逆向工程师如果对设备代码和固件系统进行检测时,发现了许多经过加密处理的固件文件,该怎么办?在本文中我将通过一个真实的故事来教大家如何利用一些基础的计算机知识以及简单的逻辑来应对这一问题。
因为这篇文章主要是要教会大家如何去应对这样的情况,并且给大家提供一个行之有效的解决方案,所以这里我们并不会指明测试所用的调制解调器来自哪家厂商,也不会列出具体文件的真实文件名。
另外这种方法对最新款的调制解调器可能已经不适用了,但在旧版本的调制解调器或者其他生产商所生产的Modem中应该仍可以进行测试。
1. 了解文件结构
首先,我们需要了解该调制解调器固件的文件结构。这款调制解调器中有三个更新版本:
v2.8_image.bin v3.7_image.bin v3.7.4_image.bin
其所有的文件均采用了TLV(Tag-Length-Value) 格式。比如文件v3.7.4_image.bin的结构:
数据值均采用了小端格式 (一种存放二元化资料的格式(所有数字的低位组放在最前面)),其标签(Tag)的长度为16位,数据长度(Length)值为32位。
标签0×7240位于第一个嵌套级中,其数据占满了整个文件。标签0×0003(0x0A字节)位于第二嵌套级中(标签0×7240的数据在其中);接下来的是标签0×0000(0x4BDE0E字节),标签0×0001,以及0×0002(它们并不在上面给出的截图中)。第三层嵌套(含有0×0003的数据)封装了标签0×0002的数据并且存储在长度为四个字节版本号的030704FF的文件中。
其他标签的描述均位于第二嵌套级的其他标签中(0×0000,0×0001,以及0×0002),而他们被单独“打包”存放在一个固定的文件中。即每一个文件都会有一个单独的名称(标签0×0001),标志(标签0×0002),大小(标签0×0003),长度为16字节的值(标签0×0004),以及文件数据(标签0×0005)。
下面是对文件中的所有标签内容进行分析之后所显示出的结果:
如此以来我们便可以对固件的所有组件(CPUImage,AutoInstall,以及WebUI)中的加密数据进行检索获取了。我们发现这三个固件版本中的AutoInstall文件其实是一样的,3.7和v3.7.4版本中的WebUI文件内容也是相同的,但CPUImage文件并不一样。
2、通过算法来进行猜测
标签0×0004位于第三嵌套级中,该标签包含有一个长度为16字节的数据集,且被设置了非常高的熵。它很有可能是一个哈希值,目前最受欢迎的128位哈希算法就是MD5了。
在我们获取到的文件中,很多字节的偏移量数值都是相同的。下图显示的是两个文件的起始部分(不同之处已经进行了高亮显示):
然而如果你试图想要在单个文件中找到相同的数据序列无异于是痴人说梦。
这样看似乎是使用了一个半随机的伽马常数对这些信息进行了处理。RC4算法是目前最为流行的一种加密算法,它刚好可以实现此功能。
3、使用常量密钥对密码流进行破解
如果几条信息使用了相同的密钥来进行加密(例如伽马),对它们进行异或计算就有可能得到它们的部分内容:0字节将会返回明文。
而对AutoInstall文件和WebUI文件分析后我们获得了一个非常有趣的结果:
我们可以看到在该文件中有两个片段:一个 FAT12软盘的镜像和一个CD-ROM的镜像。
4、获取伽马值的数据
在安装驱动或者软件的时候,调制解调器通常倾向于创建一个虚拟光驱来连接,这里就使用了这一概念。
然而当调制解调器与新型的操作系统(例如Windows 7/8,Linux,或者Mac OS X)连接时,虚拟光驱要么就不显示,要么就是显示一两秒钟之后然后消失。因此我们专门找了一台2002年生产的Windows XP笔记本电脑来进行该测试。此时虚拟光驱显示了大约五秒钟,这已经足够我们读取出所有逻辑卷中的数据并获取到镜像。
该文件大小为606,208=0×94000字节,这与AutoInstall文件的大小完全一致。镜像的MD5值为897279F34B7629801D839A3E18DA0345,与标签0×0004的值相同。
现在,我们只需要用AutoInstall文件与这个镜像文件进行异或,就能得到伽马值的数据了。这个伽马值可以用于解密CPUImage和WebUI文件中的加密数据 (大小分别为4,971,976个字节和2,093,056个字节)。
5. 重组一个软盘镜像
如果你能破解这些加密数据,并且使用零字节填充WebUI文件的剩余部分,然后将所有内容编译成一个FAT镜像文件,那么你将能够看到文件系统的整体结构和一些文件的内容。
如果你的调制解调器连接到http:///dir,你将看到相同的文件系统,并能够下载任意文件。
而要恢复WebUI文件,你需要通过与boot,FAT表以及目录描述数据一致的Web接口来下载文件。唯一的困难在于根目录下的 ru文件夹,其内容描述超出了606208字节,因此其内容需要单独恢复。
根据web接口的数据,这个 ru目录必须包含以下文件:
幸运的是,根目录下的eng文件夹具有相同的文件名和创建日期,为了得到正确的ru文件夹,应进行如下改变:
The number of the starting cluster of the current directory
The size of each file
The numbers of the starting clusters of all files
根目录下含有大量的ru目录的集群(0×213)
使用web接口去识别文件大小(分别是3981 = 0xF8D, 5327 = 0x14CF, 以及3328 = 0xD00 )
最开始的集群是很容易猜到的。根据boot数据来看,每一个集群占据了四个分区或者2048字节。ru目录仅要求一个集群,Manualupdate.html 和 Network.html-两个集群Index.html-三个集群。由于集群会被按照顺序写在一个空的磁盘中,文件将会分别从 0×214, 0×216以及 0×219开始。ru目录恢复的数据如下所示:
包含刻录磁盘镜像的ru folder 和所有文件内容,并且还有一个明文的WebUI 文件,从固件头文件我们得到其MD5 是48D1C3194E45472D28ABFBEB6BBF1CC6 。
至此,我们已经破解了AutoInstall文件和WebUI文件,并且还得到了 2,093,056字节的伽马值数据。
6. 校验CPUImage文件
自然而然地,当我们破解了CPUImage文件的前2MB数据之后,我们就可以进行反汇编了。在对处理器的指令系统(ARM 小端)和下载基址(第一个0 x34c字节必须跳过)以及找到更新解密位置进行了解之后,我们获得了下列代码:
如上所示,其中加密密钥位于0x2ADC60,长度为0×15 个字节并被RC4 算法加载。但是0x2ADC60=2,808,928,所以这个密钥已经超出了我们所知的伽马值了。
在更早的固件版本(v3.7和v2.8)中,这个密钥也超出了其解密域(分别为0x2AD70C和0x2A852C)。
7、再一次进行异或运算
如果对3.7版本和3.7.4版本的CPUImage文件进行异或计算,我们将会得到位于0x34C + 0x2AD70C = 0x2ADA58的字符串“SungKook ”James” Shin”。这是一个RC4密钥,被用于对所有更新文件进行加密。
现在,我们只需要确认这个RC4密钥能与我们之前所获取的伽马值相匹配,并且CPUImage的MD5值能与固件系统的文件header相匹配。
到这里,我们可以对固件本身进行测试了,而这将是一个完全不同的故事。
*参考来源:ptsecurity