4、固件文件系统分析:binwalk、固件解包、文件系统识别(SquashFS、CramFS、JFFS2)与提取

固件逆向工程的第一步往往不是直接反汇编代码,而是先回答一个更基础的问题:固件镜像里到底装了什么?绝大多数嵌入式设备(路由器、摄像头、IoT 网关、工业控制器)的固件并非单一的可执行文件,而是由引导加载程序(Bootloader)、内核(Kernel)、设备树(DTB)、根文件系统(RootFS)以及若干应用分区共同组成的复合镜像。文件系统作为存放用户态程序、配置脚本、Web 管理页面和动态库的核心载体,其格式识别与成功解包直接决定了后续分析的效率与深度。本章将围绕 binwalk 的使用、固件解包流程、三大经典嵌入式文件系统(SquashFS、CramFS、JFFS2)的识别与提取方法展开,帮助读者建立一套从“拿到固件”到“看到文件内容”的完整方法论。

固件文件系统分析链路 固件镜像 .bin / .img / .trx binwalk 扫描 文件签名 / 熵分析 偏移定位 文件系统起始地址 解包提取 unsquashfs 等 文件系统类型识别 SquashFS 只读压缩 · 高压缩比 unsquashfs 提取 CramFS 老牌只读 · zlib 压缩 cramfsck / 手动解包 JFFS2 NOR/NAND Flash 专用 jefferson 提取 输出:文件系统目录树 /bin /sbin /etc /usr /lib /www → 后续静态分析与漏洞挖掘基础

4.1 核心原理:固件镜像的复合结构与文件系统定位

嵌入式固件在出厂时通常以单一镜像文件的形式发布,但内部却是由多个独立分区拼接而成。典型的固件布局从低地址到高地址依次为:Bootloader(如 U-Boot)、内核镜像(zImage/Image)、设备树(DTB)、根文件系统、以及可选的用户数据分区(如 JFFS2 用于存储配置)。这些分区之间往往存在对齐填充(Padding),且没有统一的索引表,因此分析工具必须依靠文件签名(Magic Number)来识别每个分区的起始位置。

binwalk 是这一阶段最核心的工具。它通过扫描镜像中的已知文件签名(如 SquashFS 的 hsqs、CramFS 的 0x28CD3D45、JFFS2 的 0x1985 节点标记),输出一张“偏移地址 + 文件类型”的清单。但签名扫描并非万能——当固件启用了加密或混淆时,签名会被隐藏,此时需要借助熵分析(Entropy Analysis)来辅助判断。熵值接近 1.0 的区域通常表示已加密或已压缩的数据,而熵值较低的区域则可能是明文代码或未压缩数据。

关键认知:文件系统在固件中的偏移地址是后续所有提取操作的基础。偏移定位错误将导致解包失败或提取出损坏的文件。建议在扫描后使用 binwalk -A(ASCII 扫描)和 binwalk -E(熵分析)交叉验证。

4.2 判断方法与操作流程:从 binwalk 扫描到文件系统提取

下面以一台典型家用路由器固件为例,演示完整的分析流程。假设固件文件名为 router_fw.bin,大小约 16MB。

步骤一:基础扫描

binwalk router_fw.bin

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             U-Boot version string, "U-Boot 1.1.4..."
131072        0x20000         Linux kernel image (zImage)
4194304       0x400000        SquashFS filesystem, little endian, version 4.0, compression:lzma, size: 10485760 bytes

扫描结果显示在偏移 0x400000 处存在一个 SquashFS 文件系统。此时可以直接使用 binwalk 的自动化解包功能:

binwalk -e router_fw.bin

该命令会自动提取所有可识别的分区,并在当前目录下生成 _router_fw.bin.extracted 文件夹。对于 SquashFS,binwalk 会调用 unsquashfs 工具完成解包。但自动化解包并非总是成功,当遇到损坏的填充数据或非标准对齐时,需要手动指定偏移进行提取:

dd if=router_fw.bin of=squashfs_part.bin bs=1 skip=4194304
unsquashfs squashfs_part.bin

步骤二:文件系统类型识别

当 binwalk 无法自动识别文件系统类型时,需要手动检查签名。下表列出了三种常见嵌入式文件系统的关键特征:

文件系统 魔数/签名 压缩方式 典型用途 提取工具
SquashFS hsqs(版本 4.0)
sqsh(版本 3.x)
gzip / lzma / lzo / xz 现代路由器、IoT 设备根文件系统 unsquashfs
CramFS 0x28CD3D45(小端) zlib(仅支持压缩) 早期 Linux 嵌入式设备(2000-2010) cramfsck / binwalk -e
JFFS2 节点标记 0x1985(小端) zlib / rubin / rtime NOR/NAND Flash 上的可写分区(配置存储) jefferson / jffs2extract

步骤三:CramFS 与 JFFS2 的专项提取

CramFS 的提取相对简单,因为其头部结构固定且未采用复杂的块索引。使用 cramfsck -x 命令即可解包:

cramfsck -x extracted_dir cramfs_part.bin

JFFS2 的提取则复杂得多。JFFS2 是日志型文件系统,数据以节点(Node)形式分布在 Flash 上,且可能存在擦除块(Erase Block)之间的空洞。推荐使用 jefferson 工具:

pip install jefferson
jefferson jffs2_part.bin extracted_dir

如果 JFFS2 镜像包含 OOB(Out-of-Band)数据(常见于 NAND Flash),则需要先使用 nanddump 或 nandwrite 工具剥离 OOB 区域,再进行提取。

风险提示:JFFS2 镜像可能包含多个擦除块,且每个块的大小(通常为 64KB 或 128KB)会影响提取结果。在提取前务必确认 Flash 的页大小(Page Size)和块大小(Block Size),否则可能导致文件内容错位。

4.3 案例拆解:某品牌 IP 摄像头固件的完整解包过程

本案例来自一次真实的 IoT 设备安全评估。目标设备是一款国产 IP 摄像头,固件版本为 v2.1.4,固件文件 ipcam_fw.bin 大小 8MB。初始目标是提取 Web 管理后台的源码,以寻找未授权访问漏洞。

初始现象:使用 binwalk ipcam_fw.bin 扫描后,仅识别出内核镜像(偏移 0x1F0000),未发现任何文件系统签名。熵分析显示在偏移 0x400000 之后存在一段高熵区域(熵值 0.99),但签名扫描无结果。

分析判断:高熵区域通常意味着数据已被压缩或加密。考虑到该设备使用联咏(Novatek)主控芯片,其 SDK 默认对文件系统进行 XOR 加密或自定义混淆。进一步使用 binwalk -X 尝试常见 XOR 密钥扫描,发现密钥 0x5A 能够使熵值显著下降,确认文件系统被简单 XOR 加密。

实际操作:

# 使用 XOR 密钥 0x5A 解密文件系统区域
dd if=ipcam_fw.bin of=encrypted_fs.bin bs=1 skip=4194304 count=4194304
python3 -c "
data = open('encrypted_fs.bin','rb').read()
decrypted = bytes([b ^ 0x5A for b in data])
open('decrypted_fs.bin','wb').write(decrypted)
"
# 重新扫描解密后的文件
binwalk decrypted_fs.bin
# 输出显示 SquashFS filesystem, little endian, version 4.0, compression:lzma
unsquashfs decrypted_fs.bin

结果对比:解包后获得了完整的文件系统目录树,其中包括 /www 目录下的 CGI 脚本和 HTML 页面。通过分析 login.cgi 的源码,发现其存在硬编码的后台管理员账号 admin/123456,且未对登录尝试次数进行限制,可直接利用该漏洞获取设备完全控制权。

风险与代价:XOR 解密属于弱加密,但若厂商使用 AES 等强加密算法,则无法通过简单 XOR 破解。此时需要从 U-Boot 或内核启动参数中提取密钥,或通过硬件调试接口(UART/JTAG)获取解密后的内存镜像。

复盘经验:当 binwalk 无法识别文件系统时,不要急于放弃。优先检查是否存在 XOR 混淆(常见于小厂设备),其次检查是否启用了 LZMA 压缩但未正确识别签名。此外,binwalk -E 的熵分析是判断“是否存在加密”的最快手段。

4.4 常见误区与总结复盘

在固件文件系统分析中,初学者常犯以下错误,值得特别注意:

  • 盲目依赖 binwalk -e 自动解包:自动化工具在遇到非标准对齐、填充数据或损坏的头部时可能失败。手动使用 dd 配合偏移提取是更可靠的方式。
  • 忽略文件系统版本差异:SquashFS 4.0 与 3.x 的签名不同(hsqs vs sqsh),且 4.0 支持多种压缩算法。使用 unsquashfs 时需确保版本匹配,否则会报错。
  • 混淆 CramFS 与 SquashFS:CramFS 的魔数位于文件系统头部偏移 0 处,而 SquashFS 的魔数位于偏移 0 处但内容不同。使用 hexdump -C 检查头部前 4 字节是最直接的区分方法。
  • 忽略 JFFS2 的擦除块结构:JFFS2 镜像在提取时若未指定正确的擦除块大小,可能导致文件内容错乱。建议使用 jefferson 时通过 --block-size 参数显式指定。
  • 未检查文件系统末尾的填充数据:某些固件在文件系统之后会追加额外的配置数据或第二个文件系统。使用 binwalk -A 扫描 ASCII 字符串,可以发现遗漏的分区。
效率提升建议:在分析未知固件时,建议先使用 binwalk --preserve-symlinks 保留符号链接,避免解包后因链接断裂而丢失关键文件。同时,使用 file 命令对提取出的每个分区进行二次确认,确保类型判断准确。

总结而言,固件文件系统分析是固件逆向的基石。掌握 binwalk 的签名扫描与熵分析、熟悉 SquashFS/CramFS/JFFS2 的结构差异、并能手动处理 XOR 混淆等常见对抗手段,将极大提升分析效率。在实际操作中,建议将自动化工具与手动偏移提取相结合,并始终保留原始固件的备份,以便在提取失败时重新尝试。文件系统解包成功后,后续的静态代码审计、漏洞挖掘和固件篡改分析才能顺利展开。