3. 固件获取与提取:从Flash芯片读取到BGA拆焊
固件逆向的第一步,也是最关键的一步——把固件拿到手。没有二进制,后面全是空谈。
我见过太多人,花了几周时间分析一个根本不完整的固件,最后发现是提取环节出了问题。所以这一章,咱们把固件获取的几种主流手段掰开揉碎了讲清楚。
3.1 从Flash芯片读取:SPI与I2C接口
嵌入式设备里最常见的固件载体就是Flash芯片。SPI Flash占绝大多数,I2C EEPROM在一些低端设备里也能见到。
3.1.1 SPI Flash读取
SPI Flash引脚少,速度快,容量大。标准25系列(如W25Q64、MX25L128)几乎统治了IoT设备市场。
硬件连接要点:
- VCC/GND:供电必须稳定,我习惯用3.3V,别搞错电压
- CS#:片选,拉低才能通信
- SCK:时钟,一般10MHz以内都稳
- MOSI/MISO:数据线,注意交叉连接
常用工具与命令:
我个人最常用的是CH341A编程器配合flashrom开源工具。便宜、稳定、社区支持好。
# 识别芯片
flashrom -p ch341a_spi -V
# 读取整个固件
flashrom -p ch341a_spi -r firmware.bin
# 校验读取结果
flashrom -p ch341a_spi -v firmware.bin
读取完成后,用hexdump或binwalk快速看一眼,确认不是全0或全1。
3.1.2 I2C EEPROM读取
I2C接口的EEPROM容量小(通常2KB~256KB),多用于存储配置参数或Bootloader。读取时注意设备地址,7位地址常见于0x50~0x57。
# 使用i2c-tools扫描总线
i2cdetect -y 1
# 读取256字节
i2cget -y 1 0x50 0x00 i 256 > eeprom.bin
3.2 从JTAG/SWD接口转储
如果Flash芯片被封装在BGA下面,或者板子有读保护,JTAG/SWD就成了突破口。
3.2.1 JTAG接口
JTAG有4个标准信号:TMS、TCK、TDI、TDO。加上TRST和SRST可选。连接时注意目标板电压,1.8V和3.3V很常见。
常用工具:
- OpenOCD:开源,支持芯片多
- J-Link:商业工具,速度快
- Bus Blaster:便宜好用
# OpenOCD连接STM32示例
openocd -f interface/jlink.cfg -f target/stm32f4x.cfg
# 读取Flash内容
flash read_bank 0 firmware.bin 0x08000000 0x100000
3.2.2 SWD接口
SWD只有两根线:SWDIO和SWCLK。ARM Cortex-M系列几乎都支持。我个人觉得SWD比JTAG更稳定,尤其在高速模式下。
3.2.3 绕过读保护
很多芯片有读保护(RDP)。Level 1可以用全擦除解除,Level 2基本无解。我遇到过一台设备,RDP Level 1,但Bootloader里有个漏洞,可以通过串口命令解锁——这就是另一个故事了。
| 保护等级 | 描述 | 绕过难度 |
|---|---|---|
| Level 0 | 无保护 | 直接读取 |
| Level 1 | 禁止调试接口读取Flash | 中等(全擦除或漏洞利用) |
| Level 2 | 永久锁定,不可回退 | 极高(物理攻击) |
3.3 从OTA更新包提取
OTA更新包是固件逆向的“金矿”。厂商通常会把固件打包成加密或压缩的格式,但总有办法拆开。
3.3.1 抓包获取
用Wireshark抓取设备升级时的网络流量。HTTP/HTTPS、MQTT、CoAP都有可能。我习惯在路由器上做端口镜像,或者用中间人代理。
# 使用mitmproxy抓取HTTPS流量
mitmproxy --mode transparent --listen-port 8080
3.3.2 解包分析
拿到更新包后,先看文件头。常见格式:
- 原始二进制:直接就是固件
- 差分补丁:bsdiff/xdelta,需要原固件
- 加密包:AES/RSA,需要找密钥
- 容器格式:U-Boot的uImage、Intel HEX、SREC
# 查看文件头
hexdump -C update.bin | head -20
# 使用binwalk自动提取
binwalk -Me update.bin
3.4 从BGA芯片拆焊读取
这是最后的手段。当Flash芯片是BGA封装,且没有其他接口可用时,只能拆下来读。
3.4.1 拆焊工具
- 热风枪:温度控制在280~350°C,风速适中
- 预热台:防止PCB变形
- 助焊剂:必须用,不然锡球不熔化
- 镊子:陶瓷或钛合金,不导热
3.4.2 操作步骤
- PCB固定在预热台上,预热到100°C左右
- 热风枪对准芯片,均匀加热
- 用镊子轻轻推动芯片,感觉锡球熔化后取下
- 清理焊盘,植球或直接飞线到编程器
3.4.3 读取方式
拆下来的芯片可以用专用BGA编程器读取,或者飞线到SPI编程器。BGA封装的Flash内部还是SPI接口,只是引脚间距小。
# 飞线后读取
flashrom -p ch341a_spi -r bga_firmware.bin
3.5 知识体系总览
下面这张图总结了固件获取的四种路径和适用场景:
3.6 避坑指南
做了这么多年固件逆向,我踩过的坑不少。挑几个典型的说说:
- 电压不匹配:1.8V的Flash接到3.3V编程器,芯片直接冒烟。先查datasheet
- 在线干扰:芯片在主板上时,其他器件可能干扰SPI总线。我习惯断开CS#引脚再读
- 读保护误判:有时候不是读保护,而是芯片进入了低功耗模式。复位一下再试
- OTA包不完整:抓包时漏了分片,解出来固件校验失败。用Wireshark的Follow TCP Stream功能