固件解包的目的是,将完整的设备固件分解成文件系统、内核、引导程序等各个功能模块,以达到有针对性地分析某个脚本或二进制程序的目的。
基于嵌入式Linux开发的设备固件的二进制可执行程序、共享库、可执行脚本等文件,一般都打包成文件系统存储在固件中。常见的文件系统有SquashFS、JFFS2等。
常用的解包工具有Binwalk、firmware-mod-kit等。
3.5.1.1 Binwalk工具
Binwalk工具是一款优秀的固件解包工具,可以解析多种固件类型。它能对绝大多数没有加密的固件进行解包,从而获取固件的文件系统或对固件进行其他分析。
1.Binwalk工具的安装
如果使用apt-get命令直接安装Binwalk工具,那么可能会由于一些依赖库的问题而造成Binwalk工具的部分功能缺失。因此,建议通过GitHub将该项目源文件克隆到本地,并按照帮助文档进行安装。
2.Binwalk工具的基本用法
Binwalk工具的常见格式为“binwalk参数 文件目录/文件名”。Binwalk工具能自动对整个固件进行分析,进而提取出相应的文件系统。其常用参数如下。
-M参数:递归扫描提取文件。
-e参数:自动提取已知的文件类型。
-A参数:使用普通可执行操作码签名扫描目标文件。
-Y参数:显示目标程序的指令集架构和指令数量。
(1)使用-A参数,可以快速扫描出固件文件中字节码对应的指令集。此参数主要用于快速确定某些RTOS、裸机固件的CPU类型。-A参数的使用过程如图3-89所示。从扫描结果中可以发现,固件为ARM指令集架构。对于一些不存在文件系统的裸机固件,可以快速判断出目标指令集。
图3-89-A参数的使用过程
(2)使用-Y参数,会显示目标程序的指令集架构和指令数量。-Y参数的使用过程如图3-90所示。
图3-90-Y参数的使用过程
3.案例:Tenda ac15路由器固件分析
(1)使用binwalk-Me命令直接进行递归解包,如图3-91所示。
图3-91 进行递归解包
(2)查看文件系统根目录,并对二进制文件进行进一步分析,如图3-92所示。
图3-92 查看文件系统根目录
3.5.1.2 firmware-mod-kit工具
firmware-mod-kit工具的功能与Binwalk工具的功能类似。它们都是用于固件解包的集成工具,并支持多种文件系统解包。另外,firmware-mod-kit工具还有重打包固件的功能。
1.firmware-mod-kit工具的安装
该项目在GitHub中开源,建议将该项目源文件从GitHub克隆到本地,依照项目帮助文档使用下载文件进行编译安装。此过程涉及的代码如下。
2.firmware-mod-kit工具的基本用法
在firmware-mod-kit工具目录下使用extract-firmware.sh脚本进行解包,命令为./extract-firmware.sh<firmware image>。
3.5.1.3 binaryanalysis-ng工具
binaryanalysis-ng工具是一个支持通用操作系统的解包工具,具有非常强大的文件解包集成能力,不仅可以解析出物联网设备的固件文件,而且支持解析一些Android固件文件。binaryanalysis-ng工具支持的文件格式如图3-93所示。
图3-93 binaryanalysis-ng工具支持的文件格式
1.binaryanalysis-ng工具的安装
从Gitee上下载binaryanalysis-ng工具,并使用apt-get、pip等命令安装相关依赖文件。
该项目在Gitee中开源,建议将该项目源文件从Gitee克隆到本地,并使用apt-get命令和pip命令安装依赖文件。此过程涉及的代码如下。
2.binaryanalysis-ng工具的基本用法
假设已经访问到src目录,此时进入src目录会看到许多Python脚本,可以使用bang-scanner工具来对固件文件进行解析。
(1)访问src目录。
(2)使用bang-scanner工具对固件文件进行解析。
(3)进入tmp目录,如图3-94所示。
图3-94 tmp目录
(4)进入unpack目录,找到需要的文件系统,如图3-95所示。
图3-95 找到需要的文件系统
(5)应用bangshell,解析解包后的结果。在运行bangshell之后,查看bangshell支持的命令有哪些,如图3-96所示。使用load命令(load/root/tmp/bang-scan-52x0_zxy)加载刚刚解析完成的目录,使用summary命令分析文件类型,如图3-97所示。
图3-96 查看bangshell支持的命令
图3-97 加载目录并分析文件类型
最终结果如下。
labels命令如图3-98所示。
图3-98 labels命令
3.5.1.4 案例:小米路由器UBI格式固件解包程序
(1)直接使用Binwalk工具解包,会显示不能解包的报错信息,代码如下。
(2)编写UBI格式固件解包程序代码,如图3-99所示。
图3-99 UBI格式固件解包程序代码
(3)编译、运行,并处理UBI文件,代码如下。
(4)使用ubireader_extract_images命令解压UBI文件,代码如下。
(5)使用unsquashfs命令解压rootfs.ubifs文件,代码如下。
(6)解压之后,成功得到文件系统,代码如下。
为了防止恶意分析人员或者攻击者对物联网设备固件进行解包分析,一些厂商会对发布的设备固件进行加密。面对这种情况,用户无法直接使用Binwalk工具对设备固件进行解包,需要通过手动分析逆向程序中的加密过程来解密,从而进行设备固件解包。
1.场景一:设备固件在出厂时未加密
在此种加密场景中,解密程序与较新版本程序中的未加密固件一起被提供,以便将来进行加密固件程序的更新,此后发布的固件为加密固件。固件加密场景如图3-100所示。
图3-100 固件加密场景1
2.场景二:设备固件在原始版本中已加密
(1)虽然设备固件在原始版本中已加密,但是厂商决定更改加密方案,并发布一个未加密的转换版本v1.2,其中包含了新的解密程序。固件加密场景如图3-101所示。
图3-101 固件加密场景2
(2)虽然设备固件在原始版本中已加密,但是厂商决定更改加密方案,并发布一个包含新版本解密程序的未加密转换版本。固件加密场景如图3-102所示。
图3-102 固件加密场景3
3.案例:D-Link DIR-878路由器解密
(1)获取DIR-878路由器固件的过程代码如图3-103所示。从结果中可知,该路由器固件的版本号为v1.04。
图3-103 获取DIR-878路由器固件的过程代码
(2)使用binwalk-Me命令将固件解包,之后进入固件文件系统根目录,代码如下。
(3)找到bin/imgdecrypt二进制文件,并使用以下代码解密高版本加密固件。
(4)解密后的固件存放在/tmp/.firmware.orig目录下,使用如图3-104所示的Binwalk工具正常解包即可。
图3-104 使用Binwalk工具正常解包解密后的固件
固件重打包是在对设备原有固件进行解包之后,先在固件中加入自定义的功能,再对其进行重打包并将重打包的固件刷回设备。固件重打包经常用于种植后门木马或者获取调试设备权限。
根据3.3.3节中内容可知,物联网设备固件一般由头部分和数据部分组成。由于在进行逆向分析时,通常关注的是如何使用Binwalk工具提取文件系统,因此在对设备固件进行修改时,必须了解以下内容。
1.uImage header简介及实例
uImage是U-boot专用的镜像文件,是在zImage(经过gzip命令压缩的vmlinux内核镜像)之前加上一个长度为64字节的文件头,是存储整个镜像概括信息的区域。
1)uImage header简介
uImage header一般放在固件的头部位置,也可以放在固件的中间位置。uImage header中一般存储的信息有uImage header大小(默认为64字节)、uImage header的CRC32的值、固件总大小,以及除了uImage header的data区域CRC32的值及固件镜像的一些基本属性,如设备的CPU类型、镜像压缩算法、镜像名等。
2)uImage header实例
使用Binwalk工具分析得到某个固件uImage header的代码如下。
从以上代码中可以获取如下具体信息。
(1)header size:64 bytes.
(2)header CRC:0xCFAB1B51.
(3)image size:3755611 bytes(整个固件减去uImage header的大小)。
(4)data CRC:0x1352BC1D.
(5)固件的指令集架构为MIPS架构。
(6)数据压缩算法是lzma。
(7)固件名称为B-LINK Linux Image。
2.uImage header的十六进制的表示方法
uImage header在hexdump命令下的信息如图3-105所示。
图3-105 uImage header在hexdump命令下的信息
其中,左上方框中的内容表示的是uImage header的CRC32的值(也就是从0x00到0x40的数据的CRC32的值);右上方框中的内容表示的是固件data段数据的总大小(0x394e5b,即date段数据的总大小为3755611字节);中间方框中的内容表示的是data段数据的CRC32的值。
3.uImage header的CRC32的值的计算方法
在对固件进行修改之后,需要重新计算uImage header的CRC32的值并替换,计算过程如下。
(1)使用dd命令单独对uImage header进行提取。
(2)将原uImage header CRC位置的值覆盖成00 00 00 00。
(3)使用010 Editor工具或者其他可以计算CRC32的值的工具计算uImage header的CRC32的值。
如图3-106所示,使用010 Editor工具计算uImage header的CRC32的值为CFAB1B51,对应了上面的数值。
图3-106 计算uImage header的CRC32的值