4、固件解包与识别:使用binwalk分析固件结构、识别文件系统、手动提取与修复
拿到一个固件,第一件事是什么?
不是急着去逆向,而是先搞清楚它里面到底装了啥。说白了,就是给固件做个“CT扫描”。
我个人的习惯是,先跑一遍 binwalk,看看固件里藏了多少东西。这工具就像一把瑞士军刀,能帮你快速定位文件系统、内核镜像、甚至是一些加密的签名块。
4.1 binwalk 基础用法
先来个最简单的命令:
binwalk firmware.bin
它会扫描固件,然后列出所有它认识的“签名”。比如你可能会看到:
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 TRX firmware header, little endian, image size: 4194304 bytes, CRC32: 0xABCDEF01, flags: 0x0, version: 1, header size: 28 bytes
28 0x1C LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 2097152 bytes
1052672 0x101000 SquashFS filesystem, little endian, version 4.0, compression:lzma, size: 3145728 bytes, inodes: 1024, blocks: 512
嗯,这里要注意。binwalk 不是万能的。它靠的是“特征签名”来识别。如果固件被加密了,或者用了非标准的魔数,它可能就认不出来。
-T 参数,提高扫描的灵敏度。或者用 -E 看熵值图,加密的固件熵值通常很高,接近1.0。
4.2 识别文件系统:SquashFS、JFFS2、CramFS
固件里最常见的文件系统,我接触最多的是这三种:
| 文件系统 | 特点 | 常见场景 |
|---|---|---|
| SquashFS | 只读、压缩率高、支持大端小端 | OpenWrt、大部分路由器固件 |
| JFFS2 | 可读写、支持闪存磨损均衡 | 老款嵌入式设备、工业控制器 |
| CramFS | 老牌只读文件系统、压缩率一般 | 早期Linux内核、老旧设备 |
binwalk 识别出文件系统后,通常会告诉你偏移量和大小。比如上面那个例子,SquashFS 从 0x101000 开始,大小是 3145728 字节。
我曾经在一个工控设备的固件里,binwalk 识别出了三个 SquashFS 分区。一开始我以为是重复的,后来才发现,一个是主系统,一个是恢复分区,还有一个是配置分区。如果不仔细看偏移量,很容易搞混。
4.3 手动提取与修复
binwalk 自带的 -e 参数可以自动提取,但有时候会失败。为什么?
因为固件可能被“魔改”过。比如厂商把文件系统的魔数改了,或者中间插了一些自定义的头部。这时候,就得手动来。
手动提取的步骤,我一般这么干:
- 确认偏移量:用
binwalk或者hexdump找到文件系统的起始地址。 - 切割文件:用
dd命令把文件系统部分单独切出来。
dd if=firmware.bin of=squashfs_part.bin bs=1 skip=1052672 count=3145728
这里 skip 是跳过的字节数,count 是要提取的长度。这两个值都来自 binwalk 的输出。
- 尝试挂载或解压:
# 尝试挂载 SquashFS
mount -t squashfs -o loop,ro squashfs_part.bin /mnt
# 或者用 unsquashfs 解压
unsquashfs -d ./extracted squashfs_part.bin
如果挂载失败,提示“无法识别文件系统”,那大概率是魔数被改了。
unsquashfs 死活解不开。后来用 hexdump 一看,文件系统的魔数 hsqs 被改成了 hsqS。手动改回来,就能正常解压了。
修复魔数的方法很简单:
# 用 printf 写入正确的魔数
printf '\x68\x73\x71\x73' | dd of=squashfs_part.bin bs=1 seek=0 conv=notrunc
对于 JFFS2 文件系统,情况更复杂一些。它通常需要知道擦除块大小。如果 binwalk 没识别出来,可以试试 jefferson 工具:
jefferson -d ./jffs2_root jffs2_part.bin
如果还是不行,可能是文件系统有损坏,或者固件里包含了多个 JFFS2 分区,需要手动拼接。
4.4 核心逻辑:固件解包流程
下面这张图,是我自己总结的固件解包流程。每次拿到新固件,我都会按这个思路走一遍。
这个流程看起来简单,但实际工作中,每一步都可能遇到坑。比如第二步,binwalk 识别成功了,但自动提取出来的文件系统是坏的。这时候,就得回到手动分析的路子上来。
- binwalk 是起点,不是终点。它帮你定位,但不保证提取成功。
- 手动提取时,
dd命令的偏移量和大小必须精确。差一个字节,文件系统就可能挂不上。 - 魔数修复是常见操作。SquashFS 的魔数是
hsqs,JFFS2 的魔数是1985(小端序)。 - 遇到加密固件,先找密钥。密钥可能在 bootloader 里,也可能在固件的某个固定偏移处。
我记得有一次,一个客户拿来的工控固件,binwalk 扫出来全是乱码。我一看熵值,0.99,明显是加密了。后来在 bootloader 里找到了 AES 密钥,写了个脚本解密,才看到里面的 SquashFS。嗯,那一次折腾了整整两天。
所以,别指望一个工具解决所有问题。binwalk 是你的好帮手,但真正的功夫,在于你手动分析和修复的能力。
/etc/init.d/ 和 /sbin/init 这两个文件。它们能告诉你固件的启动流程和关键服务。有时候,漏洞就藏在这些启动脚本里。
好了,这一章的内容就到这里。记住,固件解包是逆向的第一步,也是最关键的一步。基础打牢了,后面的分析才能事半功倍。
公众号:蓝海资料掘金营,微信deep3321