这一节的内容实际上与程序编写毫无关系,主要是记录如何修改 Android 设备的引导分区,对其映像进行手术式操作,把编译出的模块的 SHA1 值添加到 Moto X Pro 的白名单里并使之生效。
简要概括起来,和一台 Android 移动设备的引导分区/内核打交道,想要分析它或者修改它,相关的工作有这么几个。
1、如果有现成的 ROM,需要把 boot 分区的映像从中提取出来(这个工作一般较为简单,在这儿不多说);
2、如果没有现成的 ROM,可以通过 dd 命令将 boot 分区(查看 /dev/block/platform/msm_sdcc.1/by-name/ 下的信息)的内容转储出来,前提是设备已经被 root;
3、无论以上哪种方法,假定获得的映像文件名字为 boot.img 的话,进一步可以把它拆解为压缩后的内核(通常命名为 zImage)以及引导时的内存盘映像(通常命名为 initrd.img)两个部分;
4、zImage 就是通常说到的内核了,不过它也是由几个部分粘合而成的。最开头是解压后面的被压缩的真正的内核的代码;接着就是压缩过的内核代码(也称作 piggy.gz),后面通常还有一些其它的零碎;如果有逆向分析的需要,那就需要进一步拆解它;
5、initrd.img 是系统引导时早期的根文件系统;如果有修改此文件系统上的文件的需求,要能对它进行拆解和重制;
6、把修改后的引导分区映像刷回到设备中去。
自动化操作 boot.img 的工具(解包或者重打包),既可以使用 apt 就能直接安装的 abootimg,也可以使用需要搜索一下才能找到的 AIK(Android Image Kitchen),后者会顺便把 initrd.img 也解开,如果有对根文件系统进行修改的需求,就会便捷一些,而且重打包也很方便。
如果要对 zImage 进行更进一步的剖析,则可以寻求 repack-zImage.sh 脚本的帮助,它能够把解压代码、piggy.gz 等分离开来(如果要从 zImage 中提取内核所包含的符号版本,则可以寻求 extract-symvers.py 的帮助)。
有了这些工具,使得修改 Moto X Pro 的白名单成了一项简单的工作。先把原始的 boot 分区 dd 到 /data/local/tmp/boot.img,用 adb pull 到 Linux,使用 AIK 解开,修改 ramdisk 下的 module_hashes 文件,把我们的 .ko 内核模块的 SHA1 值添加到其中,注意到原有的内容是经过排序的,所以加入新内容的时候也保持了有序的状态。再用 AIK 重打包,adb push 到 /data/local/tmp 后用 dd 刷入引导分区。刷分区的方法,视情况而定,也许是 fastboot 就能搞定,也许需要厂商的工具(如三星的 Odin)支持,也许 dd 就足矣。
白名单生效后,依次来了一个好消息、两个坏消息。第一个好消息是模块貌似真的被加载了,insmod 命令没有打印出任何错误信息,一个坏消息是手机立刻重启,数次尝试均是如此。最后一个坏消息,是在隔天才发现的,手机卡插入后设备不识别了,一直保持处于无 SIM 卡状态。
最后有必要补充一下手工从 zImage 中把真正的内核解压出来的方法。使用十六进制编辑工具打开 zImage,查找 gzip 流的起始标识 1F 8B 08,找到后把它们之前的数据全部删掉,文件另存为 .gz,然后用 gunzip 直接解压即可。事实上,被删除掉的就是 ROM 里自己进行解压的那部分代码,而且 .gz 的文件尾部也还有不属于 gzip 数据的内容,只不过会被 gunzip 自动抛弃掉不予处理。