最近工作需要对boot.img,system.img进行破解。顺便将心得分享一下。
我的工作环境是在linux下的。所以工具都是针对linux的。
boot.img破解相关工具:
1、split_boot perl脚本
2、boot_info perl脚本
3、repack_ramdisk bash脚本
4、unpack_ramdisk bash脚本
5、mkbootimg x86二进制程序
工作原理先不解释了,有兴趣的朋友可以就此帖聊聊。
首先通过split_boot来分解boot.img或recovery.img。
./split_boot boot.img
分解后有个base address 0x00800000(一下数据都是举例并非真实数据)和command line信息要记录下来。
不记也可以用boot_info查看一下就可以了。其实就只有command line有用。
解包目录:
boot/ramdisk
boot.img-kernel
boot.img-ramdisk.cpio.gz
修改主要是boot/ramdisk目录下的东西,修改完后用repack_ramdisk工具打包生成新的boot.img-ramdisk.cpio.gz覆盖旧的。
最后用mkbootimg --cmdline '上面信息获取的command line' --kernel boot/boot.img-kernel --ramdisk boot/boot.img-ramdisk.cpio.gz -o 输出目录 --base 上面信息获取的base address(如:0x00800000)
最关键的部分来了。很多朋友都说重新打包后的boot.img无法用odin刷进去。
寻找壳数据并补充:
关键部分在于新的boot.img缺少了一些标记数据,其实分析过源码bootimg.h的人也知道,既然能解开,重新打包后应该是没错的啊。
确实是这样的,任何数据,能正常解包,再重新打包都不会有错。我们可以想想,为什么要odin工具刷入?因为那是三星自己开发的刷机工具。所以它肯定有区别于android默认的fastboot工具。
不同手机厂家也一样的道理,对于这种二进制数据包,如果厂家是从bootimg.h数据结构上做手脚,那么肯定就不是bootimg.h的数据结构了,那么它就只有在boot.img生成后,再进行二次加工生成的
加壳数据包。我是这样理解的,只要是特定结构的数据包,用ue打开后都会看到一些空白段(也就是0000组成的无数据区),这些区域可以填充特定数据来改变原来的数据包结构(可以理解为签名),
三星的boot.img为发现它的数据包末尾多处一段数据,可以用ue查找ASCII一下"QCDT" 就可以发现这部分多处来的壳数据。首先要修复这个地方,把壳数据二进制复制并粘贴到新的boot.img末尾。
修改头数据:
看过bootimg.h以及mkbootimg源码就可以知道一些不能改动的值,下面我们看看一些关键头部数据。
struct boot_img_hdr
{
unsigned char magic[BOOT_MAGIC_SIZE];
unsigned kernel_size; /* size in bytes */
unsigned kernel_addr; /* physical load addr */
unsigned ramdisk_size; /* size in bytes */
unsigned ramdisk_addr; /* physical load addr */
unsigned second_size; /* size in bytes */
unsigned second_addr; /* physical load addr */
unsigned tags_addr; /* physical addr for kernel tags */
unsigned page_size; /* flash page size we assume */
unsigned unused[2]; /* future expansion: should be 0 */
unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
unsigned char cmdline[BOOT_ARGS_SIZE];
unsigned id[8]; /* timestamp / checksum / sha1 / etc */
};
因为我们只修改了ramdisk所以这里应该只改变了ramdisk_size,而其他的数据,就让它完好无损把。
所以呢,我们就要用旧的boot.img的头部数据,覆盖新的boot.img数据。在这之前要先复制新boot.img的ramdisk_size部分数据出来。
用ue打开新boot.img,拷贝第二行开始前4位如:00 4b 8a 90,新建一个空白文档切换到16进制编辑模式,把刚才的复制粘贴到这里保留起来。
用ue打开旧boot.img,拷贝从0h~250h行的数据到新boot.img覆盖,最后从新文档中保留的ramdisk_size地址复制粘贴回新boot.img的第二行前4位。
这样一来boot.img就搞定了,只要一个 tar cvf boot.img.tar boot.img打包成tar文件就可以用odin刷进去了。
==========================================
修改三星的system.img比较麻烦,因为它并非bootimg.h结构,而是ext4文件结构,而且还是sparse img模式的ext4。
首先需要的工具如下:
make_ext4fs
mkuserimg.sh
simg2img
当我们拿到三星的system.img文件其实名字是这样system.img.ext4。通过file system.img.ext4我们可以发现它其实是data,也就是sparse img模式的ext4。
我们需要用simg2img来转换。
simg2img system.img.ext4 system.img
这时候再用file查看就是ext4结构数据来。
接下来需要挂载到系统来修改
sudo mount -t ext4 -o loop system.img ./system
ls 查看一下system.img镜像大小。
ls -l system.img
-rw-rw-r-- 1 xxx:xxx 2499805184 .... system.img
因为我们打包需要设定镜像文件大小,这个大小是固定的,最好别乱改。
另外,之前我们解开boot.img的ramdisk里有一个file_contexts文件,也拷贝到当前目录,打包需要用到。
修改过后通过make_ext4fs来打包为sparse img模式的ext4,关键参数是 -s
sudo make_ext4fs -s -l 2499805184 -a system -S ./file_contexts ./system.img.ext4 ./system
打包完后继续上面的壳理论,因为这时候你哪怕tar打包后还是刷不进去的。
寻找壳或者签名.....
找到签名位置在 0x220h~0x428h,所以我们从旧system.img.ext4里拷贝一下这段数据,覆盖到新的system.img.ext4,然后再tar打包就可以刷了。
目前我自己也有烦恼,卡在了,如何把system.img内的framework进行二次修改。因为当前真机是user模式且odex化,所以我以及把所有的framework,app以及里面odex化的app只要我能找到的odex都全部
用一个自己写的脚本进行了转换。
odex -> baksmali -> smali -> dex -> zip -> zipalign -> jar -> dexopt-wrapper(这步是在真机内执行的,用的是本机的dexopt,以及确定可以重新打包odex成功)。
我把所有重新odex的文件都push回system.img了。重新打包后刷进手机,三清后重启,结果手机开机动画处停留了一段时间就重启。
因为看不到logcat所以臆测可能是odex签名校验问题,根据网上资料查找到了libdvm.so的函数dvmCheckOptHeaderAndDependencies返回值的问题。
用IDA修改返回值为true后,还是如此。ida修改没问题。确定不是对libdvm.so修改导致的错误。
如果有大神路过请留下解决思路。有什么办法可以在保留user模式情况下修改掉所有的odex或者是重新odex还有什么错误的地方?
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课