固件逆向分析基础:二进制文件格式解析与反汇编工具链入门

各位同学,欢迎来到第二章。上一章我们聊了固件安全审计的整体框架,今天要扎进去的是逆向分析的基础——说白了,就是怎么跟二进制文件打交道。

我刚开始做固件安全那会儿,拿到一个.bin文件就头大。后来发现,只要搞懂了文件格式、会用反汇编工具、会解包打包,大部分固件在你面前就是透明的。嗯,咱们一步步来。

2.1 二进制文件格式解析:ELF / PE / BIN

固件逆向的第一步,是搞清楚你手里拿的是什么格式的文件。常见的就三种:ELF、PE、以及裸二进制BIN。

2.1.1 ELF(Executable and Linkable Format)

Linux和大多数嵌入式系统(比如VxWorks、uClinux)都用ELF。它结构清晰,分段明确。

我个人习惯,拿到ELF文件先看它的段表(Section Header Table)和程序头(Program Header)。段表告诉你代码、数据、符号表在哪;程序头告诉系统怎么加载。

段名 作用 逆向关注点
.text 可执行代码 主要分析目标,包含固件逻辑
.rodata 只读数据(字符串、常量) 硬编码密码、URL、密钥线索
.data 已初始化全局变量 配置参数、状态标志
.bss 未初始化全局变量 运行时分配,文件里不占空间
.symtab 符号表 函数名、变量名——调试信息没strip的话,逆向难度直接降一半
小技巧: 用 readelf -S firmware.elf 可以快速列出所有段。如果厂商没strip符号表,你甚至能看到函数名叫“check_password”——这基本等于把漏洞送给你了。

2.1.2 PE(Portable Executable)

PE是Windows和某些UEFI固件的标准格式。结构比ELF复杂一点,多了个DOS头、NT头、节表。

我记得有一次审计一个UEFI固件,厂商把关键配置放在PE文件的.rsrc节里。用Resource Hacker一翻,直接找到了硬编码的后门账号。嗯,这种低级错误在IoT设备里真不少见。

PE文件的关键节:

  • .text — 代码段,跟ELF一样
  • .rdata — 只读数据,导入表(IDT)也在这
  • .data — 读写数据
  • .rsrc — 资源(图标、字符串、配置)
  • .reloc — 重定位表,基址随机化时用

2.1.3 裸二进制(BIN / Raw Binary)

这是最头疼的格式——没有头、没有段表、没有符号。说白了就是一段内存转储,从某个起始地址开始直接放代码和数据。

为什么会有这种格式?很多MCU(比如STM32、ESP32)的固件就是直接从Flash地址0x08000000开始执行,不需要文件系统来解析。

注意: 分析裸BIN文件时,你必须先确定加载基址。基址错了,反汇编出来的代码全是乱的。我见过有人对着一个BIN文件反汇编了三天,最后发现基址设错了——全白干。

怎么猜基址?看中断向量表。ARM Cortex-M的固件,地址0x00000000或0x08000000处放的是栈指针,0x00000004处是复位向量。如果看到这两个值合理,基址就对了。

2.2 反汇编工具链入门:Ghidra vs IDA Pro

工具是手的延伸。我个人两个都用,但场景不同。

2.2.1 Ghidra——开源、免费、团队协作

NSA开源的Ghidra,这几年火得不行。它最大的优势是:免费、支持插件、有协作功能。

我建议初学者从Ghidra入手。原因很简单——不用破解,随便装。而且它的反编译引擎(Decompiler)质量很高,能把汇编转成伪C代码,阅读起来舒服很多。

基本操作流程:

  1. 创建项目(Project)→ 导入固件文件
  2. 自动分析(Auto-Analyze)→ 识别指令集、段、函数
  3. 手动修正基址(如果导入的是BIN文件)
  4. 反编译 → 看伪C代码
  5. 重命名函数/变量 → 标注注释

Ghidra的杀手锏: 它的“版本跟踪”(Version Tracking)功能,可以对比两个固件版本之间的差异。我在挖漏洞时经常用这个——厂商修了一个漏洞,但没修干净,通过对比就能发现。

2.2.2 IDA Pro——老牌、强大、但贵

IDA Pro是行业标杆。它的交互式反汇编、F5反编译、脚本支持(IDAPython)都是顶级的。

但说实话,价格劝退了很多人。个人版也要上千美元。不过如果你做商业审计,公司一般会买。

IDA Pro比Ghidra强在哪?

  • 指令集支持更全 — 冷门MCU(比如Renesas RL78、TI MSP430)的插件更多
  • 反汇编精度更高 — 对混淆代码、花指令的处理更成熟
  • 调试器集成 — 可以动态调试,Ghidra的调试器还在完善中

我个人习惯:日常分析用Ghidra,遇到混淆严重的代码或者需要动态调试时,切到IDA Pro。

2.2.3 工具对比

特性 Ghidra IDA Pro
价格 免费 商业授权(贵)
反编译质量 优秀(伪C) 优秀(F5)
指令集支持 ARM/x86/MIPS等主流 几乎全覆盖
脚本语言 Python / Java IDAPython / C++
协作功能 内置(多人同时分析) 需插件
调试器 基础 成熟

2.3 固件解包与打包技术

拿到固件文件,第一件事不是反汇编,而是解包。因为固件通常是一个大包,里面塞了Bootloader、内核、文件系统、配置分区等等。

我曾经遇到一个路由器固件,厂商把文件系统用LZMA压缩了三层,每层还加了自定义魔数。解了三天才解开——但解开之后发现漏洞就在第一层配置里。你说气不气人?

2.3.1 常见固件打包格式

  • SquashFS — Linux嵌入式最常用,只读压缩文件系统
  • CramFS — 老牌,现在用得少了
  • JFFS2 / UBIFS — 针对NAND Flash的读写文件系统
  • TRX / BIN — 路由器固件常见,带头部校验
  • U-Boot Image (uImage) — U-Boot引导的内核镜像

2.3.2 解包工具链

我常用的工具:

  • binwalk — 神器,自动扫描固件中的文件系统、压缩数据、头部特征
  • unsquashfs — 解压SquashFS
  • jefferson — 解压JFFS2
  • dd + 手动偏移 — 当自动工具失效时,手工切割
实战步骤:
binwalk -Me firmware.bin — 自动扫描并递归解包
如果binwalk没识别出来,用 binwalk -R "\x00\x00\x00\x00" firmware.bin 手动搜索魔数。

2.3.3 打包——修改后怎么封回去

解包容易,打包难。很多固件有校验和签名,你改了内容就启动不了。

打包的基本思路:

  1. 用 mksquashfs 重新打包文件系统
  2. 用原始固件的头部模板,替换掉文件系统部分
  3. 重新计算校验和(CRC32 / SHA256)
  4. 如果固件有数字签名——嗯,那就得走漏洞利用路线了,后面章节会讲
警告: 修改固件后如果校验失败,设备可能变砖。我建议先在模拟器(QEMU)里测试修改后的固件,再刷到真机上。

2.4 本章知识体系

下面这张图总结了本章的核心逻辑——从拿到固件到开始逆向分析的完整流程。

固件逆向分析基础流程 文件格式识别 ELF / PE / BIN 固件解包 binwalk / unsquashfs 反汇编分析 Ghidra / IDA Pro 查看段表/程序头 确定代码/数据位置 识别加载基址 提取文件系统 SquashFS / JFFS2 配置分区提取 反编译/伪C代码 函数识别与重命名 交叉引用分析 逆向分析输出 漏洞点定位 | 硬编码凭证 | 后门函数 | 协议逆向 修改 → 重新打包 → 校验修复 mksquashfs / CRC重算 / 签名绕过 ⚠ 注意 先模拟再刷机 💡 提示 保留原始备份

这张图把今天的知识点串起来了。你拿到一个固件,先识别格式,再解包,然后反汇编分析,最后定位漏洞并尝试修改打包。每一步都有对应的工具和方法。