固件提取技术:从物理芯片到文件系统

固件分析的第一步,也是最关键的一步——把固件从设备里「请」出来。我见过不少新手,拿着一个 IoT 设备,翻来覆去不知道从哪下手。其实说白了,提取固件就两条路:硬件方法和软件方法。

这一章,我会把这两条路都给你讲透。包括我踩过的坑,和一些实战技巧。

硬件提取方法

硬件提取,就是直接跟芯片打交道。设备不开机、系统崩溃、或者压根没有软件接口的时候,这是唯一的路。

SPI Flash 提取

大部分嵌入式设备,固件都存在 SPI Flash 里。这种芯片通常 8 个脚,长得像个小蜘蛛。我刚开始做的时候,总觉得这玩意儿很神秘,后来发现,说白了就是把它当 U 盘读。

常用的工具有:

  • 编程器:CH341A、FT2232H、树莓派的 GPIO 也能干这活
  • 夹子:SOP8 夹子,免拆焊,但容易接触不良
  • 热风枪:实在不行就吹下来,焊到转接板上读

我的习惯:先用夹子试,不行再拆焊。夹子读数据时,手要稳,最好用胶带固定一下。我曾经因为手抖,读出来的固件全是 0xFF,白忙活半天。

读取命令很简单,以 CH341A 为例:

# 安装工具
sudo apt-get install flashrom

# 读取整个 Flash,保存为 bin 文件
sudo flashrom -p ch341a_spi -r firmware.bin

# 验证读取是否成功
sudo flashrom -p ch341a_spi -v firmware.bin

注意:读取前一定要确认 Flash 型号和电压。1.8V 的芯片用 3.3V 去读,直接烧掉。我有个同事就干过这事,芯片冒烟了。

JTAG 提取

JTAG 是调试接口,但也能用来 dump 固件。它比 SPI 更「暴力」——直接通过 CPU 把整个内存空间读出来。

JTAG 接口通常有 4 个信号线:

信号 功能 常见颜色
TMS 模式选择 橙色
TCK 时钟 黄色
TDI 数据输入 绿色
TDO 数据输出 蓝色

找 JTAG 接口是个技术活。我常用的方法:

  1. 看 PCB 上有没有 4 个或 5 个一排的过孔
  2. 用万用表量,JTAG 的 TMS 和 TCK 通常有上拉电阻
  3. 用 JTAGulator 或 J-Link 的扫描功能自动识别

实战经验:有一次我拿到一个路由器,SPI Flash 被涂了黑胶,没法直接读。最后通过 JTAG 把整个固件 dump 出来了。JTAG 的速度比 SPI 慢,但胜在不需要拆芯片。

软件提取方法

软件方法的前提是——设备能开机,而且你能拿到 shell 权限。不管是 telnet、SSH 还是串口,只要能执行命令就行。

dd 命令

dd 是 Linux 下的「磁盘克隆」工具。在嵌入式设备上,它能把 Flash 分区整个读出来。

先看看分区表:

cat /proc/mtd
# 输出示例:
# dev:    size   erasesize  name
# mtd0: 00040000 00010000 "bootloader"
# mtd1: 00020000 00010000 "config"
# mtd2: 007a0000 00010000 "firmware"

然后 dump 每个分区:

# 读取 bootloader 分区
dd if=/dev/mtd0 of=/tmp/bootloader.bin

# 读取整个固件分区
dd if=/dev/mtd2 of=/tmp/firmware.bin

# 如果设备有网络,直接传到本地
nc -l -p 1234 > firmware.bin   # 本地执行
dd if=/dev/mtd2 | nc 192.168.1.100 1234  # 设备上执行

避坑指南:我曾经用 dd 读一个 16MB 的 Flash,结果设备内存只有 8MB,直接 OOM 了。后来改用 dd bs=1024 count=16384 分段读取,才搞定。

binwalk 提取

binwalk 是固件分析的瑞士军刀。它不仅能提取,还能识别固件里嵌了什么东西。

基本用法:

# 扫描固件,看看里面有什么
binwalk firmware.bin

# 自动提取所有文件
binwalk -e firmware.bin

# 只提取特定类型的文件(比如 squashfs)
binwalk -D 'squashfs:squashfs' firmware.bin

binwalk 的识别能力很强。它通过文件头签名来识别:

文件类型 文件头签名 说明
U-Boot 0x27051956 常见的 bootloader
SquashFS hsqs / sqsh 只读文件系统
JFFS2 0x1985 可写文件系统
LZMA 0x5D0000 压缩数据
gzip 0x1F8B 压缩数据

为什么 binwalk 这么重要? 因为很多固件是「套娃」结构——外面一层 U-Boot,中间是压缩的内核,最里面才是文件系统。binwalk 能一层层帮你剥开。

固件解包与文件系统挂载

拿到固件文件后,下一步就是把它解包,挂载文件系统,这样才能看到里面的配置、脚本、二进制程序。

解包工具

除了 binwalk,还有一些专用工具:

  • unsquashfs:解压 SquashFS 文件系统
  • jefferson:解压 JFFS2 文件系统
  • firmware-mod-kit:一个集成的固件解包/打包工具集

举个例子,解包一个 SquashFS 文件系统:

# 先用 binwalk 找到文件系统的偏移
binwalk firmware.bin

# 假设 SquashFS 在偏移 0x100000 处
# 用 dd 切出来
dd if=firmware.bin of=rootfs.squashfs bs=1 skip=$((0x100000))

# 解包
unsquashfs rootfs.squashfs

# 解包后的文件在 squashfs-root 目录下
ls squashfs-root/

挂载文件系统

有时候你不想解包,只想看看里面的内容。那就直接挂载:

# 挂载 SquashFS(只读)
sudo mount -t squashfs rootfs.squashfs /mnt/firmware

# 挂载 JFFS2(需要模拟 MTD 设备)
modprobe mtdblock
modprobe jffs2
dd if=rootfs.jffs2 of=/tmp/jffs2.img
sudo mount -t jffs2 /tmp/jffs2.img /mnt/firmware

注意:挂载 JFFS2 比较麻烦,因为它需要 MTD 设备模拟。我建议直接用 jefferson 解包,省事。

知识体系总览

下面这张图,把固件提取的整个流程串起来了。你可以把它当作一个「决策树」——根据你的设备状态,选择对应的提取方法。

固件提取技术体系 固件提取 硬件提取 软件提取 SPI Flash 编程器 / 夹子 JTAG 调试接口 dump dd 命令 分区读取 binwalk 自动识别/提取 固件解包与挂载 解包工具 unsquashfs / jefferson 挂载文件系统 mount -t squashfs / jffs2 根据设备状态选择提取路径:能开机用软件,不能开机用硬件,最终都要解包分析

嗯,这张图基本把本章的内容都串起来了。你从最顶上的「固件提取」开始,根据设备能不能开机,选择左边硬件或者右边软件。最后汇合到「固件解包与挂载」——这是分析前的最后一步。

我个人建议,刚开始做固件分析时,先从软件方法入手。找个能开机的路由器,用 dd 和 binwalk 练手。等熟悉了流程,再挑战硬件提取。毕竟,拆芯片这种事,手一抖就是几百块的成本。