第二章 固件逆向工程基础:二进制分析工具链、固件提取技术、固件解包与打包

各位好,欢迎来到固件逆向工程的基础章节。说实话,这一章是整个课程里最“硬核”的部分之一。你可能会问:为什么要把逆向工程放在这么靠前的位置?

我的回答很简单:没有逆向能力,固件安全审计就是纸上谈兵。你拿到的可能是一个加密的.bin文件,也可能是一块焊死的Flash芯片。怎么把它变成可读的代码?怎么找到漏洞入口?这些都得靠逆向工程。

我个人习惯把固件逆向分成三个层次:工具链准备 → 固件提取 → 解包与打包。下面我们一层层拆开讲。

核心观点:固件逆向不是“破解”,而是“理解”。你只有理解了固件的结构,才能发现其中的安全缺陷。

固件逆向工程知识体系 固件逆向工程知识体系 固件逆向工程 二进制分析工具链 固件提取技术 固件解包与打包 反汇编器 十六进制编辑器 调试器 硬件提取 软件提取 网络提取 文件系统识别 解包工具 重打包 ⚠ 核心原则:先识别 → 再提取 → 后分析 每一步都依赖上一步的结果,顺序不能乱

2.1 二进制分析工具链

做固件逆向,工具就是你的武器。我见过不少新手,上来就开IDA Pro,结果面对一堆裸二进制数据完全懵了。为什么?因为选错工具比没有工具更可怕。

下面这张表是我个人常用的工具清单,按使用场景分类:

工具类别 推荐工具 主要用途 我的评价
反汇编器 Ghidra / IDA Pro / Radare2 将机器码转为汇编代码,支持交叉引用分析 Ghidra免费且强大,IDA Pro插件生态好
十六进制编辑器 010 Editor / HxD / ImHex 查看和编辑原始二进制数据,识别文件结构 010 Editor的模板功能是神器
调试器 GDB / OpenOCD / JTAG调试器 动态分析固件运行时的行为 硬件调试器配合GDB效果最佳
字符串提取 strings / binwalk / foremost 从固件中提取可读字符串和文件碎片 binwalk是固件分析的瑞士军刀
二进制差异 bindiff / diaphora 对比不同版本固件的差异,定位补丁位置 漏洞挖掘时经常用到

我的小技巧:别只依赖一个工具。我习惯先用 binwalk 做快速扫描,再用 Ghidra 做深度分析。两个工具互相验证,能避免很多误判。

举个例子,你拿到一个路由器固件,先用 strings 跑一遍:

strings firmware.bin | grep -i "password\|admin\|root\|debug"

如果看到硬编码的凭据,恭喜你,第一个漏洞已经到手了。但更多时候,你需要把固件加载到反汇编器里,分析函数调用关系。

我记得有一次审计一个IoT摄像头固件,用 binwalk 扫描后发现有LZMA压缩段。手动解压后,再用 Ghidra 分析,发现了一个未授权的远程命令执行漏洞。整个过程,工具链的配合是关键。

2.2 固件提取技术

固件提取,说白了就是把固件从设备里“拿”出来。这步做不好,后面全是白费。

提取方式分三种:硬件提取、软件提取、网络提取。我按难度从低到高给你排个序:

  1. 网络提取:通过设备的Web管理界面、FTP、TFTP等网络服务下载固件。最简单,但厂商通常不会把完整固件放在这里。
  2. 软件提取:通过设备的命令行接口(CLI)或调试串口,使用 cat、dd 等命令读取Flash分区。需要你有设备的管理员权限。
  3. 硬件提取:直接焊接飞线到Flash芯片的引脚,用编程器或SPI读卡器读取。最麻烦,但最可靠。

⚠ 警告:硬件提取有风险!我曾经有一次焊接SPI Flash时,不小心把引脚焊短路了,芯片直接冒烟。建议新手先用烧录座练习,别直接焊板子。

硬件提取的典型流程是这样的:

  1. 拆开设备外壳,找到Flash芯片(通常是SOIC-8封装)。
  2. 用逻辑分析仪确认芯片的供电、地、CLK、MOSI、MISO引脚。
  3. 焊接飞线或使用烧录夹,连接到编程器(如CH341A、FT2232H)。
  4. 使用 flashrom 或厂商软件读取整个Flash内容。

命令示例(使用 flashrom):

# 检测Flash芯片
flashrom -p ch341a_spi -V

# 读取固件到文件
flashrom -p ch341a_spi -r firmware_dump.bin

# 验证读取是否完整
flashrom -p ch341a_spi -v firmware_dump.bin

你想想看,如果设备有防读取保护(比如读保护RDP级别),那硬件提取就失效了。这时候需要更高级的手段,比如电压故障注入。嗯,这个我们后面章节再细讲。

2.3 固件解包与打包

拿到固件文件后,下一步就是解包。固件通常不是单一的可执行文件,而是多个组件的集合:Bootloader、内核、文件系统、配置数据、应用程序等。

常见的固件结构如下:

组件 常见格式 说明
Bootloader U-Boot、RedBoot、Barebox 引导加载程序,负责初始化硬件并加载内核
内核 zImage、uImage、vmlinux Linux内核或RTOS内核
文件系统 SquashFS、JFFS2、UBIFS、CramFS 存放应用程序、配置文件和库文件
配置分区 MTD分区、NVRAM、U-Boot环境变量 存储设备配置参数

解包的第一步是识别文件系统类型。我一般用 binwalk 做自动识别:

binwalk -Me firmware.bin

这个命令会递归扫描并提取所有已知类型的文件。如果 binwalk 识别不出来,那就得手动分析了。用 hexdump 查看文件头:

hexdump -C firmware.bin | head -50

常见的文件系统魔数:

  • SquashFS: 以 hsqs 开头(0x68737173)
  • JFFS2: 以 0x1985 开头
  • CramFS: 以 0x28cd3d45 开头
  • UBIFS: 以 0x31181006 开头

避坑指南:我曾经遇到一个固件,binwalk 识别出了SquashFS,但解包后文件全是乱码。后来发现厂商在文件系统前加了自定义头部偏移。用 dd 跳过前512字节后,才正常解包。

手动解包SquashFS的命令:

# 假设SquashFS从偏移0x100000开始
dd if=firmware.bin of=squashfs_part.bin bs=1 skip=$((0x100000))

# 解包
unsquashfs squashfs_part.bin

打包则是解包的逆过程。修改完固件后,需要重新打包成原始格式。注意:很多固件有校验机制,比如CRC32、SHA256或数字签名。如果你修改了内容但没有更新校验值,设备会拒绝启动。

我一般用 firmware-mod-kit 这个工具集来做解包和打包,它封装了大部分常见文件系统的操作:

# 解包
./extract-firmware.sh firmware.bin

# 修改文件系统内容后,重新打包
./build-firmware.sh firmware_new.bin

但要注意,firmware-mod-kit 对某些定制固件可能不兼容。这时候就得手动分析固件结构,写Python脚本处理了。

核心原则:解包容易,打包难。打包时一定要保留原始的对齐方式和填充字节,否则固件可能变砖。