4、文件系统解析:Squashfs、JFFS2、UBIFS等嵌入式文件系统
好,咱们进入正题。这一章聊的是嵌入式文件系统。说白了,就是固件里那些数据是怎么组织、怎么存放的。你拿到一个思科路由器的固件,解压出来一堆二进制文件,怎么找到里面的配置文件?怎么把文件系统挂载到本地?这些就是本章要解决的问题。
我个人习惯,拿到一个固件后,第一件事就是看它的文件系统类型。为什么?因为不同的文件系统,提取方式完全不同。你拿处理Squashfs的方法去搞JFFS2,那肯定碰一鼻子灰。
4.1 嵌入式文件系统三巨头
嵌入式世界里,文件系统就那么几种。我挑三个最常见的讲:Squashfs、JFFS2、UBIFS。你想想看,思科、华为、中兴这些厂家的固件,十有八九跑不出这三个。
| 文件系统 | 特点 | 适用场景 | 压缩方式 |
|---|---|---|---|
| Squashfs | 只读、高压缩比 | 固件根文件系统 | gzip/lzma/lzo |
| JFFS2 | 可写、磨损均衡 | NOR Flash | zlib |
| UBIFS | 可写、大容量支持 | NAND Flash | LZO/zlib |
嗯,这里要注意。Squashfs是只读的,你没法直接往里面写东西。但好处是压缩率高,同样的空间能塞更多数据。我在项目中遇到过,一个40MB的固件,解压出来能有200MB。这就是Squashfs的功劳。
4.2 Squashfs的挂载与提取
Squashfs是最常见的。思科很多低端路由器都用它。怎么识别?用binwalk扫一下固件,看到"Squashfs filesystem"的标识,那就是了。
提取Squashfs,我推荐两种方法:
- 用unsquashfs直接解压——最简单,一行命令搞定
- 挂载后拷贝——适合你想保留文件属性的场景
方法一:unsquashfs解压
# 先找到Squashfs的起始偏移
binwalk -Me firmware.bin
# 假设偏移是0x123456,直接解压
unsquashfs -offset 0x123456 firmware.bin
# 解压后的文件在squashfs-root目录下
我曾经遇到过一个坑。有个固件,binwalk识别出了Squashfs,但unsquashfs死活解压不出来。后来发现是厂商自己魔改了Squashfs的头部。怎么办?手动分析偏移,用dd把Squashfs部分切出来,再尝试挂载。
小技巧:如果unsquashfs报错,试试用sasquatch。这个工具能处理一些非标准的Squashfs变种。
4.3 JFFS2的处理方式
JFFS2在思科的老设备上很常见。它跟Squashfs不一样,是可写的。但这也意味着它更复杂——有日志结构、有磨损均衡。
提取JFFS2,我一般用jefferson这个工具。它是个Python写的JFFS2解析器,比手动挂载方便多了。
# 安装jefferson
pip install jefferson
# 提取JFFS2文件系统
jefferson -d output_dir jffs2_partition.bin
你可能会问,为什么不直接挂载?嗯,因为JFFS2需要MTD设备支持。你在普通Linux上挂载JFFS2,得先模拟一个MTD设备。不是不行,但麻烦。jefferson直接解析二进制文件,省事。
注意:JFFS2的镜像可能有多个erase block。jefferson会自动处理,但如果你用dd切分,一定要算好每个block的大小。我见过有人切错了,结果文件系统全是乱码。
4.4 UBIFS——大容量NAND的标配
UBIFS是后来兴起的,专门针对NAND Flash。思科的中高端设备,比如Catalyst系列,很多都用它。UBIFS比JFFS2强在哪?支持更大的分区、更快的挂载速度、更好的压缩。
提取UBIFS,需要两步走:
- 从固件中分离出UBI镜像
- 用
ubireader或ubi_reader提取文件
# 用ubireader提取
ubireader_extract_files ubi_image.bin
# 或者手动挂载(需要内核支持)
modprobe ubi
ubiattach -p /dev/ubi_ctrl -m 0 -O 2048
mount -t ubifs ubi0:rootfs /mnt/ubifs
我个人习惯用ubireader。为什么?因为手动挂载需要内核模块,而且不同内核版本兼容性不一样。ubireader是纯Python的,跨平台,省心。
4.5 关键配置文件定位
文件系统挂载好了,接下来就是找配置文件。思科设备最重要的配置文件是startup-config和running-config。但它们在文件系统里的位置,不同型号不一样。
我总结了一个查找路径的优先级:
/etc/startup-config—— 最常见的位置/flash/startup-config—— 有些设备放在flash分区/nvram/startup-config—— 老设备喜欢放这里/mnt/config/startup-config—— 定制化固件可能的位置
除了startup-config,还有几个文件值得关注:
| 文件名 | 说明 | 重要性 |
|---|---|---|
| startup-config | 启动配置文件 | ⭐⭐⭐⭐⭐ |
| running-config | 当前运行配置 | ⭐⭐⭐⭐ |
| private-config | 加密的私有配置 | ⭐⭐⭐ |
| system.cfg | 系统级配置 | ⭐⭐⭐ |
实战技巧:如果找不到startup-config,试试搜索所有包含"enable password"或"username"的文件。用grep -r "enable password" .,往往能直接定位到配置文件。
4.6 知识体系总览
说了这么多,我画个图帮你理清思路。嵌入式文件系统解析的核心流程,其实就是三步:识别类型、挂载提取、定位关键文件。
这张图把整个流程串起来了。你从固件分析开始,识别出文件系统类型,然后选择合适的工具挂载提取,最后定位到startup-config。每一步都有对应的工具和方法,按图索骥就行。
4.7 避坑指南
最后,分享几个我踩过的坑:
- 偏移量算错——binwalk给出的偏移是十进制,但有些工具要十六进制。我曾经因为这个浪费了半天。
- 文件系统被加密——有些厂商会对Squashfs进行AES加密。遇到这种情况,先找解密密钥,通常在bootloader里。
- 配置文件被混淆——startup-config里的密码可能是加密的。别慌,思科的加密算法有规律可循,Type 7密码可以直接在线解密。
我的建议:每次处理新固件,先建一个工作目录。把binwalk的结果、提取的文件、分析笔记都放一起。这样回头查问题,能省不少时间。
好了,文件系统解析这块就讲这么多。你把这些方法练熟了,以后拿到任何嵌入式固件,都能快速找到你想要的东西。