[原创]中兴ZTE ZX279128S芯片固件解密

APT 2个月前 admin
61 0 0

最近家里的移动宽带到期了,闲置了一台H3-2S的光猫,原本我也有一台MIPS的友华光猫,固件修改后我自己也很满意了。但这台闲置的光猫是ARMv7l的,测试后发现性能更好一些(是MIPS的一倍多)。于是就想着也改改,加一些自启脚本,装frpc、alist、kms、aria2c、clash、甚至还能跑一点自己写的Java程序。

通过分析一通之后,我发现这个光猫的rcS相关的自启内容里一点破绽都没有,原本的alipay的dns也注释了,要加自启脚本就必须改rootfs里的rcS。由于系统里没有dd,但有nandump,我给dump出来,使用binwalk分析了一下,果然从kernel里解出了文件系统。整个固件的文件结构大概是这样的:中兴文件结构,占480bytes,然后是uImage头64bytes,然后会执行一段程序,解压gzip。gzip解压出来之后,解压的字节中又有一段程序,然后再解压一个lzma块,这个lzma块解压出来就是rootfs.cpio了。

这个cpio是没有任何压缩的。但我用python的cpio库libarchive的时候遇到了不小的挑战,就是cpio解压后什么都不改,再压回去,对比改动发现差异很大,里边有一些数据的大小写都发生了变化,小写全都变成了大写。我想探究里边的原因,耗费了一天时间也没找出来,于是我只好人肉修改cpio的16进制内容,找到rcS部分,把alipay.sh的注释打开,然后改一小段。

剩下的就是还原回去并刷进去的工作了,这个还原工作异常艰难:

首先是gzip解压的时候不知道gzip块的长度,不知道什么时候会结束,虽然不影响解压,但肯定影响还原啊。好在gzip解压的时候,异常信息里会提示无法解码的字节,那直接搜索这个字节就能找到结束的附近了。然后观察右侧的块特征,终于找到了结束位,顺带还发现了dtb的开始位置和整个分区的结束位置、还有crc32的偏移量。

然后是lzma的结束位,这个就比gzip难多了,因为这个lzma解压的时候没有报任何异常,直接就解压出来了,再尝试压回去会发现大小完全对不上,大了1M多不止。尝试了好几个库和xz\tar等格式,发现也对不上,应该就是lzma的压缩格式。后来我开始怀疑是不是lzma的结束位置不对,可没有任何异常啊,应该不会不对吧。

我带着这个怀疑,使用linux中的lzma去检查这个文件块,发现lzma竟然无法识别,而我压缩回去的lzma则能识别,而且完全没问题。我好奇它究竟用的什么lzma算法啊,难道老版本的不支持?于是我开始翻python的lzma库源代码,发现它果然捕获了异常,而且直接把异常吃掉了。真狗!我把那段代码拷贝出来。

1
2
3
4
5
6
7
8
9
10
11
12
data = f.read(buff)
        results = []
        while True:
            decomp = lzma.LZMADecompressor(lzma.FORMAT_AUTO)
            try:
                res = decomp.decompress(data)
            except lzma.LZMAError as e:
                if results:
                    print("LZMAError: %s" % e)
                    break  # Leftover data is not a valid LZMA/XZ stream; ignore it.
                else:
                    raise  # Error on the first iteration; bail out.

lzma则是非常难,因为lzma的那次压缩是在gzip解压之后,又执行了一段,那偏移量完全都不知道怎么对上,载入到IDA里也是一堆未识别的地址。好在它的库函数会有俩个不同的异常,一个是流未结束,一个是字节无法解析。流未结束就是截取少了,字节无法解析就是截取多了,然后写了一个二分查找的方法,找到了lzma解压的位置,位置结束后俩个字节处就是lzma的长度数值。

然后我测试了一下,将截取的lzma解压出rootfs.cpio后再原封不动的压缩回去,大小竟然比原来的小了几十字节。这可不行,我又尝试了一下用linux自带的lzma压缩:

1
cat ./rootfs.cpio |lzma -9 > lzma.lzma

果然还原了,和原文件md5值一字不差,看来linux的lzma算法还是和python的lzma有些小差异。

至此,整个逆向过程告一段落。IDA可以直接载入uImage的文件去查看gzip的解压逻辑,来验证gzip的结束偏移的地址是否正确。

经过一番验证,也找到了双固件切换的的方法,也完成了文件系统提取也压缩回去的程序工具,但改完的固件始终无法启动,查看gzip解压的出来的数据块,发现了大量证书内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
65728         0x100C0         AES Inverse S-Box
70336         0x112C0         SHA256 hash constants, little endian
98393         0x18059         Certificate in DER format (x509 v3), header length: 4, sequence length: 5384
98405         0x18065         Certificate in DER format (x509 v3), header length: 4, sequence length: 5392
98409         0x18069         Certificate in DER format (x509 v3), header length: 4, sequence length: 5396
745165        0xB5ECD         Certificate in DER format (x509 v3), header length: 4, sequence length: 1284
3911129       0x3BADD9        Certificate in DER format (x509 v3), header length: 4, sequence length: 4736
4316777       0x41DE69        Certificate in DER format (x509 v3), header length: 4, sequence length: 1456
5909712       0x5A2CD0        gzip compressed data, maximum compression, from Unix, last modified: 1970-01-01 00:00:00 (null date)
6121672       0x5D68C8        DES SP2, little endian
6122440       0x5D6BC8        DES SP1, little endian
6142464       0x5DBA00        CRC32 polynomial table, little endian

感觉要裹足不前了……,目前的水平对arm反汇编的能力严重不足。
所以把成果文件贡献出来,看有没有大神有兴趣挑战,如果成功,我将分享我开发的中兴固件拆包打包工具(现在不分享是因为打包的固件无法启动,有变砖风险)。

https://cloud.189.cn/web/share?code=aYVVNzMvA7ze(访问码:6hyx)

文件说明:
该文件为吉比特,中兴芯片光猫固件:

  1. uImage.bin为从uboot启动的uImage镜像文件,从该文件中可解出 zImage.bin文件;
  2. zImage.bin文件,可解出kernel.gzip文件和dtb.bin文件;
  3. kernel.gzip文件可解出kernel.bin文件,该文件中可看到大量证书内容和加密相关内容;
  4. kernel.bin文件可解出lzma.lzma文件,该文件为rootfs.cpio压缩包,即linux文件系统;
  5. 由于uboot中禁用了earlyprintk,所以无法通过串口得到任何有用的信息,但是可以通过uboot的tftp功能,将文件传输到内存中,然后通过uboot的bootm命令启动内核,从而实现调试。
  6. uImage.bin和kernel.bin文件可以使用IDA pro载入,能看到程序的大致结构。
  7. 由于启动不了也可能是uboot里有相关验证,所以补充一个mtd1_u-boot.bin,这是该光猫的u-boot分区备份。

2023年5月8日 我已自己挑战成功,实现了通用工具:

  1. 可编辑zImage中嵌入了编译型initramfs.cpio的kernel
  2. 可对cpio中的文件实现增删改,而无需解压和再打包
  3. 可生成中兴uboot启动的固件,无需刷第三方uboot,从而避免变砖风险

原文始发于看雪社区(XYUU):[原创]中兴ZTE ZX279128S芯片固件解密

版权声明:admin 发表于 2024年1月4日 下午4:29。
转载请注明:[原创]中兴ZTE ZX279128S芯片固件解密 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...