3、固件获取与提取:从Flash芯片读取、从OTA包提取、从JTAG/SWD接口获取、固件加密与解密初步

做固件逆向这么多年,我最大的感触就是:拿不到固件,一切都是空谈。你分析能力再强,工具用得再溜,没有原始二进制数据,那就是巧妇难为无米之炊。

这一章,咱们就聊聊固件到底能从哪儿搞到手。我把它分成四条路:硬啃Flash芯片、拆解OTA升级包、通过调试接口直接捞、以及处理加密固件。每条路都有坑,我踩过的坑不少,今天一并说清楚。

核心观点:固件获取没有万能钥匙。不同场景用不同手段,有时候得组合使用。别指望一招鲜吃遍天。

3.1 从Flash芯片读取固件

这是最直接、最暴力、也最可靠的方法。设备就在你手上,把存储芯片拆下来,用编程器读就是了。

常见Flash芯片类型:

  • SPI Flash: 最常见,8脚或16脚封装。型号如W25Q64、MX25L128等。容量从几MB到几十MB。
  • Parallel NOR Flash: 老设备上多见,引脚多,读取速度慢。现在基本被SPI取代了。
  • NAND Flash: 路由器、摄像头里常见。容量大(128MB起步),但读取需要处理坏块和ECC。
  • eMMC: 高端设备用,比如手机、平板。相当于一个SD卡焊在主板上,读取需要专用座子或飞线。

我的操作流程:

  1. 先拍照: 拆之前,把芯片周围电路拍清楚。别焊下来忘了方向。
  2. 热风枪拆焊: 温度调到320-350℃,风速适中。吹到焊锡融化,用镊子轻轻取下。
  3. 清理焊盘: 用烙铁和吸锡带把残留焊锡清理干净。这一步马虎不得,否则编程器夹不住。
  4. 上编程器: 我常用的是CH341A(便宜够用)和TL866II Plus(稳定可靠)。夹子夹好,软件里选对芯片型号。
  5. 读取并校验: 读完后一定要做校验。我遇到过读出来数据全是0xFF的情况,白忙活半小时。

小技巧: 有些设备把Flash芯片涂了黑胶或者灌了环氧树脂。别硬撬,用热风枪加热到200℃左右,胶会变脆,再用刀片小心剔除。

避坑指南:

  • 我曾经遇到过芯片型号被磨掉的情况。这时候别慌,看电路连接方式:VCC、GND、CS、CLK、MOSI、MISO这六根线,对照常见引脚定义就能猜出来。
  • 有些设备用了加密Flash,比如Atmel的某些型号。读出来的数据是乱码,需要配合MCU的密钥才能解密。这个后面会讲。
  • 焊接温度别太高,超过380℃容易损坏芯片内部电路。我烧坏过一块W25Q128,教训深刻。

3.2 从OTA包提取固件

很多时候你拿不到硬件,或者设备还在正常工作。这时候OTA升级包就是你的突破口。

OTA包长什么样?

说白了,就是一个二进制文件。可能是.bin.img.fw.pkg,甚至没有后缀名。我见过最奇葩的是改名为.jpg的固件包,藏在服务器上。

提取步骤:

  1. 抓包: 用Burp Suite或Fiddler拦截设备升级请求。注意看URL和POST数据。
  2. 下载: 拿到下载链接后,用wget或curl下载到本地。
  3. 分析文件头:hexdumpbinwalk查看前几个字节。常见魔数:
    • 1F 8B → gzip压缩
    • 50 4B 03 04 → ZIP压缩
    • 7F 45 4C 46 → ELF文件
    • U-Boot → U-Boot镜像
  4. 解包:binwalk -e自动提取。如果不行,手动用dd命令切割。

实战案例: 我分析过一个智能摄像头的OTA包。用binwalk扫描,发现里面嵌入了三个文件系统:一个squashfs(主系统)、一个jffs2(配置分区)、还有一个加密的ubifs(用户数据)。每个都要单独处理。

常见加密方式:

加密类型 特征 破解思路
XOR简单加密 数据看起来有规律,比如每隔几个字节重复 用已知明文攻击,或者暴力枚举密钥
AES-ECB/CBC 数据随机分布,无规律 需要找到密钥,通常在固件其他位置硬编码
RSA签名+明文 头部有签名,但数据本身未加密 跳过签名验证,直接提取数据
自定义算法 完全看不懂,没有标准特征 逆向升级程序,找到解密函数

注意: 有些厂商会在OTA包头部加入版本号、校验和、设备ID等信息。别把这些当成加密数据。我见过有人对着版本号字符串分析了一整天,结果发现那只是ASCII文本。

3.3 从JTAG/SWD接口获取

这个方法比较高级,需要硬件调试器。但好处是:不需要拆Flash芯片,直接从MCU内存里读

JTAG vs SWD:

  • JTAG: 5线(TMS、TCK、TDI、TDO、TRST)。支持所有ARM芯片,速度较慢。
  • SWD: 2线(SWDIO、SWCLK)。Cortex-M系列专用,速度快,引脚少。

我的常用工具:

  • J-Link: 最稳定,支持芯片多。就是贵了点。
  • ST-Link: STM32专用,便宜好用。
  • OpenOCD + FT232H: 开源方案,适合折腾。

操作步骤:

  1. 找接口: 主板上找4-5个连在一起的过孔,或者一个10针/20针的排针。用万用表量一下:VCC、GND、SWDIO、SWCLK。
  2. 连接: 用杜邦线或探针连接调试器。注意电平匹配,3.3V设备别接到5V上。
  3. 识别芯片: 运行JLinkExe或OpenOCD,输入connect命令。如果能识别出芯片型号,恭喜你,有戏。
  4. 读取内存:savebin命令把Flash区域全部读出来。比如savebin firmware.bin 0x08000000 0x100000

小技巧: 如果芯片有读保护(RDP),JTAG/SWD接口会被禁用。这时候需要想办法绕过:比如利用Bootloader漏洞、或者用电压故障注入。这个后面章节会详细讲。

避坑指南:

  • 我曾经遇到过SWD接口被复用为GPIO的情况。这时候需要在上电瞬间快速连接,或者按住复位键再连接。
  • 有些芯片的调试接口需要特定时序才能激活。比如某些NXP的芯片,需要在复位期间给特定引脚加高电平。
  • 连接线别太长,超过20cm容易信号失真。我一般控制在10cm以内。

3.4 固件加密与解密初步

拿到固件后,发现全是乱码?别急着扔。先判断是不是加密了。

如何判断固件是否加密?

  • 熵值分析:binwalk -E查看熵值。如果整个固件熵值接近1.0(完全随机),大概率是加密了。
  • 文件头缺失: 没有常见的魔数,也没有文件系统签名。
  • 重复模式: 如果看到大量重复字节(比如0x00、0xFF),那可能是未加密区域,或者加密算法有漏洞。

常见解密思路:

  1. 找密钥: 密钥通常硬编码在Bootloader或升级程序中。用strings命令搜索,或者反汇编找AES_KEYSECRET等字符串。
  2. 逆向解密函数: 在升级程序里找到解密函数,用IDA或Ghidra分析。复制算法逻辑,用Python实现。
  3. 已知明文攻击: 如果你知道固件里某段数据的内容(比如版本号字符串),可以用XOR推导出密钥。
  4. 侧信道攻击: 高级玩法,通过功耗或电磁辐射分析破解密钥。这个我还在学习中,暂时不展开。

实战案例: 我分析过一个路由器固件,发现它用AES-128-CBC加密。密钥藏在Bootloader的字符串表里,偏移量是0x1A3F。用Python写了个脚本,几秒钟就解密了。

解密示例代码(Python):

from Crypto.Cipher import AES
import binascii

# 假设密钥和IV从固件中提取
key = binascii.unhexlify('2B7E151628AED2A6ABF7158809CF4F3C')
iv = binascii.unhexlify('000102030405060708090A0B0C0D0E0F')

# 读取加密固件
with open('encrypted_firmware.bin', 'rb') as f:
    ciphertext = f.read()

# 解密
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)

# 去除PKCS7填充
pad_len = plaintext[-1]
plaintext = plaintext[:-pad_len]

# 保存
with open('decrypted_firmware.bin', 'wb') as f:
    f.write(plaintext)

print("解密完成!")

注意: 有些固件用了多重加密。比如先XOR再AES,或者分段加密。别以为一次解密就完事了。我遇到过三层加密的固件,解了一层还有一层。

好了,固件获取和提取的基本套路就这些。说白了,就是硬拆、软抓、调试口捞、加密破。每个方法都有适用场景,也有坑。我个人建议:先从OTA包入手,不行再拆Flash,最后才考虑JTAG。因为OTA包最容易获取,风险也最低。

嗯,这一章就到这里。记住,拿到固件只是第一步,后面还有更精彩的分析等着你。


公众号:蓝海资料掘金营,微信deep3321