3、固件获取与提取:从芯片、板卡、设备中提取固件的方法
固件逆向分析的第一步,也是最关键的一步,就是获取目标固件。没有原始固件镜像,后续的静态分析、漏洞挖掘、协议逆向都无从谈起。在实际工程中,固件并非总是以“一个完整的.bin文件”形式存在——它可能被焊死在SPI闪存中、通过JTAG调试口加密导出、由Bootloader通过串口输出,或者被厂商封装在在线升级包中。本章将系统梳理四种主流固件获取途径(SPI闪存、JTAG、串口、在线升级包),并深入讲解固件镜像格式识别与解包工具链(binwalk、UEFITool、flashrom)的核心用法与实战技巧。
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总线造成冲突。
操作流程:从识别到完整转储
- 识别闪存型号:观察PCB丝印,常见型号包括Winbond W25Q128(16MB)、Macronix MX25L25645G(32MB)、GigaDevice GD25Q64(8MB)等。若丝印模糊,可用万用表测量VCC和GND确认供电电压(3.3V或1.8V)。
- 选择连接方式:对于DIP-8封装的闪存,可直接使用烧录座;对于贴片SOIC-8,优先使用免拆夹子(如Pomona 5250);若夹子接触不良,则需热风枪拆焊后使用烧录座。
- 配置flashrom:安装flashrom后,先检测编程器是否识别:
flashrom -p ch341a_spi # 输出示例: Found Winbond flash chip "W25Q128" (16384 kB, SPI) - 读取固件:
flashrom -p ch341a_spi -r firmware_dump.bin # 读取完成后建议校验: flashrom -p ch341a_spi -v firmware_dump.bin - 多次读取对比:至少读取两次,使用
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)以提高稳定性。
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实战
- 定位调试接口:检查PCB上是否有4针(SWD)或14/20针(JTAG)排针,若无则需查阅芯片数据手册寻找测试点。
- 连接调试器:以J-Link为例,连接SWDIO、SWCLK、GND、VCC(可选,用于电平参考)。
- 配置OpenOCD:
# openocd.cfg source [find interface/jlink.cfg] transport select swd source [find target/stm32mp1.cfg] # 连接后执行: # flash read_bank 0 firmware.bin 0 0x100000 - 读取Flash:通过OpenOCD命令将Flash内容导出为二进制文件。
常见误区与总结
- 误区一:JTAG一定能读取所有Flash。实际上,若芯片启用了RDP(Read-out Protection)级别2,JTAG/SWD将被永久禁用,只能通过全片擦除解除。
- 误区二:SWD速度越快越好。过高的SWCLK频率可能导致信号反射,建议从1MHz开始逐步提升。
- 误区三:忽略目标板供电。调试器必须与目标板共地,且目标板需要独立供电,否则电平不匹配会导致通信失败。
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下导出固件
- 连接串口:使用USB转TTL模块,波特率通常为115200或57600,连接目标板UART接口。
- 中断启动:上电后迅速按下Ctrl+C或空格键,进入U-Boot命令行。
- 查看Flash布局:
U-Boot> sf probe U-Boot> sf read 0x82000000 0x0 0x1000000 # 读取16MB到内存 - 导出固件:
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签名校验,但可能因密钥泄露或校验逻辑缺陷被绕过。
操作流程:从抓包到解包
- 抓包获取固件:使用Burp Suite或Fiddler设置代理,触发设备升级,捕获HTTP请求中的固件下载URL。
- 下载固件:
wget http://firmware.vendor.com/update/AC1200_V1.2.3.bin - 识别格式:使用
file命令和binwalk扫描:file AC1200_V1.2.3.bin binwalk AC1200_V1.2.3.bin - 解密处理:若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 + binwalk | Bootloader、Kernel、RootFS |
| UEFI BIOS | 包含“EFI PART”或“_FVH”签名 | UEFITool | DXE驱动、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依赖签名库,对于自定义格式或加密固件可能失效,需结合熵分析和手动偏移分析。
- 误区三:读取固件后直接分析。应先验证固件完整性(哈希校验),再制作备份,最后才进行解包分析。
- 误区四:忽略固件版本差异。同一型号不同版本的固件可能采用不同的加密方式或分区布局,提取时应记录设备型号、硬件版本、固件版本。
固件获取与提取是逆向工程的地基,掌握SPI闪存直读、JTAG调试、串口Bootloader和OTA抓包四种方法,并熟练运用binwalk、UEFITool、flashrom等工具,能够覆盖绝大多数嵌入式设备的固件提取需求。在实际项目中,往往需要组合多种方法:例如先通过OTA获取加密固件,再通过串口Bootloader提取解密密钥,最后用SPI编程器完整转储Flash。这种多维度、交叉验证的提取策略,是专业固件逆向工程师的核心能力之一。