原文作者:Juan Carlos Jiménez

翻译者:光棍节

原文地址:http://jcjc-dev.com/2016/06/08/reversing-huawei-4-dumping-flash/

在前三节中,我们可以得到部分的存储数据,嗅探感兴趣的数据块以及观察每个进程使用的资源信息等,但是我们却无法获取所有的存储数据,如果PCB板上没有了串口的话,或者wifi密码使用的不是默认的口令呢?上述的研究意义就不大了。

本节中,我们将尝试从Flash芯片中提取出数据,解压后就能得到可用的数据,这种提取不依靠昂贵的设备,在之前的研究基础上,结合Flash芯片的datasheet实现提取。

一、提取存储内容

在第三节中,我们已经可以根据datasheet知道flash芯片的引脚信息。如图一所示。  图一 Flash芯片部分引脚意义

我们也有Flash芯片的操作指令集,这样我们就可以自己开发程序实现与Flash之间的SPI通信。

在上节中,我们已经测试了在启动的过程中,CPU芯片Ralink会与Flash芯片进行通信,这个会干扰我们尝试读取芯片的内容,所以我们需要断开他们之间的通信,最好是基于路由器的电路实现。

二、难道我们要拆掉Flash芯片上的焊锡

最简单的办法是直接断开Flash芯片的引脚上的焊锡,这样就会与电路完全断开,我们就可以消除掉所有的干扰进而完全的控制芯片,但是,这样需要额外的设备,还需要有经验和时间,甚至可能造成芯片的损坏。

第二种方法就是能不能让CPU芯片及其周边所有的设备都处于无效或待机状态。微处理器通常会有一个reset引脚,当接上低电位时就处于关闭状态,这个引脚一般用于强制重启设备。但是从电路板上引出CPU这个引脚的麻烦比较大。

如果仅对一个芯片供电而不对其他的芯片供电呢?我们能不能只对Flash芯片供电而不是整个电路板供电?如果只是单独用3v的电源直接给Flash芯片供电,而不用PCB上的电源电路。这样有可能会破坏Flash芯片,反正这个路由器便宜而且广泛使用,当然这样也有可能会间接的给CPU供电了。如图二所示。  图二 直接给Flash芯片供电

在我们供电之后,我们就观察UART串口打印的数据,虽然可以看到PCB板上有led灯亮了,但是UART却没有数据打印,也就是说Ralink没有运行。尽管Ralink是关闭的,但是由于电路的影响,还是有可能会对我们读取Flash中的内容造成影响。如果有影响的话,那只能把Flash焊出来单独研究。

Led灯和一些静态模块不会和Flash芯片有数据交互的,所以对我们的分析没有影响。接下来,我们就用一个bench电源,能够支持足够多的电量消耗,当然,也可以用Usb供电等解决。

三、连接Flash芯片

现在我们可以不用将Flash或者Ralink焊断,我们可以直接连接到Flash,从而实现按块读取存储单元的数据。所有的微处理器都可以实现数据的读取,一个专用的SPI转USB将会极大的提高效率。我们采用了一个基于FT232T的电路板,支持SPI以及其他低层次协议。如图三所示。 

图三 Flash芯片数据读取连接示意图

四、提取数据

我们需要一个软件能够读取USB-SPI连接器上的数据,并将存储器中的内容保存为二进制文件,开源的Flashroom能够帮助我们解决这个问题。 在测试的过程中发现,无论是OSX和Ubuntu虚拟机上都存在问题,但是在树莓派上能够工作。如图四所示。

图四 Flash芯片内容读取

数据已经读取了,接下来就是分析存储器中的数据。

五、分解二进制数据

上图中的file能够帮助我们大概的看一下二进制文件的格式,我们可以利用binwalk来彻底的解压二进制数据。如图五所示。  图五 binwalk解压二进制数据

之前我们已经得到了这些数据相关的信息,如整个的内存映射表,结合这些,整个二进制的结构就会更加清晰。如图六所示。

图六 Flash存储映射表

根据上述的地址,整个二进制文件被分成4个段,使用dd命令完成,如下所示:

1. $ dd if=spidump.bin of=bootloader.bin bs=1 count=$((0x020000))
2.     131072+0 records in
3.     131072+0 records out
4.     131072 bytes transferred in 0.215768 secs (607467 bytes/sec)
5. $ dd if=spidump.bin of=mainkernel.bin bs=1 count=$((0x13D000-0x020000)) skip=$((0x020000))
6.     1167360+0 records in
7.     1167360+0 records out
8.     1167360 bytes transferred in 1.900925 secs (614101 bytes/sec)
9. $ dd if=spidump.bin of=mainrootfs.bin bs=1 count=$((0x660000-0x13D000)) skip=$((0x13D000))
10.     5386240+0 records in
11.     5386240+0 records out
12.     5386240 bytes transferred in 9.163635 secs (587784 bytes/sec)
13. $ dd if=spidump.bin of=protect.bin bs=1 count=$((0x800000-0x660000)) skip=$((0x660000))
14.     1703936+0 records in
15.     1703936+0 records out
16.     1703936 bytes transferred in 2.743594 secs (621060 bytes/sec)

这样我们创造了4个不同的二进制文件:

1、bootloader.bin:uboot,这个文件没有被压缩,因为它是最先运行的,CPU并不知道压缩算法。 2、mainkernel.bin:Linux内核,使用的是LZMA压缩,这是最基本的固件。 3、mainrootfs.bin:文件系统,使用的是LZMA压缩算法的squashfs格式,里面包含了所有的二进制文件和配置文件等。 4、protect.bin:保护区域,第三节中已经遇到的。

六、提取数据

接下来详细的分析4个段的数据。 Bootloader,binwalk分析如图七所示。

图七 binwalk分析bootloader.bin

其中有UImage头,uboot根据这个头信息来识别存储区域。有点像Linux下的file命令,解释第一个头的意思。 由于bootloader前面已经有分析,此处就跳过。 Kernel,binwalk分析如图八所示。

图八 binwalk分析mainkernel.bin

在分析之前,我们首先需要知道采用了什么样的压缩算法。此处使用了嵌入式设备中普遍使用的lzma压缩,这样就不会有明文的string保存其中了,用strings命令后发现没有有意义的字符串。 有很多工具能够解压缩lzma算法,如7z或者xz等。但是对mainkernel.bin都无效。

  1. $ xz --decompress mainkernel.bin
  2. xz: mainkernel.bin: File format not recognized

这可能是UImage头部信息占有了最开始的64个字节,在分析中,我们跳过前面64个字节,然后看到以0x40开头的就是lzma压缩的开始,如图九所示。  图九 跳过mainkernel.bin的前64个字节

再次使用xz命令解压:

  1. $ xz --decompress mainkernel_noheader.lzma
  2. xz: mainkernel_noheader.lzma: Compressed data is corrupt

由此可见,xz已经能识别是lzma压缩,但是并不是完全的正确格式。由于我们是尝试解压所有的mainkernel区域,但是并不是整个的数据区域都是有效的,查看二进制发现最后的0xff就是无效的,如图十所示,去掉最后部分,实现了xz的解压。 

图十 分析mainkernel的格式实现xz解压

Xz解压成功之后,我们可以用strings命令查看其中包含的有用的字符串了,如图十一所示。

图十一     strings查看解压后的mainkernel.bin中的字符串

上述的字符串都我们分析wifi密码生成算法没有什么帮助,如Wi-Fi Easy and Secure Key Derivation 仅仅是wifi设备中的一个硬编码字符串。

Filesystem,binwalk分析如图十二所示。  图十二 binwalk分析mainrootfs.bin

Mainrootfs段没有一个UImage头,由上图可见,采用的是squashfs文件系统,这个在嵌入式设备中经常使用,有很多的版本,让我们看看mainrootfs.bin使用的是什么版本标志。如图十三所示。  图十三 mainrootfs中的squashfs标志

已有脚本文件能够实现自动化的分析squashfs。此处使用的是Firmware Modification kit中的 unsquashfs_all.sh实现解压。如图十四所示。

图十四 unsquashfs_all.sh解压mainrootfs.bin

这样我们得到了文件系统中的所有二进制文件、配置文件以及快捷方式等。如图十五。  图十五 文件系统目录结构

根据第一节中的字符串,我们就可以查找感兴趣的文件了,如图十六所示。  图十六 感兴趣的文件

这样文件在挖掘路由器漏洞中将会发挥重要作用。 Protected,binwalk分析如图十七所示。  图十七 binwalk分析protect.bin

第三节中已经分析,这块存储区域没有压缩,包含了启动过程中所必需含有的字符串,用strings命令查看得到如图十八所示。  图十八 strings查看protect.bin文件

这些内容与curcfg.xml很像,第三节已经分析。

七、后记

至此硬件逆向已经完成,我们得到了存储器中所有的数据,接下来就是进一步的深挖已有的数据。当然,如果你无法从硬件中得到这些数据,你可以去官方网站上下载固件,官方提供的可能不是所有的数据,但是应该能够满足研究的要求。


Paper 本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/165/