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

固件逆向分析的第一步,也是最关键的一步,就是获取目标固件。没有原始固件镜像,后续的静态分析、漏洞挖掘、协议逆向都无从谈起。在实际工程中,固件并非总是以“一个完整的.bin文件”形式存在——它可能被焊死在SPI闪存中、通过JTAG调试口加密导出、由Bootloader通过串口输出,或者被厂商封装在在线升级包中。本章将系统梳理四种主流固件获取途径(SPI闪存、JTAG、串口、在线升级包),并深入讲解固件镜像格式识别与解包工具链(binwalk、UEFITool、flashrom)的核心用法与实战技巧。

固件获取与提取技术全景图 SPI闪存 flashrom / 编程器 SOIC-8夹子 / 热风枪 读取速度: 1-8MB/s 风险: 焊盘损伤 JTAG/SWD OpenOCD / J-Link 读取Flash/RAM内容 需找到测试点/排针 风险: 目标板供电 串口/UART Bootloader交互 U-Boot / CFE / RedBoot 通过loady/loadb命令 风险: 波特率误判 在线升级包 固件服务器抓包 HTTP/FTP/TFTP 加密/签名校验 风险: 需解密绕过 原始固件镜像 (Raw Binary) 格式识别与解包工具链 binwalk / UEFITool / flashrom / 010 Editor binwalk 文件签名扫描/熵分析/自动提取 UEFITool UEFI/BIOS解析 flashrom SPI闪存读写/校验/擦除 可分析的文件系统 / 内核 / 引导程序 / 配置分区

3.1 SPI闪存固件提取:硬件直读与编程器操作

核心原理

SPI(Serial Peripheral Interface)闪存是当前嵌入式设备中最常见的固件存储介质,广泛应用于路由器、智能家居网关、工业控制器、网络摄像头等设备。其容量通常在1MB到64MB之间,通过SPI总线与主控芯片(SoC/CPU)连接。固件以二进制形式存储在闪存的线性地址空间中,起始地址通常为0x00000000(或由BootROM映射到特定基地址)。提取SPI闪存固件的本质,就是绕过系统运行时的访问控制,直接通过编程器或调试接口对闪存芯片进行物理读取。

从硬件层面看,SPI闪存有8个引脚(SOIC-8封装):CS#(片选)、CLK(时钟)、DI(数据输入)、DO(数据输出)、VCC(电源)、GND(地),以及WP#(写保护)和HOLD#(保持)。提取固件时,需要将编程器的探针或夹子正确连接到这些引脚,并确保目标板断电或处于复位状态,避免主控芯片与编程器同时驱动SPI总线造成冲突。

操作流程:从识别到完整转储

  1. 识别闪存型号:观察PCB丝印,常见型号包括Winbond W25Q128(16MB)、Macronix MX25L25645G(32MB)、GigaDevice GD25Q64(8MB)等。若丝印模糊,可用万用表测量VCC和GND确认供电电压(3.3V或1.8V)。
  2. 选择连接方式:对于DIP-8封装的闪存,可直接使用烧录座;对于贴片SOIC-8,优先使用免拆夹子(如Pomona 5250);若夹子接触不良,则需热风枪拆焊后使用烧录座。
  3. 配置flashrom:安装flashrom后,先检测编程器是否识别:
    flashrom -p ch341a_spi
    # 输出示例: Found Winbond flash chip "W25Q128" (16384 kB, SPI)
  4. 读取固件:
    flashrom -p ch341a_spi -r firmware_dump.bin
    # 读取完成后建议校验: flashrom -p ch341a_spi -v firmware_dump.bin
  5. 多次读取对比:至少读取两次,使用sha256sum对比哈希值,确保读取过程无位翻转。

案例拆解:某品牌路由器固件提取

某型号路由器使用Winbond W25Q128(16MB)存储完整固件。初始现象是设备启动后无法进入管理界面,疑似固件损坏。分析目标是提取原始固件用于恢复和逆向。关键参数:闪存供电3.3V,PCB丝印标注TP1-TP4为SPI测试点。操作步骤:首先用万用表确认TP1=CS#、TP2=CLK、TP3=DI、TP4=DO,然后使用免拆夹子连接CH341A编程器。flashrom识别芯片后,以8MB/s速度读取,耗时约2秒。读取两次哈希一致后,用binwalk扫描发现固件包含U-Boot、Linux内核、SquashFS文件系统。复盘经验:免拆夹子在高速读取时容易因接触不良产生错误,建议降低SPI时钟频率(flashrom -p ch341a_spi --spi-speed 1000)以提高稳定性。

风险提示:SPI闪存提取时,若目标板仍连接电源,编程器与主控芯片可能同时驱动DO引脚,导致读取数据错误甚至损坏芯片。务必确保目标板完全断电,并优先使用夹子而非飞线以减少干扰。

3.2 JTAG/SWD调试接口提取:从调试口获取内存与Flash

核心原理

JTAG(Joint Test Action Group,IEEE 1149.1)和SWD(Serial Wire Debug)是芯片级调试接口,允许外部调试器直接访问CPU内核、内存映射和外设寄存器。对于固件提取而言,JTAG的价值在于:即使系统未启动或操作系统崩溃,调试器仍可通过DAP(Debug Access Port)读取Flash控制器映射的地址空间。ARM Cortex-A/M系列芯片通常同时支持JTAG和SWD,后者仅需2根线(SWDIO、SWCLK),更适合紧凑型设备。

JTAG提取固件的本质是利用调试接口的内存访问权限,绕过软件层面的保护。但现代芯片(如i.MX、STM32MP1)可能启用Secure Boot或JTAG熔丝锁定,此时需要先通过硬件攻击(如电压故障注入)或利用已知漏洞解锁调试口。

操作流程:OpenOCD + J-Link实战

  1. 定位调试接口:检查PCB上是否有4针(SWD)或14/20针(JTAG)排针,若无则需查阅芯片数据手册寻找测试点。
  2. 连接调试器:以J-Link为例,连接SWDIO、SWCLK、GND、VCC(可选,用于电平参考)。
  3. 配置OpenOCD:
    # openocd.cfg
    source [find interface/jlink.cfg]
    transport select swd
    source [find target/stm32mp1.cfg]
    # 连接后执行:
    # flash read_bank 0 firmware.bin 0 0x100000
  4. 读取Flash:通过OpenOCD命令将Flash内容导出为二进制文件。

常见误区与总结

  • 误区一:JTAG一定能读取所有Flash。实际上,若芯片启用了RDP(Read-out Protection)级别2,JTAG/SWD将被永久禁用,只能通过全片擦除解除。
  • 误区二:SWD速度越快越好。过高的SWCLK频率可能导致信号反射,建议从1MHz开始逐步提升。
  • 误区三:忽略目标板供电。调试器必须与目标板共地,且目标板需要独立供电,否则电平不匹配会导致通信失败。
经验提醒:对于量产设备,JTAG测试点可能被电阻或0欧姆跳线隔离。使用万用表蜂鸣档测量测试点与主控芯片引脚之间的连通性,可快速确认调试口是否有效。

3.3 串口Bootloader提取:利用U-Boot/CFE导出固件

核心原理

绝大多数嵌入式Linux设备在量产时保留了串口调试接口(UART),Bootloader(如U-Boot、CFE、RedBoot)通过串口提供交互式命令行。若Bootloader未设置密码或存在已知绕过漏洞,攻击者可在启动阶段中断自动启动流程,进入命令行环境。此时可利用Bootloader内置的loady(YMODEM)、loadb(二进制)、tftpboot(TFTP)等命令,将内存中的固件导出到主机,或将外部固件写入Flash。

串口提取的核心优势是无需拆机,只需连接UART的TX、RX、GND三根线。但前提是Bootloader必须可用,且Flash中的固件未被加密或签名校验阻断。

操作流程:U-Boot下导出固件

  1. 连接串口:使用USB转TTL模块,波特率通常为115200或57600,连接目标板UART接口。
  2. 中断启动:上电后迅速按下Ctrl+C或空格键,进入U-Boot命令行。
  3. 查看Flash布局:
    U-Boot> sf probe
    U-Boot> sf read 0x82000000 0x0 0x1000000  # 读取16MB到内存
  4. 导出固件:
    U-Boot> loady 0x82000000 0x1000000
    # 主机端使用minicom或C-Kermit发送YMODEM接收

案例拆解:网络摄像头固件提取

某IP摄像头使用海思Hi3518E芯片,U-Boot版本为2010.06。初始现象:设备固件损坏,无法正常启动。分析目标:提取完整固件用于恢复。关键参数:串口波特率115200,Flash容量8MB。操作步骤:连接串口后中断启动,执行sf probe识别SPI Flash,使用sf read 0x82000000 0x0 0x800000读取全部8MB到内存,然后通过loady配合主机端lrzsz工具接收。结果:成功导出8MB固件,binwalk识别出H.264编码器固件和根文件系统。复盘经验:YMODEM传输速度约10KB/s,8MB需约14分钟,建议改用TFTP传输(tftpboot 0x82000000 firmware.bin)可提速至1MB/s。

关键命令速查:
# U-Boot导出固件到内存
sf probe
sf read 0x82000000 0x0 0x800000
# 通过TFTP上传到主机
tftpboot 0x82000000 firmware.bin
# 通过YMODEM上传
loady 0x82000000 0x800000

3.4 在线升级包获取:抓包与固件解密

核心原理

在线升级(OTA)是获取固件最便捷的途径,厂商通常将固件打包为加密或签名的镜像文件,通过HTTP/HTTPS服务器分发。提取升级包的难点不在于网络抓包,而在于解密和去签名。常见固件包格式包括:TRX(TP-Link)、BIN(D-Link)、CHK(ZyXEL)、PKG(小米)、IMG(通用)。部分厂商使用AES-128-CBC加密,密钥硬编码在Bootloader或主控固件中;另一些使用RSA签名校验,但可能因密钥泄露或校验逻辑缺陷被绕过。

操作流程:从抓包到解包

  1. 抓包获取固件:使用Burp Suite或Fiddler设置代理,触发设备升级,捕获HTTP请求中的固件下载URL。
  2. 下载固件:
    wget http://firmware.vendor.com/update/AC1200_V1.2.3.bin
  3. 识别格式:使用file命令和binwalk扫描:
    file AC1200_V1.2.3.bin
    binwalk AC1200_V1.2.3.bin
  4. 解密处理:若binwalk显示“AES encrypted data”,需从Bootloader中提取密钥,使用openssl解密:
    openssl enc -d -aes-128-cbc -K 00112233445566778899AABBCCDDEEFF -iv 00000000000000000000000000000000 -in encrypted.bin -out decrypted.bin

常见误区与总结

  • 误区一:升级包一定是明文。实际上,2020年后的主流路由器厂商(TP-Link、Netgear、小米)均对固件进行加密或签名。
  • 误区二:抓包只能抓HTTPS。部分设备使用HTTP明文传输,但URL可能包含动态,需在短时间内下载。
  • 误区三:解密后即可直接分析。解密后的固件可能仍包含U-Boot头部、文件系统偏移等,需结合binwalk进一步处理。

3.5 固件镜像格式识别与解包工具链

核心原理

获取到原始固件后,需要识别其内部结构。固件镜像通常由多个部分组成:引导程序(Bootloader)、内核(Kernel)、根文件系统(RootFS)、配置分区、校准数据等。binwalk通过扫描文件签名(Magic Bytes)识别嵌入式文件系统(SquashFS、JFFS2、CramFS)、压缩算法(gzip、lzma、xz)、内核镜像(Linux zImage、FIT)等。UEFITool则专门用于解析UEFI BIOS固件,提取其中的DXE驱动、PEI模块、NVRAM变量等。flashrom除了读写SPI闪存外,也支持识别固件中的Flash布局。

binwalk实战:从扫描到自动提取

# 扫描固件中的文件签名
binwalk firmware.bin

# 详细扫描(包含熵分析)
binwalk -E firmware.bin

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

# 提取指定偏移的文件
dd if=firmware.bin of=rootfs.squashfs bs=1 skip=0x1F0000 count=0x500000

UEFITool解析BIOS固件

对于UEFI BIOS,UEFITool可打开原始固件镜像,以树形结构展示Firmware Volume、Firmware File System、EFI Modules。操作流程:打开固件文件→选择“Extract All”导出所有模块→使用IDA Pro分析特定DXE驱动。关键功能包括:Search(搜索GUID、字符串)、Rebuild(重建固件)、Extract Body(提取模块原始二进制)。

知识结构表格:固件格式与工具匹配

固件类型典型特征推荐工具输出内容
SPI Flash完整镜像以FF或00填充开头,包含U-Boot头部flashrom + binwalkBootloader、Kernel、RootFS
UEFI BIOS包含“EFI PART”或“_FVH”签名UEFIToolDXE驱动、PEI模块、NVRAM
路由器升级包TRX/CHK/PKG头部binwalk + 自定义脚本文件系统、Web界面源码
加密固件高熵数据,无明文签名熵分析 + 密钥提取解密后的明文镜像
MCU裸机固件ARM Cortex-M向量表(0x20000000)objdump + Ghidra中断向量、代码段

案例拆解:智能门锁固件完整分析

某智能门锁使用STM32F407主控,固件通过OTA升级。初始现象:升级包仅200KB,疑似仅包含应用层代码。分析目标:提取完整固件(包括Bootloader和蓝牙协议栈)。关键参数:Flash 1MB,SRAM 192KB。操作步骤:首先通过串口Bootloader(ISP模式)读取全部Flash,得到1MB镜像。binwalk扫描发现固件分为三个区域:0x00000-0x10000为Bootloader(含自定义签名),0x10000-0x80000为应用固件(含FreeRTOS内核),0x80000-0x100000为配置存储(含蓝牙MAC地址和密钥)。使用objdump -D -b binary -m arm反汇编应用固件,定位到OTA校验函数,发现其仅验证CRC32而非RSA签名,因此可构造恶意升级包。复盘经验:即使固件有加密,Bootloader中的密钥提取和校验逻辑分析仍是突破口。

法律与合规提醒:固件提取与分析仅限用于安全研究、漏洞挖掘、产品兼容性测试等合法目的。未经授权提取商业设备固件并用于破解、抄袭或恶意攻击,可能违反《计算机软件保护条例》和《网络安全法》。请确保在获得设备所有权或厂商授权的前提下进行研究。

3.6 固件提取的工程化总结与风险控制

核心原理

固件提取不是单一操作,而是一个需要综合运用硬件、软件、密码学知识的系统工程。选择提取途径时,应遵循“从易到难、从软到硬”的原则:优先尝试在线升级包(无需拆机),其次串口Bootloader(需物理接触但无需拆焊),再次SPI闪存(需拆机但成功率最高),最后JTAG(需调试口且可能被锁定)。

提取方法对比表

方法难度风险成功率适用场景
在线升级包低低(仅网络流量)中(可能加密)消费级路由器、IoT设备
串口Bootloader中低(仅需UART)高(若Bootloader可用)Linux嵌入式设备、开发板
SPI闪存中高中(可能损坏焊盘)极高(物理直读)所有含SPI Flash的设备
JTAG/SWD高中(可能触发保护)中(受RDP限制)MCU、应用处理器

常见误区与总结复盘

  • 误区一:固件提取必须拆芯片。实际上,串口和OTA途径往往更高效,且不会造成物理损伤。
  • 误区二:binwalk能识别所有固件。binwalk依赖签名库,对于自定义格式或加密固件可能失效,需结合熵分析和手动偏移分析。
  • 误区三:读取固件后直接分析。应先验证固件完整性(哈希校验),再制作备份,最后才进行解包分析。
  • 误区四:忽略固件版本差异。同一型号不同版本的固件可能采用不同的加密方式或分区布局,提取时应记录设备型号、硬件版本、固件版本。
工程化建议:建立固件提取的标准操作流程(SOP):①记录设备信息→②选择提取途径→③制作固件备份→④验证哈希→⑤格式识别→⑥解包分析→⑦归档记录。每一步都应有明确的输出物和校验点,确保可复现、可追溯。

固件获取与提取是逆向工程的地基,掌握SPI闪存直读、JTAG调试、串口Bootloader和OTA抓包四种方法,并熟练运用binwalk、UEFITool、flashrom等工具,能够覆盖绝大多数嵌入式设备的固件提取需求。在实际项目中,往往需要组合多种方法:例如先通过OTA获取加密固件,再通过串口Bootloader提取解密密钥,最后用SPI编程器完整转储Flash。这种多维度、交叉验证的提取策略,是专业固件逆向工程师的核心能力之一。