第二章:固件逆向工程基础——二进制分析工具与文件结构解析

各位同学,欢迎来到固件安全审计的第二课。今天咱们聊聊逆向工程最基础的东西——怎么跟一堆二进制数据打交道。

说实话,我刚入行那会儿,面对一个几十兆的.bin文件,真有点无从下手。后来慢慢摸索,发现其实就三板斧:binwalk、strings、hexdump。这三样工具用熟了,大部分固件在你面前就跟透明的一样。

2.1 二进制分析三剑客

2.1.1 binwalk——固件分析的瑞士军刀

binwalk 是我个人最常用的工具,没有之一。它的核心能力就两个:扫描文件签名提取文件系统

为什么会这么强?因为大多数固件其实就是把多个文件打包在一起——比如 bootloader、内核、文件系统、配置数据。binwalk 能根据文件头签名,把这些东西一个个识别出来。

常用命令速查:

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

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

# 递归提取(遇到压缩包自动解压)
binwalk -Me firmware.bin

# 只显示签名信息,不提取
binwalk -I firmware.bin

我在项目中遇到过一台路由器固件,用 binwalk 扫描后发现有 3 个 squashfs 文件系统。当时我就知道——这设备大概率是双分区备份设计。后来验证确实如此。

小技巧:binwalk 的签名库可以自定义。如果你遇到私有格式的固件,可以自己写签名规则放到 ~/.config/binwalk/magic/ 下。

2.1.2 strings——从二进制里捞字符串

strings 这个工具,说白了就是帮你从一堆乱码里找出人类能读懂的文本。别小看它,很多时候关键信息就藏在这些字符串里。

# 提取所有可打印字符串
strings firmware.bin

# 设置最小长度(过滤太短的字符串)
strings -n 8 firmware.bin

# 显示字符串在文件中的偏移地址
strings -t x firmware.bin

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

嗯,这里要注意:strings 默认只处理 ASCII 编码。如果固件用的是 UTF-16 或别的编码,记得加参数 -e l-e b

我曾经在分析一个工控设备的固件时,用 strings 捞出了一段硬编码的 SSH 私钥。你想想看,这要是被攻击者拿到,整个设备就成后门了。所以做固件审计时,strings 绝对是第一道防线。

2.1.3 hexdump——二进制世界的显微镜

当 binwalk 和 strings 搞不定的时候,就该 hexdump 上场了。它能让你看到最原始的字节数据。

# 标准十六进制查看
hexdump -C firmware.bin | head -50

# 只显示指定偏移范围
hexdump -C -s 0x1000 -n 512 firmware.bin

# 显示 ASCII 和十六进制对照
xxd firmware.bin | head -30

# od 命令也可以(老派但好用)
od -A x -t x1z -v firmware.bin | head -20

避坑指南:我曾经在分析一个加密固件时,直接用 hexdump 看了半天,发现全是随机数据。后来才意识到——这固件是加密的,必须先解密才能分析。所以看到全乱码时,先想想是不是加密了。

2.2 固件文件结构解析

搞清楚了工具,咱们来看看固件到底长什么样。一个典型的嵌入式固件,结构大致是这样的:

典型嵌入式固件结构图 固件头部(Header) 魔数、版本、校验和、大小、入口地址 Bootloader(引导加载程序) U-Boot / RedBoot / 私有 Boot Linux 内核(Kernel) zImage / uImage / vmlinux 文件系统(Root Filesystem) squashfs / jffs2 / ubifs / cramfs / ext4 ← 最常分析的部分

这个结构图是我根据上百个固件总结出来的。当然,实际中会有变种——有的固件没有 Bootloader,有的把配置数据放在最后。但核心骨架就是这四块。

2.2.1 固件头部(Header)

头部是固件的身份证。不同厂商的头部格式千差万别,但通常包含这些信息:

字段 说明 常见值示例
魔数(Magic) 文件类型标识 0x27051956(U-Boot)、0x1F8B(gzip)
版本号 固件版本信息 1.0.2、R3.1.0
校验和 完整性校验 CRC32、MD5、SHA256
固件大小 总长度或各分区长度 0x400000(4MB)
入口地址 CPU 开始执行的位置 0x80001000

实战技巧:用 hexdump 看头部前 64 字节,基本就能判断固件格式。比如看到 HDR0 开头的是 Broadcom 的固件,27051956 是 U-Boot 镜像。

2.2.2 Bootloader 与内核

Bootloader 负责初始化硬件并加载内核。常见的有 U-Boot、RedBoot、CoreBoot。内核则通常是压缩过的,需要先解压才能分析。

怎么区分它们?用 binwalk 扫描时,Bootloader 通常出现在最前面,内核会显示为 Linux kernel 或 ARM zImage。我个人习惯先看 Bootloader 的版本——老版本往往有已知漏洞。

2.2.3 文件系统——真正的宝藏

文件系统是固件分析的重头戏。大部分应用层代码、配置文件、Web 页面都在这。常见的嵌入式文件系统有:

  • squashfs:只读压缩文件系统,最常见。用 unsquashfs 解压。
  • jffs2/ubifs:可读写,用于 Flash 存储。用 jeffersonubi_reader 提取。
  • cramfs:老式压缩文件系统。用 cramfsck 解压。
  • ext4:少见,但高端设备会用。
# 提取 squashfs 文件系统
binwalk -e firmware.bin
cd _firmware.bin.extracted/
unsquashfs *.squashfs

# 或者手动指定偏移(如果 binwalk 没识别出来)
dd if=firmware.bin bs=1 skip=0x100000 of=rootfs.squashfs
unsquashfs rootfs.squashfs

注意:有些厂商会对文件系统进行加密或混淆。我曾经遇到一个设备,文件系统被 XOR 加密了,密钥就藏在 Bootloader 的字符串里。所以提取不出来时,别急着放弃,回头看看 Bootloader 区域。

2.3 实战:分析一个真实固件

咱们来走一遍完整流程。假设你拿到了一个 router_fw.bin

# 第一步:查看文件基本信息
file router_fw.bin
# 输出:data(说明是裸二进制)

# 第二步:binwalk 扫描
binwalk router_fw.bin

# 输出示例:
# DECIMAL       HEXADECIMAL     DESCRIPTION
# 0             0x0             TRX firmware header, little endian
# 28            0x1C            LZMA compressed data
# 131072        0x20000         Squashfs filesystem, little endian

# 第三步:提取文件系统
binwalk -e router_fw.bin

# 第四步:进入提取目录,查看内容
cd _router_fw.bin.extracted/
ls -la

# 第五步:解压 squashfs
unsquashfs *.squashfs

# 第六步:分析关键文件
cd squashfs-root/
strings bin/httpd | grep -i "password\|admin\|root"
cat etc/shadow
ls -la etc/init.d/

你看,就这么几步,固件的内部结构就暴露无遗了。我在实际项目中,80% 的漏洞都是通过这个流程发现的——硬编码密码、后门账号、不安全的配置,全藏在文件系统里。

核心要点总结:

  • binwalk 负责拆包,strings 负责捞信息,hexdump 负责看细节
  • 固件结构 = 头部 + Bootloader + 内核 + 文件系统
  • 文件系统是分析重点,squashfs 最常见
  • 遇到加密/混淆,先找密钥,通常在 Bootloader 或头部

好了,这一章的内容就到这。工具和方法都给了,剩下的就是多练。下次你拿到一个固件,别急着跑动态分析,先用这三板斧把静态结构摸清楚——你会发现,很多问题在静态阶段就已经暴露了。


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