2. 固件逆向工程基础:固件提取技术、二进制分析工具链、固件结构解析
做MCU安全,说白了就是跟二进制打交道。你拿不到源码,只能对着hex文件或者bin文件硬啃。这时候,逆向工程就是你的基本功。
我个人习惯把固件逆向分成三步:拿到固件 → 看懂结构 → 分析代码。每一步都有坑,咱们一个一个说。
2.1 固件提取技术:怎么把固件搞到手?
没有固件,分析个啥?提取固件的方式,取决于你手里有什么。
| 提取方式 | 适用场景 | 工具/方法 | 难度 |
|---|---|---|---|
| 读芯片Flash | 有开发板或目标板,芯片未锁 | J-Link / ST-Link + 厂商工具 | 低 |
| 读外部存储器 | 固件存在SPI Flash / EEPROM | 逻辑分析仪 / 编程器 + 飞线 | 中 |
| OTA抓包 | 设备支持无线升级 | Wireshark + 代理 / 嗅探 | 中高 |
| 拆芯片读Die | 芯片有读保护,硬破解 | 酸腐蚀 + 显微镜 + 探针台 | 极高 |
我的经验:别一上来就想着拆芯片。先试试用调试器读Flash,很多开发板压根没开读保护。我曾经遇到一个项目,客户说固件加密了,结果我用J-Link直接读出来了——他们只开了写保护,没开读保护。
读Flash时,注意地址范围。MCU的Flash通常从0x08000000或0x00000000开始。用J-Link Commander读个例子:
# 连接目标
connect
# 选择设备,比如STM32F103
# 读取整个Flash,保存为bin文件
savebin firmware.bin 0x08000000 0x10000
读出来的bin文件,就是你的分析对象。嗯,这里要注意:如果芯片开了读保护(RDP Level 1或2),调试器会拒绝读取。这时候才考虑其他手段。
2.2 二进制分析工具链:你的武器库
拿到固件后,用什么工具看?我列个清单,都是我自己常用的。
2.2.1 十六进制查看与编辑
- HxD / 010 Editor:快速查看文件头、字符串、Magic Number。
- binwalk:自动扫描固件中的文件系统、压缩包、Bootloader。
2.2.2 反汇编与反编译
- Ghidra:NSA出品,免费,支持ARM/Thumb/Cortex-M。我主力工具。
- IDA Pro:商业工具,插件生态好。但贵。
- objdump:GNU工具链自带,快速看汇编。
2.2.3 固件结构分析
- binwalk:提取文件系统、识别LZMA/gzip压缩。
- strings:找明文字符串,比如WiFi密码、API Key。
- hexdump:看原始字节布局。
避坑指南:我曾经用binwalk分析一个IoT固件,它报了一堆“LZMA compressed data”,结果全是误报。后来手动看文件头才发现,那是厂商自定义的加密魔数。所以,工具的结果要交叉验证,别全信。
2.3 固件结构解析:从二进制到逻辑
MCU固件不是一堆随机字节。它有结构。最常见的布局是这样的:
+-----------------------+
| 中断向量表 (IVT) | <- 起始地址,存放栈指针和复位向量
+-----------------------+
| Bootloader (可选) | <- 引导程序,负责跳转或升级
+-----------------------+
| 应用程序代码 | <- 你的main函数在这里
+-----------------------+
| 只读数据 (.rodata) | <- 字符串、常量
+-----------------------+
| 文件系统 (可选) | <- 如LittleFS、SPIFFS
+-----------------------+
怎么快速定位?看中断向量表。Cortex-M的向量表开头是栈顶地址,第二个是复位向量。这两个值通常是合法的RAM和Flash地址。比如:
0x08000000: 0x20001000 (栈顶,指向RAM)
0x08000004: 0x08000123 (复位向量,指向Flash)
如果这两个值看起来合理,那基本就是标准的固件。如果全是0xFF或0x00,那可能是加密了,或者你读错了地址。
注意:有些厂商会把向量表偏移,比如放在0x08002000。这时候你需要查芯片手册,或者用Ghidra的“Auto Analyze”手动指定基址。
2.4 固件逆向核心流程:一张图说清楚
我把整个流程画成了一张SVG图。你跟着这个顺序走,基本不会迷路。
2.5 实战:用Ghidra打开一个固件
说一千道一万,不如动手做一次。我拿一个常见的STM32固件举例。
- 打开Ghidra,新建项目,导入你的.bin文件。
- 选择语言:ARM Cortex-M小端(v7或v8,看你芯片)。
- 设置基址:比如0x08000000。如果不知道,看向量表第一个值。
- 自动分析:Ghidra会反汇编、识别函数、建交叉引用。
- 找main函数:搜索字符串“main”或看复位向量指向的地址。
小技巧:Ghidra里按
G跳转到复位向量地址,然后按F创建函数。如果反汇编出来全是“undefined”,说明基址设错了。我刚开始用Ghidra时,经常犯这个错。
分析过程中,重点关注几个地方:
- 字符串引用:比如“password”、“admin”、“key”。
- 外设寄存器访问:比如0x40000000附近的地址,那是GPIO/UART/SPI。
- 系统调用:比如SVC指令,可能触发RTOS上下文切换。
嗯,到这里,你已经能独立分析一个固件了。剩下的就是耐心和细心。逆向工程没有捷径,但有了正确的工具和流程,你至少不会在第一步就卡住。