4. 固件文件系统分析:SquashFS、CramFS、JFFS2 解析与挂载

拿到一个固件,解包之后看到一堆二进制文件,下一步干什么?我个人习惯,先看文件系统。因为文件系统决定了你怎么挂载、怎么提取、怎么分析。说白了,它就是固件的“骨架”——目录结构、配置文件、可执行程序全藏在里面。

嵌入式固件里最常见的三种文件系统:SquashFS、CramFS 和 JFFS2。它们各有各的脾气,挂载方式也不一样。今天我就带你一个一个过一遍。

核心观点: 文件系统分析是固件逆向的“入口”。选错挂载方式,轻则提取失败,重则损坏固件镜像。我建议你先把下面这张图看明白,再动手操作。

固件文件系统分析:三种主流格式与挂载流程 固件镜像 SquashFS CramFS JFFS2 只读、高压缩比 unsquashfs 解包 只读、zlib 压缩 cramfsck / mount -t cramfs 可写、磨损均衡 jefferson / mount -t jffs2 ⚠ 避坑提示 挂载前先用 file 命令确认文件系统类型,避免用错工具导致镜像损坏。

4.1 SquashFS:只读文件系统的“扛把子”

SquashFS 是嵌入式 Linux 里最常见的只读文件系统。为什么?因为它压缩率高,而且支持随机读取。你想想看,一个 64MB 的 Flash 芯片,用 SquashFS 能塞进 200MB 的根文件系统——这对空间受限的设备来说太重要了。

我在项目中遇到过一台路由器,固件解包后看到一堆 .squashfs 后缀的文件。当时我直接用 mount 去挂,结果报错。后来才发现,SquashFS 有多个版本(v3、v4),挂载参数不一样。

4.1.1 识别 SquashFS 版本

先用 file 命令看一眼:

$ file firmware.bin
firmware.bin: Squashfs filesystem, little endian, version 4.0, ...

如果输出里没有版本号,可以用 binwalk 扫描:

$ binwalk -Me firmware.bin

嗯,这里要注意:binwalk -Me 会自动提取所有已知文件系统。但有时候它会漏掉偏移量不对的镜像。我个人习惯先用 binwalk -A 看特征码,再手动指定偏移。

4.1.2 挂载 SquashFS

挂载 SquashFS 需要内核支持。如果你的分析机是 Ubuntu/Debian,先装工具:

$ sudo apt install squashfs-tools

然后挂载:

$ sudo mount -t squashfs -o loop,ro firmware.squashfs /mnt/squashfs

如果挂载失败,八成是版本不匹配。试试用 unsquashfs 直接解包:

$ unsquashfs -d ./extracted firmware.squashfs

小技巧: 我曾经遇到一个 Squashfs v3 的镜像,Ubuntu 20.04 默认的 squashfs-tools 只支持 v4。解决办法是装旧版工具,或者用 sasquatch——一个专门解旧版 SquashFS 的补丁版工具。

4.2 CramFS:轻量级但“过时”的选择

CramFS 是更早的只读文件系统。它比 SquashFS 更简单,但压缩率低,而且最大只支持 256MB 的文件系统。现在新设备基本不用了,但老固件里经常碰到——尤其是那些基于 Linux 2.4/2.6 内核的嵌入式设备。

我记得有一次分析一个工业控制器的固件,解包后看到一堆 .cramfs 文件。当时我心想:“这年头还有人用 CramFS?” 但没办法,该分析还得分析。

4.2.1 挂载 CramFS

CramFS 的挂载比 SquashFS 简单,因为它不需要额外工具——内核自带支持。直接 mount:

$ sudo mount -t cramfs -o loop,ro firmware.cramfs /mnt/cramfs

如果 mount 失败,检查一下内核是否启用了 CramFS 支持:

$ cat /proc/filesystems | grep cramfs

没输出?那就得重新编译内核,或者换一台机器。我个人建议用 cramfsck 工具先验证镜像完整性:

$ cramfsck firmware.cramfs

警告: CramFS 不支持写操作,也不支持硬链接。如果你在解包后修改了文件,想重新打包成 CramFS——别想了。老老实实转成 SquashFS 或者用其他方式处理。

4.3 JFFS2:NAND Flash 的“亲儿子”

JFFS2 是专门为 NAND Flash 设计的日志型文件系统。它支持写操作、磨损均衡、坏块管理。你想想看,路由器、摄像头这些设备,运行时需要写日志、保存配置,用只读文件系统肯定不行。JFFS2 就是干这个的。

但 JFFS2 有个问题:它没有标准的“镜像文件”格式。固件里的 JFFS2 分区通常是直接从 Flash 里 dump 出来的裸数据,包含 OOB(Out-of-Band)数据。这就导致挂载时经常遇到“找不到超级块”的错误。

4.3.1 挂载 JFFS2 镜像

先装工具:

$ sudo apt install mtd-utils

然后挂载(注意:需要模拟 MTD 设备):

$ sudo modprobe mtdblock
$ sudo modprobe mtdram total_size=65536 erase_size=128
$ sudo dd if=firmware.jffs2 of=/dev/mtdblock0
$ sudo mount -t jffs2 /dev/mtdblock0 /mnt/jffs2

如果镜像包含 OOB 数据,得先清理:

$ nanddump --noecc --omitoob -f clean.jffs2 firmware.jffs2

避坑指南: 我曾经花了一下午挂一个 JFFS2 镜像,一直报 CRC 错误。后来发现是镜像里混了 UBI 头部。用 ubinfo 和 ubiattach 挂 UBI 卷,而不是直接挂 JFFS2。记住:JFFS2 和 UBI/UBIFS 是两回事。

4.4 三种文件系统对比

下面这张表,我建议你收藏。做固件分析时拿出来对照,能省不少时间。

特性 SquashFS CramFS JFFS2
读写属性 只读 只读 可读写
压缩算法 gzip/lzma/lzo/zstd zlib zlib/rtime
最大文件系统 16TB(v4) 256MB 取决于 Flash 大小
适用场景 根文件系统、只读分区 老旧嵌入式设备 NAND Flash 运行时分区
挂载工具 mount -t squashfs / unsquashfs mount -t cramfs / cramfsck mount -t jffs2 / jefferson
常见问题 版本不匹配、偏移量错误 内核不支持、镜像损坏 OOB 数据、UBI 头部干扰

4.5 实战:从固件中提取文件系统

光说不练假把式。我们拿一个实际固件走一遍流程。

4.5.1 步骤一:扫描固件

$ binwalk -Me router_firmware.bin

输出会显示所有文件系统的偏移量和类型。比如:

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header
64            0x40            LZMA compressed data
1310720       0x140000        Squashfs filesystem, little endian, version 4.0

4.5.2 步骤二:提取 SquashFS

$ dd if=router_firmware.bin of=rootfs.squashfs bs=1 skip=1310720
$ unsquashfs -d ./rootfs rootfs.squashfs

4.5.3 步骤三:分析文件系统

解包后,重点关注这些目录:

  • /etc/ —— 配置文件、密码哈希、证书
  • /bin/、/sbin/、/usr/bin/ —— 可执行程序
  • /lib/ —— 动态链接库
  • /www/、/web/ —— Web 管理界面(常有漏洞)
  • /var/ —— 运行时数据(可能包含敏感信息)

经验之谈: 我每次拿到解包后的文件系统,第一件事就是 grep 搜索密码、密钥、token。命令很简单:grep -r "password" ./rootfs/etc/。你猜怎么着?十次里有八次能搜到硬编码密码。

4.6 常见问题与排错

挂载文件系统时,你可能会遇到下面这些问题。我把我的排错思路写出来,供你参考。

  1. 挂载时报“wrong fs type” —— 内核没编译对应文件系统支持。装工具或换内核。
  2. 挂载成功但目录为空 —— 偏移量不对。用 binwalk -A 重新确认偏移。
  3. JFFS2 报 CRC 错误 —— 镜像包含 OOB 或 UBI 头部。用 nanddump 清理。
  4. SquashFS 解包报“unsupported version” —— 版本太老。用 sasquatch 或找旧版工具。
  5. CramFS 挂载后文件不全 —— 镜像可能被截断。检查固件大小是否完整。

重要提醒: 永远不要在原始固件镜像上直接操作。先备份,再分析。我曾经见过有人用 dd 写错了偏移量,直接把 Flash 芯片的 bootloader 覆盖了——设备直接变砖。