修改GPT的OTA升级方案简介

发布于:2023-05-01 ⋅ 阅读:(342) ⋅ 点赞:(0)

         2023/1/11 补充:

         这个blog提到的三种刷机,还有一种往设备块直接push的方法。push时需要root,有写块设备权限,需注意块的格式,如果是当前用到镜像要注意影响。


        前面几个blog贴了很多网址,虽然也有自己总结的东西,并以刷机角度去总结分析,但是没有新东西终究意义不大,一想到这就感觉该系列博客低了逼格。的确做了不同的工作,而这略为不同的工作,虽然没有专利限制,但也算方案。为增加博客份量,这里就随意介绍下,没有源码,没有截图,只有思想,别人碰到后也自然想到,无技术难点。

         本博客以GPT(分区表)改变情况做升级方案分析,以升级方式划分各节。

         先来看看分区表文件gpt_main0.bin

         没有源码也能看出dtbo_a分区起始地址0x000E1000,结束地址0x000E4FFF。一般GPT的最后分区是userdata,并且分区大小为-1,这样驱动会识别emmc大小并重写GPT,让userdata使用所有剩余空间。同时GPT里面有sectool签名、时间戳信息(如果是AB系统的GPT,还有当前活动分区、正常启动次数等信息)。注意GPT有校验不可直接修改编辑。

目录

1、QFIL升级

2、fastboot 升级

3、OTA升级

3.1、nonAB的OTA升级情况

3.2、AB的OTA升级情况


1、QFIL升级

         提供全部镜像,直接全部擦写,没啥好说。

下面是xml文件label="PrimaryGPT"内容,详细解释可见升级方式QFIL部分

<program SECTOR_SIZE_IN_BYTES="512" file_sector_offset="0" filename="gpt_main0.bin" label="PrimaryGPT" num_partition_sectors="34" physical_partition_number="0" size_in_KB="17.0" sparse="false" start_byte_hex="0x0" start_sector="0" />

 NV(MP的数据/无线调试参数)备份:

         方法1,有tool->QCN backup按键。

         方法2,有partition Manager选择modemst1modemst2fsg分区read

         方法3configuration->FireHose configuration->Auto backup Restore QCN (读取后重写入)/Auto preserve(不动这几个分区)

2、fastboot 升级

         fastboot flash partition gpt_both0.bin刷完GPT后,分区信息即时替换,需要立即刷入其它所有镜像,若不刷重启后由于起始位置的改动,无法获取aboot、boot甚至sbl1的信息,设备无法开机,恢复只能靠硬件进入紧急下载。

         假如NV所使用分区起始位置不动,刷写过程中不擦除不重写NV分区,即可保留NV数据。(BC对比如果有略微差异,是由于MP版本有改动)

         假如NV所使用分区起始位置改动,NV无法通过fastboot 读取备份,因为fastboot不支持读分区操作。(个人设想方案,换公司后,没碰到这种需求,目前未实现。fastboot getvar 获取原NV起始地址与大小,aboot实现数据搬移并提供fastboot oem moveNV命令接口,刷写GPT前先获取新GPT的NV起始地址与大小,然后fastboot oem moveNV 原NV地址 新NV地址 大小)

         如上图的分区表改动情况,起始位置、结束位置没动的NV分区,其数据是可以保留的(android N之后版本的高通LK,重写GPT时会擦除整个emmc,关掉这个擦除操作即可)。手绘省时,会意即可。         

        再就是,对于RPMB未绑定设备(注),userdata分区数据可以copy到其它设备继续使用。若要想用户数据尽完整可用,copy前后设备的版本最好一致,提供的userdata使用空间必须大于copy的。为防止用户数据被copy窃取,RPMB未绑定设备应该要求用户设置开机密码。dump全盘加密的userdata无法直接挂载,全盘加密/文件级加密相关可以访问linux的全盘加密与文件系统加密在android中的应用_cola94yi的博客-CSDN博客_mtk_encryption_default_off

RPMB绑定(Android 8.0 (Keymaster 3) 中引入了 ID 认证,每个绑定设备的加密信息会不一致,无法通过dump userdata方式获取用户信息。https://source.android.com/security/keystore/attestation#id-attestation)

3、OTA升级

         nonAB与AB系统升级差异大,需要分开说。

3.1、nonAB的OTA升级情况

         nonAB升级流程是recovery调用OTA包中的update-binary二进制执行程序,解析updater-script脚本,按该脚本流程升级。官网https://source.android.com/devices/tech/ota/nonab。详细了解nonAB的OTA升级流程的看下面这系列的blog比较好

Android OTA升级包制作脚本详解(一,参数解析)_高桐@BILL的博客-CSDN博客

         google源生代码的updater(即update-binary二进制执行程序,源码位置bootable\recovery\updater)是不带修改GPT的,方案商有修改GPT方案,提供GPT修改库。

NV数据保存分下面几个情况:

         假如GPT只是签名和时间戳信息变动,可以对比关键分区的起始位置、结束位置来确定是否替换GPT。

         假如GPT改动较少,其中NV所使用分区起始位置和结束位置不动,升级过程中不擦除,NV数据也是可以保留。

         假如GPT改动很大,需要备份NV,可以在updater/install.cpp源码中添加函数,复制NV分区数据至tmp目录下,替换GPT后再写回,其它分区要么全刷,要么擦除,要么格式化。

  NOTE1:       OTA升级按需求还可以添加sparse库,并在updater/install.cpp源码中编写函数,就可以支持sparse格式镜像的刷写,这种方法可加快文件系统格式镜像的刷写。(sparse格式实际是文件系统一种压缩格式,无法用diff工具差分对比,在制作差分包时该类文件不要做diff。可修改差分包制作源码,指定后缀类型直接copy,不做差分)

   NOTE2:      在android 7.1往android 4.4降级时碰到个问题,由于库的不兼容(准确来讲,新版本往旧版本升级时,旧版本是无法知道新版本改动的),导致getprop无法读取设备属性。这时流程上可以使用源码提供的file_getprop接口,通过挂载system读build.prop文件里面的属性。

         可以看到nonAB的这种OTA升级模式,在升级过程中SELinux给予外部执行程序权限很大(OTA包内的updater-binary),包括可读写方式挂载system/vendor、可读写分区、可修改GPT等。同时update-binary执行程序的库可自己加,接口可自己写,流程updater-script可自己定,具有极高的功能自由和流程自由。之前很多破解,root都是通过recovery的OTA升级来完成,并且这种修改过的系统无法再差分升级,这里提醒ODM/OEM小公司证书签名要保护好(不然售后很多问题,让研发兄弟很难搞啊)。

3.2、AB的OTA升级情况

         AB系统升级是调用内部执行程序system/bin/update_engine,解压payload.bin文件,刷写到另外一个slot。和上面nonAB方式明显不同,无法使用自己的升级程序,无法按照自己定义流程来升级。就这两点对于AB系统来说,意味着更安全。同时利用两个slot,可以后台升级,可以断点续传,可以保证稳定性等等。

         update_engine的确有足够权限去刷写非AB的分区,修改GPT。但你无法修改已经在系统里面的update_engine执行程序,无法控制流程(https://source.android.com/devices/tech/ota/ab/ab_implement#post-install

官网介绍有个安装后执行程序,可以执行有限的定制步骤),同时你在改GPT后,你的程序读写所有起始位置变了的分区都会有问题。

当然你可以微改,能改多少可以慢慢验证。但这里没有研究。

         AB系统的GPT修改稍微通用的方式是什么呢?

         显然你需要进入和recovery一样的干净的升级环境;需要按自己流程刷写设备;当然跑自己的升级程序最好不过。

达叔:“没错!”,
最简单方式是使用nonAB的OTA升级包与升级流程。

         那么流程基本就是替换recovery,替换GPT,刷写新系统。总共是两步,需要两个OTA包一个GPT。

第1步、AB系统支持nonAB的升级:
使用AB的OTA包单独替换boot分区(AB系统的recovery文件系统在boot中),而这个新boot内的recovery的根文件系统是nonAB模式的文件系统;
这一步AB的OTA包中,如果使用同平台的nonAB的recovery镜像会有问题,因为在AB系统类型的分区表中无cache/recovery等分区,需要修改recovery模式下的挂载表和日志位置。
第2步、自己做个nonAB的OTA包,重写GPT并按自己流程升级。
这一步关键是执行程序update-binary需要3.1、nonAB的OTA升级情况中提到的sparse支持,GPT修改,NV备份等能力;updater-script脚本,需要自己编写来控制流程。

你至少要注意以下几点:
1、熟悉nonAB的升级流程与OTA包内的升级脚本,熟悉每个分区作用(比如哪些需要先刷写,哪些需要备份);
2、这种OTA包只能自己制作并打包签名,可以用fastboot线刷包来制作(system/vendor需要用sparse格式,如果不用,解压出来将会很大,刷机非常耗时,不确定因素也将更多),updater-script需要自己编写,控制好流程(1、备份NV,2、刷GPT,3、恢复NV,4、刷MP/AP);
3、nonAB的改分区的升级,必须使用外部存储;而且这种升级方式不能中断(尤其是注意点2的2-3-4流程部分),存在一定风险。

这个新系统自由度很高,AB or nonAB自选,GPT自定,版本自定等等。
但是这操作显然太麻烦,你可以有后面几个操作。如果aboot和misc作用比较熟,第一步AB的OTA包替换recovery同时替换新的aboot和misc分区,实现重启立即进入recovery升级第二个nonAB格式的OTA包。如果对nonAB的OTA升级流程及脚本比较熟,GPT放入后刷的nonAB的OTA包中。加上AB的OTA包与nonAB的OTA包差异很大,用的同一个证书签名的话,完全可以放一个包中。那整个流程,可以使用一个包一个操作完成。

根据上面的思路,使厂商release的AB版本支持改分区表升级有两种方式,第一种方法我已经实现,使用多次没出问题。

         方法一,使AB系统的recovery模式不但支持nonAB的OTA方式升级(使用执行文件update-binary与脚本updater-script升级),还支持AB的OTA升级方式(使用自己添加的update_engine_sideload升级)。两种系统的OTA包差异巨大(可以判别关键文件是否存在/判别元数据),识别为哪种,就用哪种方式升级。

         方法二,再简单点,不再判断,使AB系统的recovery模式只支持nonAB的OTA升级,system模式依然使用update_engine升级支持AB的OTA升级。

         假如AB系统的recovery模式支持nonAB方式的OTA升级,它在实现改分区OTA升级的同时也带来了nonAB系统OTA升级的优缺点,比如给system/vendor打补丁、可以利用签名轻易破解、目标版本高度自由能够轻松跨Android的大版本升级。        OTA改GPT还是需要点积累和经验的,不管如何操作,OTA升级改分区表,其风险就无法避免(设备升级中断大概率挂掉,合入发布前多调试,别说我挖坑!),所以建议熟手操作。。。这需求起因不谈,最后结果还是不错。
 

         这篇只有文字,下篇blog比较有用,新玩意,也算是趋势,而且有图了。


后续会思考如何改分区表,并保留userdata。
1、全盘加密的userdata由于recovery无法解密,在userdata空间缩小情况,无思路完全保留userdata;(升级前先缩到指定大小?)
2、文件级加密的userdata,recovery能访问其文件系统,可以改文件系统大小。linux调整文件系统大小 - zgtang - 博客园,未测试验证。

emmc地址动态映射?


本文含有隐藏内容,请 开通VIP 后查看