第三章 固件获取与提取:从Flash芯片到二进制文件
做嵌入式逆向,第一步永远不是反汇编,而是——拿到固件。没有固件,后面全是空谈。
你可能觉得这很简单,不就是把芯片里的东西读出来吗?嗯,我刚开始也这么想。直到有一次,我对着一个加密的Bootloader折腾了整整三天,才发现问题出在读取时序上。所以这一章,咱们把固件获取这件事彻底聊透。
3.1 固件存储在哪里?
绝大多数嵌入式设备的固件,存放在Flash存储器里。常见的有这么几种:
| 存储类型 | 典型芯片 | 接口协议 | 常见容量 |
|---|---|---|---|
| SPI Flash | W25Q64, MX25L128 | SPI | 1MB ~ 64MB |
| Parallel NOR Flash | JS28F128, S29GL256 | 并行总线 | 2MB ~ 32MB |
| NAND Flash | K9F1G08, MT29F2G | NAND接口 | 128MB ~ 8GB |
| 片上Flash (MCU) | STM32F4, LPC1768 | SWD/JTAG | 64KB ~ 2MB |
我个人习惯,拿到设备第一件事就是拆开看主控旁边有没有8脚或16脚的Flash芯片。如果是8脚SPI Flash,那基本就是W25Q系列或者MX25系列,这类芯片用CH341A编程器就能搞定。
3.2 使用编程器直接读取
这是最直接的方法。把Flash芯片焊下来,或者用烧录夹夹住,然后用编程器读。
3.2.1 CH341A编程器读取SPI Flash
CH341A是入门神器,便宜、好用。但要注意,它只支持3.3V的SPI Flash,1.8V的芯片需要转接板。
操作步骤:
- 把Flash芯片放到编程器的锁紧座里,注意1脚对齐。
- 打开软件(比如AsProgrammer或NeoProgrammer)。
- 选择芯片型号,比如W25Q64FV。
- 点击“读取”,等待进度条走完。
- 保存为.bin文件。
3.2.2 J-Link读取MCU内部Flash
如果固件存在MCU内部Flash里,那就得用J-Link或者ST-Link这类调试器了。通过SWD接口,可以直接把整个Flash dump出来。
我常用的命令:
# 连接目标芯片
JLinkExe -device STM32F407VG -if SWD -speed 4000
# 在JLink命令行里执行
connect
savebin firmware_dump.bin 0x08000000 0x100000
exit
这里0x08000000是STM32的Flash起始地址,0x100000是大小(1MB)。不同芯片的起始地址不一样,一定要查手册确认。
3.3 Bootloader提取方法
有些设备,Flash芯片是焊死的,或者有加密保护,没法直接用编程器读。这时候,Bootloader提取法就派上用场了。
说白了,就是利用设备自带的Bootloader程序,通过串口、USB或网络把固件传出来。
3.3.1 串口Bootloader提取
很多MCU出厂自带Bootloader,比如STM32的系统Bootloader(存在ROM里,不可修改)。通过USART1或USB,可以用官方的工具读取Flash。
操作流程:
- 把BOOT0引脚拉高,BOOT1拉低,复位芯片。
- 芯片进入系统Bootloader模式。
- 用STM32 Flash Loader Demonstrator或STM32CubeProgrammer连接。
- 选择“Read from device”,指定起始地址和长度。
- 保存固件。
核心要点: 系统Bootloader是只读的,不会被用户程序覆盖。所以只要硬件没坏,总能通过这个后门读取固件。但要注意,如果芯片使能了RDP Level 2(永久读保护),那连系统Bootloader也会禁止读取Flash。
3.3.2 自定义Bootloader提取
有些设备厂商会自己写Bootloader,支持固件升级。这种Bootloader通常通过串口或网络接收固件包。我们可以利用它来反向提取。
思路是这样的:
- 分析Bootloader的通信协议(比如XMODEM、YMODEM或自定义协议)。
- 伪造一个“读取固件”的请求。
- 如果Bootloader支持读取命令,直接dump。
- 如果不支持,那就得用更激进的方法——Bootloader漏洞利用。
我在项目中遇到过一台工业路由器,它的Bootloader有个缓冲区溢出漏洞。发送超长的固件包,能把返回地址覆盖成读取Flash的函数地址。嗯,那次我成功dump出了整个固件,但设备也彻底变砖了——因为溢出破坏了内存。所以,这种方法只适合在实验室里玩,别在生产环境试。
3.4 固件提取的完整流程
下面这张图,是我自己总结的固件提取决策流程。每次拿到新设备,我都会按这个思路走一遍。
3.5 常见问题与避坑指南
做固件提取这么多年,我踩过的坑能写满一本笔记本。挑几个典型的说说:
原因:芯片没上电、接触不良、或者芯片已经被擦除。
解决办法:检查供电电压,用万用表测VCC和GND。如果是SPI Flash,检查CS、CLK、MOSI、MISO是否接对。
原因:读取时序不稳定,或者芯片型号选错了。
解决办法:降低SPI时钟频率,比如从20MHz降到4MHz。我遇到过W25Q64和W25Q128引脚兼容但容量不同,选错型号读出来的数据会错位。
原因:RDP Level 1或Level 2保护开启。
解决办法:Level 1可以用全擦除解除(数据会丢)。Level 2是永久保护,无解。所以,拿到设备先检查保护状态,别急着连。
3.6 工具推荐
最后,列一下我常用的工具清单,供你参考:
| 工具 | 用途 | 价格 | 推荐指数 |
|---|---|---|---|
| CH341A编程器 | 读取SPI Flash | ¥20-50 | ⭐⭐⭐⭐⭐ |
| J-Link EDU | 调试/读取MCU Flash | ¥300-400 | ⭐⭐⭐⭐⭐ |
| ST-Link V2 | 调试STM32系列 | ¥20-30 | ⭐⭐⭐⭐ |
| AsProgrammer | CH341A配套软件 | 免费 | ⭐⭐⭐⭐ |
| STM32CubeProgrammer | STM32官方工具 | 免费 | ⭐⭐⭐⭐⭐ |
嗯,工具不在多,顺手就行。我个人最常用的是CH341A+AsProgrammer的组合,便宜、稳定、够用。J-Link则留着对付那些有保护的高端芯片。
这一章的内容就到这里。固件提取是逆向分析的基础,也是门槛。把这一步走稳了,后面的反汇编、漏洞分析才能顺利进行。记住:数据完整性是第一位的,读出来的固件一定要校验,否则分析到一半发现数据是错的,那才叫欲哭无泪。