3、固件获取与提取:硬件提取方法、软件提取方法、固件加密与解密初步

好,咱们进入正题。固件逆向分析的第一步是什么?说白了,你得先拿到固件本身。没有固件,后面所有的分析都是空谈。

我见过不少新手,一上来就想着怎么反汇编、怎么找漏洞,结果连固件都读不出来,卡在第一关。这一章,我就把固件获取的几种主流方法掰开揉碎了讲清楚。硬件怎么提、软件怎么提、遇到加密怎么办,咱们一条条过。

3.1 硬件提取方法

硬件提取,就是直接跟芯片的物理引脚打交道。这活儿需要点耐心,也得有趁手的工具。我个人习惯,能上夹子就不动烙铁,能读 SPI 就不碰 JTAG,因为风险是递增的。

3.1.1 SPI Flash 夹子

这是最常用、也最温和的方法。大多数嵌入式系统的固件都存放在 SPI Flash 芯片里,比如 Winbond、Macronix、GigaDevice 这些厂家的。只要你的板子给 Flash 供电,用夹子夹住芯片引脚,就能通过编程器把内容读出来。

我的经验: 夹子虽然方便,但容易接触不良。我建议你在夹之前,先用万用表测一下夹子两端对应的引脚是否导通。另外,如果板子上的 Flash 是贴片封装(比如 SOP-8),夹子还算好用;要是遇到 BGA 封装的,那就只能上热风枪了。

具体步骤大致如下:

  1. 识别 Flash 型号: 看芯片表面的丝印,记下完整型号。
  2. 连接编程器: 用夹子夹住 Flash,另一端连到编程器(如 CH341A、TL866)。注意方向,别夹反了。
  3. 上电读取: 给板子通电,然后用编程器软件读取整个 Flash 内容。保存为 .bin 文件。
注意: 有些板子在读取 Flash 时,如果主控芯片也在运行,可能会干扰 SPI 总线。我曾经遇到过读出来的数据全是 0xFF,后来把主控的复位引脚拉低,让主控停止工作,才顺利读出。所以,如果读出来不对,试试把板子置于复位状态。

3.1.2 JTAG/SWD 调试接口

如果固件不是存在外部 Flash,而是存在芯片内部的 Flash(比如 STM32、NXP 的 MCU),那 SPI 夹子就派不上用场了。这时候,你需要通过调试接口来读取。

JTAG 和 SWD 是两种常见的调试协议。SWD 是 ARM 公司搞的简化版,只需要两根线(SWDIO 和 SWCLK),比 JTAG 的 5 根线少,用起来更方便。

接口类型 所需引脚数 速度 适用场景
JTAG 5 (TMS, TCK, TDI, TDO, nTRST) 较快 复杂芯片(如 FPGA、高端 MCU)
SWD 2 (SWDIO, SWCLK) 快 ARM Cortex-M 系列 MCU

用调试器(如 J-Link、ST-Link)连接上目标板后,可以通过工具直接读取芯片内部的 Flash。比如用 J-Link 的命令行:

JLinkExe
connect
savebin C:\firmware.bin 0x08000000 0x10000
exit

这条命令的意思是从地址 0x08000000 开始,读取 0x10000(64KB)的数据,保存为 firmware.bin。

关键点: 很多芯片出厂时,调试接口是被锁死的(读保护)。你需要先解除读保护,才能读取固件。解除读保护通常会擦除整个 Flash,所以别指望能完整提取。这是芯片厂商防止固件被读走的手段。

3.1.3 芯片开盖

这是最后的手段,也是破坏性最大的方法。当 Flash 芯片是 BGA 封装,或者固件被封装在芯片内部(比如智能卡、安全芯片),你只能物理破坏芯片,用显微镜和探针台来读取。

具体做法是用浓硝酸腐蚀掉芯片的封装,露出晶圆,然后用探针直接接触存储单元。这活儿需要专业设备,而且成功率不高。我本人没干过几次,成本太高,一般公司也玩不起。

3.2 软件提取方法

硬件方法虽然直接,但有时候不方便。比如板子已经装在产品里了,拆开很麻烦。这时候,软件方法就派上用场了。

3.2.1 通过 Bootloader 提取

很多嵌入式系统都有 Bootloader,负责启动和固件更新。如果 Bootloader 提供了读取 Flash 的命令,那就省事了。

比如 U-Boot,这是 Linux 嵌入式系统里最常见的 Bootloader。进入 U-Boot 命令行后,可以用以下命令把固件读出来:

sf probe 0
sf read 0x82000000 0x0 0x100000
tftp 0x82000000 firmware.bin

这段代码的意思是:初始化 SPI Flash,从地址 0 开始读 1MB 数据到内存 0x82000000,然后通过 TFTP 传到电脑上。

避坑指南: 我曾经遇到过一台设备,Bootloader 有密码保护。试了默认密码(admin、root、123456)都不行。后来我通过串口抓到了它启动时的日志,发现密码是硬编码在 Bootloader 里的。所以,多观察启动信息,有时候能捡到漏。

3.2.2 通过系统命令提取

如果设备已经跑起了 Linux 或 RTOS,而且你能拿到 shell(比如通过 SSH、Telnet、串口),那提取固件就简单了。

常用的命令:

  • cat /dev/mtdblock0 > /tmp/firmware.bin —— 读取 MTD 设备(Flash 分区)。
  • dd if=/dev/mmcblk0 of=/tmp/firmware.bin bs=1024 count=4096 —— 读取 SD 卡或 eMMC 的前 4MB。
  • scp /tmp/firmware.bin user@your-pc:/home/user/ —— 把文件传到电脑。

这里有个前提:你得有 root 权限。如果设备限制了权限,你可能需要先提权。

3.2.3 通过 OTA 抓包

如果设备支持 OTA(Over-The-Air)升级,那固件肯定会在网络上传输。你只需要在设备和服务器之间抓个包,就能拿到固件。

常用的抓包工具:

  • Wireshark: 抓取 HTTP/HTTPS 流量。如果是 HTTP,直接就能看到固件 URL;如果是 HTTPS,需要中间人攻击(MITM)。
  • Burp Suite: 专门用来抓取和修改 HTTP/HTTPS 请求。设置好代理,让设备的流量经过你的电脑。
  • tcpdump: 在路由器或设备本身上抓包,适合没有图形界面的环境。
注意: 很多厂商会对 OTA 固件进行加密或签名。你抓到的可能是一堆乱码,或者是一个加密后的 .enc 文件。这时候,你就需要进入下一节的内容了。

3.3 固件加密与解密初步

拿到固件文件后,别急着高兴。先看看它是不是加密的。怎么判断?

  • 看文件头: 正常的固件文件头通常是 0x00 0x00 0x00 0x00 或者 0xFF 0xFF 0xFF 0xFF,或者有特定的魔数(如 0xFE 0xED 0xBA 0xAD)。如果文件头看起来像随机数据,那很可能是加密的。
  • 看熵值: 用工具(如 binwalk -E)计算文件的熵。如果熵值接近 1.0(完全随机),那基本就是加密了。

常见的加密方式:

  • XOR 加密: 最简单的加密,用固定密钥对每个字节进行异或。破解也简单,找一段已知明文(比如固件里的字符串),就能反推出密钥。
  • AES 加密: 对称加密,密钥通常存储在芯片内部或 Bootloader 里。你需要从硬件或软件中找到密钥。
  • RSA 签名: 不是加密,而是签名。固件本身是明文的,但附带了签名,用于验证完整性。你可以去掉签名,直接分析固件。
我的建议: 遇到加密固件,先别急着硬解。先找找有没有密钥泄露。我曾经在一个设备的配置文件里找到了 AES 密钥,明文写着 "aes_key=1234567890abcdef"。厂商的疏忽,就是我们的机会。

下面这张图,总结了固件获取与提取的完整流程,你可以对照着看:

固件获取与提取流程 固件获取与提取决策流程 拿到目标设备 能否物理接触电路板? 硬件提取 SPI Flash 夹子 JTAG/SWD 调试接口 芯片开盖(破坏性) 软件提取 通过 Bootloader 通过系统命令 通过 OTA 抓包 得到固件 .bin 文件

拿到固件后,下一步就是分析它了。但那是后面章节的事。这一章,你只要记住:能软则软,不能软再硬,硬的不行就开盖。至于加密,别怕,大部分厂商的加密都很弱,或者密钥就藏在某个角落里。