2. 固件逆向工程基础:二进制分析工具链

说实话,很多刚入行的朋友一拿到固件文件就懵了——一堆十六进制,完全不知道从哪下手。我当年第一次分析路由器固件时也是这样,对着二进制文件发呆。后来慢慢摸索出一套工具链,才算真正入了门。

这一章,我就带你走一遍固件逆向的起步阶段。说白了,就是三件事:看结构、找线索、认文件系统。工具嘛,就是 binwalk、strings、hexdump 这几把“瑞士军刀”。

核心思路:固件逆向不是一上来就反汇编。先做“表面分析”——识别文件类型、提取文件系统、定位关键字符串。这一步做扎实了,后续的深度逆向才能事半功倍。

2.1 固件文件结构初探

一个典型的嵌入式固件,通常包含这些部分:

  • 引导头(Header)——包含魔数、版本、校验和、大小等信息
  • 引导加载程序(Bootloader)——如 U-Boot、RedBoot
  • 内核(Kernel)——通常是压缩过的 Linux 内核
  • 文件系统(Filesystem)——SquashFS、JFFS2、CramFS 等
  • 附加数据——配置分区、校准数据、签名等

我遇到过一台工业网关的固件,厂商把配置分区藏在文件系统后面,用 binwalk 默认扫描根本看不到。后来我手动调整了偏移量才挖出来。嗯,这里要注意:不要完全信任自动化工具的输出。

2.2 binwalk:固件分析的“第一把刀”

binwalk 是我每次分析固件时第一个跑的工具。它能做的事情很多:

  • 扫描固件中的文件签名(魔数)
  • 识别嵌入的文件系统、内核、压缩数据
  • 提取文件系统内容
  • 分析熵值分布

基本用法很简单:

# 扫描固件中的文件签名
binwalk firmware.bin

# 提取所有识别到的文件
binwalk -e firmware.bin

# 只提取特定偏移的文件系统
binwalk -D 'squashfs:rootfs:squashfs' firmware.bin

# 生成熵值图,判断数据是否加密或压缩
binwalk -E firmware.bin

你想想看,为什么 binwalk 能识别这么多东西?因为它内置了一个签名数据库。每个文件格式都有独特的“魔数”——比如 SquashFS 以 hsqs 开头,JFFS2 以 0x1985 开头。binwalk 就是靠这些特征来定位的。

我的习惯:拿到固件后,先跑 binwalk -E 看熵值图。如果整个固件熵值接近 1.0(高熵),说明大概率是加密的。这时候别急着提取文件系统,先找解密密钥或算法。我曾经在一个 IP 摄像头的固件上浪费了两天,后来才发现厂商用了简单的 XOR 加密——熵值图早就告诉我了,只是我没仔细看。

2.3 strings:快速定位关键信息

strings 这个工具,说简单也简单,说强大也强大。它的作用就是从二进制文件中提取可打印的字符串。

# 提取所有长度 >= 4 的字符串
strings firmware.bin

# 指定最小长度,减少噪音
strings -n 8 firmware.bin

# 同时显示偏移地址
strings -t x firmware.bin

# 结合 grep 快速定位
strings firmware.bin | grep -i "admin\|password\|debug\|secret"

我个人习惯在 binwalk 扫描之后,马上跑 strings 看看有没有敏感信息。你猜怎么着?很多厂商会把默认密码、调试接口、甚至私钥直接硬编码在固件里。

注意:strings 只能提取 ASCII 和 Unicode 字符串。如果固件用了 UTF-16 编码的中文,记得加 -e l 参数。另外,压缩或加密过的数据段里,strings 基本是无效的——全是乱码。

2.4 hexdump:手动“摸”固件

hexdump(或 xxd、od)是最后一道防线。当自动化工具不给力时,就得靠它手动分析了。

# 查看文件头部 512 字节
hexdump -C firmware.bin | head -n 32

# 跳过前 0x1000 字节,查看后续内容
hexdump -C -s 0x1000 firmware.bin | head -n 32

# 只查看指定偏移范围
hexdump -C -s 0x20000 -n 256 firmware.bin

为什么要手动看 hexdump?举个例子:有一次我分析一个智能插座固件,binwalk 什么都没扫出来。我手动看头部,发现前 4 个字节是 AB CD 12 34——这不是任何已知文件系统的魔数。后来我查了厂商的 SDK 文档,才知道这是他们自定义的头部格式,魔数后面 4 字节就是实际固件大小。去掉头部后,binwalk 就能正常识别了。

说白了,自动化工具是帮你省时间的,不是替你思考的。

2.5 固件文件系统识别

嵌入式设备常用的文件系统就那么几种。我整理了一个对照表:

文件系统类型 魔数(十六进制) 魔数(ASCII) 特点
SquashFS 68 73 71 73 hsqs 只读压缩,最常见
JFFS2 19 85 不可打印 日志结构,支持磨损均衡
CramFS 45 3D CD 28 不可打印 老式压缩文件系统
UBIFS 31 18 10 06 不可打印 UBI 层之上的文件系统
YAFFS2 03 00 00 00 不可打印 NAND Flash 专用
ROMFS 2D 72 6F 6D -rom 极简只读文件系统

识别文件系统后,下一步就是挂载或解压它。以最常见的 SquashFS 为例:

# 用 binwalk 提取
binwalk -e firmware.bin

# 或者手动解压(需要知道偏移)
unsquashfs -d ./rootfs -o 0x123456 rootfs.img

# 挂载只读查看
mount -t squashfs -o loop,ro rootfs.img /mnt/rootfs

避坑指南:我曾经遇到一个固件,binwalk 识别出 SquashFS 但提取失败。后来发现厂商修改了 SquashFS 的超级块结构,在标准头部前加了 4 字节的自定义字段。解决办法是用 dd 跳过这 4 字节,再喂给 unsquashfs。命令如下:

dd if=firmware.bin of=clean_squashfs.bin bs=1 skip=4
unsquashfs -d ./rootfs clean_squashfs.bin

2.6 综合实战:一个典型固件分析流程

把上面的工具串起来,一个标准的固件初步分析流程是这样的:

  1. 文件信息收集:file firmware.bin 看文件类型,ls -lh 看大小
  2. 熵值分析:binwalk -E firmware.bin 判断是否加密
  3. 签名扫描:binwalk firmware.bin 识别文件系统和内核
  4. 字符串提取:strings -n 8 firmware.bin | grep -i "pass\|admin\|key"
  5. 手动验证:用 hexdump 查看头部和关键偏移
  6. 文件系统提取:binwalk -e firmware.bin 或手动解压
  7. 内容审查:查看提取出的文件系统,寻找配置文件、脚本、二进制程序

这个流程我用了快十年,基本没翻过车。当然,遇到加密固件或自定义格式时,需要额外步骤——那些我们后面章节再聊。

固件初步分析流程 固件文件 ① 文件信息收集 ② 熵值分析 ③ 签名扫描 ④ 字符串提取 ⑤ 手动验证 ⑥ 文件系统提取 ⑦ 内容审查 遇到加密或自定义格式时,需在步骤⑤后增加解密/格式逆向环节

这张图就是我平时做固件初步分析的完整路径。你可能会问:为什么步骤②③④是并行的?因为这三个工具互不依赖,可以同时跑,节省时间。我一般开三个终端窗口,binwalk 扫着,strings 跑着,hexdump 看着——效率最高。

总结一下:binwalk 是“侦察兵”,strings 是“情报员”,hexdump 是“侦察兵”。三者配合,基本能搞定 80% 的固件初步分析。剩下的 20%,要么是加密固件,要么是自定义格式——那些就需要更深入的技术了,我们后面的章节会逐一攻克。