3. 固件逆向工程基础:固件结构解析、文件系统提取、二进制分析工具链
各位同学,今天咱们聊聊固件逆向工程。说实话,这是固件安全测试里最硬核的一环。你拿到一个黑盒设备,没有源码,没有文档,只有一块Flash芯片或者一个.bin文件。怎么下手?
我刚开始做这行的时候,也犯过傻——对着二进制文件用十六进制编辑器硬看,看了三天,眼睛都快瞎了。后来才明白,逆向工程不是靠肉眼,而是靠工具和方法论。今天我就把这几年的经验梳理一下,希望能帮你少走弯路。
3.1 固件结构解析:先搞清楚它长什么样
拿到一个固件文件,第一步不是反汇编,而是先看结构。固件通常不是单一的可执行文件,而是多个组件的拼接体。我习惯用以下步骤来拆解:
- 文件头识别:用
file命令看看它是什么类型。很多固件其实是压缩包或者文件系统镜像。 - 熵分析:计算文件的熵值。高熵区域通常是加密或压缩数据,低熵区域可能是代码或明文配置。
- 字符串提取:用
strings命令捞一下,看看有没有文件路径、版本号、调试信息。这些往往是突破口。 - 偏移量定位:通过已知的魔数(Magic Number)来定位文件系统或内核镜像的起始位置。
常见固件结构示例:
+------------------+
| Bootloader | (U-Boot, RedBoot...)
+------------------+
| Kernel Image | (zImage, uImage...)
+------------------+
| Root Filesystem | (SquashFS, JFFS2, YAFFS...)
+------------------+
| Application Data | (配置文件、Web界面资源...)
+------------------+
嗯,这里要注意:有些厂商会把多个分区打包成一个文件,中间用填充字节对齐。我曾经遇到过一个固件,文件系统藏在偏移量0x100000之后,前面全是无用的填充数据。如果你不分析结构,直接反汇编,那可就白费功夫了。
3.2 文件系统提取:把固件“解压”出来
固件里最值钱的东西,往往藏在文件系统里。Web界面、配置文件、私钥、甚至硬编码的密码,都在这里。提取文件系统,我首推binwalk。
3.2.1 binwalk 实战
binwalk 是个神器。它能自动扫描固件中的文件签名,然后帮你提取出来。用法很简单:
# 扫描固件中的文件签名
binwalk firmware.bin
# 递归提取所有文件
binwalk -Me firmware.bin
输出结果会告诉你:偏移量0x123456处发现SquashFS文件系统,偏移量0x789ABC处发现LZMA压缩数据。然后binwalk会自动把它们解压到当前目录。
个人经验: 我建议你加上-Me参数,它会递归提取。有些固件是“套娃”结构——先压缩,再打包,再加密。binwalk能一层层剥开,直到露出真面目。
不过,binwalk也不是万能的。有些厂商会自定义文件系统魔数,或者用非标准压缩算法。这时候就需要手动分析了。我曾经遇到过一个固件,文件系统是定制的,binwalk识别不出来。我只好用dd命令按偏移量切出来,然后用unsquashfs强制解压。折腾了两天,最后发现厂商只是把魔数从hsqs改成了HSQS。你说气不气人?
3.2.2 常见文件系统类型
| 文件系统类型 | 魔数 | 提取工具 | 特点 |
|---|---|---|---|
| SquashFS | hsqs |
unsquashfs |
只读压缩,最常见 |
| JFFS2 | 0x1985 |
jefferson |
日志型,用于NAND Flash |
| YAFFS2 | 0x0001 |
unyaffs |
专为NAND设计 |
| CPIO | 070701 |
cpio -idmv |
initramfs常用 |
| CramFS | 0x28CD3D45 |
cramfsck |
老式嵌入式系统 |
避坑指南: 我曾经在提取一个JFFS2文件系统时,直接用了mount -t jffs2,结果系统崩溃了。后来才发现,JFFS2需要MTD设备支持,不能直接挂载普通文件。正确的做法是用jefferson工具解压到目录。
3.3 二进制分析工具链:三剑客
文件系统提取出来后,你就能看到固件里的所有文件了。接下来要分析的是核心二进制文件——通常是/bin/busybox、/usr/sbin/httpd、或者厂商自己的守护进程。这时候就需要反汇编工具了。
我个人习惯用三款工具:binwalk(前面说了)、Ghidra、IDA Pro。它们各有千秋,我分别说说。
3.3.1 Ghidra:免费且强大
Ghidra是NSA开源的逆向工具。说实话,刚出来的时候我还不信它能比IDA强。用了一段时间后,我发现它有几个优点:
- 免费:不用破解,不用找License。
- 协作功能:团队可以同时分析同一个二进制文件。
- 脚本支持:Python和Java都能写插件。
- 反编译质量:对于ARM/MIPS架构,反编译出来的C代码可读性很高。
用法也很简单:
# 启动Ghidra(需要Java 11+)
./ghidraRun
# 创建新项目 -> 导入二进制文件 -> 自动分析 -> 开始逆向
Ghidra的自动分析功能很强大。它会自动识别函数、变量、字符串引用,甚至能帮你重命名函数。不过,自动分析也不是完美的。我遇到过它把数据段误识别为代码段的情况,导致反编译结果乱七八糟。这时候就需要手动调整了。
3.3.2 IDA Pro:老牌王者
IDA Pro是商业软件,价格不菲。但它的反汇编引擎和插件生态确实无人能及。如果你做固件安全测试是职业的,我建议还是备一份。
IDA Pro的几个核心功能:
- F5反编译:一键生成伪C代码,比看汇编快10倍。
- 交叉引用:快速定位函数调用关系。
- Hex-Rays插件:支持ARM、MIPS、PowerPC等嵌入式架构。
- 调试器:可以远程调试目标设备。
我的建议: 如果你只是偶尔分析固件,用Ghidra就够了。如果你天天和二进制打交道,IDA Pro的投资是值得的。我自己是两台电脑都装——主力用IDA,备用用Ghidra。
3.3.3 其他辅助工具
除了三剑客,还有一些小工具也很有用:
- objdump:快速查看二进制文件的段信息、符号表。
- readelf:分析ELF文件结构。
- strace:跟踪程序运行时的系统调用。
- ltrace:跟踪库函数调用。
3.4 关键函数定位:找到“命门”
逆向工程的最终目的,是找到关键函数。比如:
- 认证函数(检查用户名密码的地方)
- 命令执行函数(
system()、popen()) - 网络处理函数(
recv()、send()) - 加密解密函数(
aes_encrypt()、rsa_sign())
怎么快速定位?我总结了几个方法:
- 字符串搜索:在反汇编工具里搜索"password"、"admin"、"login"、"error"等关键词。找到引用这些字符串的代码,往往就是关键函数。
- API交叉引用:搜索
system、execve、strcmp等库函数,看谁调用了它们。 - 网络端口分析:如果固件里有Web服务器,搜索
httpd或lighttpd相关的字符串。 - 调试信息:有些固件编译时没去掉符号表,直接用
nm命令就能看到函数名。
实战技巧: 我经常用Ghidra的“Symbol Tree”功能,先看导入函数表。如果看到system、popen、exec这些危险函数,直接双击进去,看谁调用了它们。十有八九能找到命令注入漏洞。
举个例子。有一次我分析一个路由器固件,搜索"password"字符串,发现它被一个叫check_auth的函数引用。反编译后发现,这个函数只是简单比较了输入字符串和硬编码的密码。密码是"admin123"。嗯,这就是典型的后门。
3.5 知识体系总览
说了这么多,我画了一张图来总结本章的核心逻辑。你看一眼就能明白固件逆向工程的完整流程:
你看,整个流程是线性的:从拿到固件开始,一步步拆解,最后找到漏洞。每一步都有对应的工具和方法。说白了,逆向工程就是一场“拼图游戏”——你手里的碎片越多,越容易看清全貌。
好了,这一章的内容就到这里。记住:工具只是手段,思路才是核心。下次你拿到一个固件,别急着双击打开,先想想它是什么结构,用什么工具,从哪里入手。慢慢来,比较快。
公众号:蓝海资料掘金营,微信deep3321