第三章 固件提取与解包:从硬件芯片读取固件

做固件安全审计,第一步就是拿到固件。这听起来简单,但实际操作中,我见过太多人在这一步就卡住了。你想想看,如果连固件都拿不到,后面的分析全是空谈。

这一章,我们就来聊聊怎么从硬件芯片里把固件“掏”出来,以及怎么把那些打包好的固件格式给解开。

3.1 从 SPI Flash 读取固件

SPI Flash 是目前最常见的固件存储介质。路由器、智能家居设备、物联网终端,十有八九用的都是它。为什么?便宜、接口简单、体积小。

读取 SPI Flash,我个人的习惯是直接用编程器。市面上常见的如 CH341A、FT2232H 都可以。操作步骤其实不复杂:

  1. 找到芯片:板子上找 8 脚或 16 脚的芯片,丝印一般是 25Qxx、W25Qxx 这类。
  2. 连接引脚:把编程器的夹子或座子对应接好。注意方向,别接反了。
  3. 读取数据:用软件(如 FlashROM、SPI Flash Tool)读取全片数据。
⚠️ 注意: 有些芯片有写保护引脚(WP#)或硬件保护位。我曾经遇到过一块芯片,读出来全是 0xFF,折腾了半天才发现是保护位没解除。所以,读取前最好先检查一下状态寄存器。

这里有个小技巧:如果你不确定芯片型号,可以先用编程器识别一下。大多数编程器软件都有自动识别功能。识别出来后再选对应的型号读取。

3.2 从 NAND Flash 读取固件

NAND Flash 比 SPI Flash 复杂一些。它通常用在需要大容量存储的设备上,比如高端路由器、网络摄像头、工业控制器。

读取 NAND Flash 时,有几个关键点要注意:

  • 坏块管理:NAND 出厂时就可能有坏块,读取时不能直接按顺序读,要跳过坏块。
  • ECC 校验:NAND 的数据容易出错,需要 ECC 纠错。不同厂商的 ECC 算法可能不一样。
  • 页大小:常见的有 512B、2KB、4KB 等,读取时要按页对齐。

我建议用专门的 NAND 编程器,比如 RT809H、TL866II Plus 这类。它们能自动处理坏块和 ECC。如果你非要自己用飞线接,那就要准备好折腾了。

💡 经验之谈: 读取 NAND 时,最好多读几次,对比一下数据是否一致。因为 NAND 本身就有比特翻转的特性,一次读取可能不准。

3.3 常见固件格式解包

固件读出来后,通常不是裸数据,而是被某种文件系统打包好的。最常见的三种是 Cramfs、Squashfs 和 JFFS2。

3.3.1 Cramfs

Cramfs 是早期 Linux 嵌入式系统常用的只读文件系统。特点是压缩率高,但只支持只读。

解包 Cramfs 很简单,用 Linux 下的 cramfsck 工具就行:

# 解包 Cramfs 固件
cramfsck -x output_dir firmware.cramfs

如果系统里没有这个工具,可以自己编译一个。源码在 GitHub 上很容易找到。

3.3.2 Squashfs

Squashfs 是目前最主流的固件格式。它比 Cramfs 更灵活,支持压缩、支持多种块大小。OpenWrt、DD-WRT 这些系统都用它。

解包 Squashfs 推荐用 unsquashfs 工具:

# 解包 Squashfs 固件
unsquashfs -d output_dir firmware.squashfs

有时候你会遇到解包失败的情况。别慌,很可能是固件头被修改过,或者用了非标准的压缩算法。这时候可以试试用 binwalk 先分析一下:

# 用 binwalk 分析固件结构
binwalk firmware.bin

binwalk 会告诉你固件里有哪些文件系统、偏移量是多少。然后你可以手动指定偏移量来解包。

🔑 关键点: Squashfs 有多个版本(v3、v4),不同版本的压缩算法不同。解包前最好确认一下版本。我遇到过用 v3 工具解 v4 固件,结果解出来全是乱码。

3.3.3 JFFS2

JFFS2 是专门为 NAND Flash 设计的日志型文件系统。它支持磨损均衡和坏块管理,所以常用于 NAND 设备。

解包 JFFS2 稍微麻烦一点,因为它需要模拟一个 MTD 设备。我一般用 jefferson 这个工具:

# 解包 JFFS2 固件
jefferson -d output_dir firmware.jffs2

如果 jefferson 不行,还可以用 mtd-utils 里的 flash_erasenandwrite 配合模拟。不过那个步骤比较繁琐,我建议优先用 jefferson

3.4 核心逻辑:固件提取与解包流程

下面这张图概括了从硬件芯片到可分析文件系统的完整流程:

固件提取与解包核心流程 SPI Flash / NAND 硬件芯片 编程器 / 调试器 读取原始数据 固件镜像文件 .bin / .img binwalk 分析 识别格式 Cramfs cramfsck 解包 Squashfs unsquashfs 解包 JFFS2 jefferson 解包 文件系统 → 可分析的文件结构

3.5 避坑指南

做固件提取和解包,有几个坑我踩过,分享给你:

  • 芯片电压不匹配:SPI Flash 有 3.3V 和 1.8V 两种。我曾经用 3.3V 的编程器去读 1.8V 的芯片,结果芯片直接冒烟了。所以,读取前一定要确认电压。
  • 固件头被篡改:有些厂商会在固件头加自定义标记,导致标准工具无法识别。这时候需要手动分析二进制数据,找到真正的文件系统起始位置。
  • 多分区固件:一个固件文件里可能包含多个分区(bootloader、kernel、rootfs)。binwalk 可以帮你识别分区边界,然后分别提取。
💡 我的习惯: 拿到一个固件后,先用 file 命令看看文件类型,再用 binwalk 扫描一遍。这样心里就有底了,知道接下来该用什么工具。

好了,这一章的内容就到这里。固件提取和解包是基本功,多练几次就熟练了。记住,拿到固件只是第一步,后面的分析才是重头戏。


公众号:蓝海资料掘金营,微信deep3321