4、固件文件系统分析:识别文件系统类型、挂载与分析文件系统、提取关键文件
拿到一个固件,解压之后面对一堆二进制数据,很多人第一反应是懵的。我刚开始做固件分析时也是这样,对着 hex dump 看了半天,啥也没看出来。后来才明白——文件系统才是固件的骨架。你想想看,路由器、摄像头、IoT 设备,它们的固件本质上就是一个压缩的文件系统镜像。搞懂了文件系统,就等于拿到了设备的「硬盘」。
4.1 识别文件系统类型
这一步是基本功。我习惯先用 binwalk 扫一遍,它会自动识别常见的文件系统签名。但别完全依赖它,有时候签名被抹掉了,或者用了非标准的魔数,binwalk 也会翻车。
常用识别方法:
- binwalk -Me:自动提取,递归扫描,适合新手
- hexdump + 手动比对:看文件头魔数,比如 SquashFS 的
hsqs、UBIFS 的UBI# - strings + grep:搜索
squashfs、jffs2、ubifs等关键字
常见的嵌入式文件系统就那么几种:
| 文件系统类型 | 魔数(Magic Number) | 常见设备 |
|---|---|---|
| SquashFS | hsqs / sqsh |
路由器、机顶盒 |
| JFFS2 | 0x1985(无固定字符串) |
老旧嵌入式设备 |
| UBIFS | UBI# |
NAND Flash 设备 |
| CramFS | 0x28CD3D45 |
早期 Linux 设备 |
| ext2/3/4 | 0xEF53 |
部分定制设备 |
我的小技巧: 如果 binwalk 识别不出来,试试 file 命令。有时候它比 binwalk 更靠谱。比如 file firmware.bin 直接告诉你「这是 SquashFS 文件系统」。
4.2 挂载与分析文件系统
识别出类型之后,下一步就是挂载。嗯,这里要注意——千万别直接挂载到系统根目录,我见过有人把固件挂到 / 上,结果系统直接崩了。老老实实建个临时目录。
4.2.1 SquashFS 挂载
SquashFS 是只读的,挂载起来最简单:
# 安装工具
sudo apt install squashfs-tools
# 挂载
sudo mount -t squashfs firmware.squashfs /mnt/firmware -o loop,ro
# 或者直接用 unsquashfs 解压
unsquashfs firmware.squashfs
我个人习惯用 unsquashfs 解压出来,因为挂载后有些文件权限问题会导致读取失败。解压出来随便折腾。
4.2.2 JFFS2 挂载
JFFS2 稍微麻烦点,因为它需要模拟 MTD 设备。我踩过这个坑,第一次挂载时忘了加载 mtdblock 模块,折腾了半小时。
# 加载内核模块
sudo modprobe mtdblock
sudo modprobe jffs2
# 创建 MTD 设备
sudo modprobe mtdram total_size=65536 erase_size=256
sudo dd if=firmware.jffs2 of=/dev/mtdblock0
# 挂载
sudo mount -t jffs2 /dev/mtdblock0 /mnt/firmware
避坑指南: 我曾经在挂载 JFFS2 时遇到 jffs2: too few erase blocks 错误。原因是 total_size 设小了,要确保它大于固件实际大小。建议设成固件大小的 2 倍。
4.2.3 UBIFS 挂载
UBIFS 更复杂,需要 UBI 层。说实话,我一般直接用 ubireader 工具提取,省心:
# 安装 ubireader
pip install ubireader
# 提取
ubireader_extract_images firmware.ubi
4.3 提取关键文件
文件系统挂载或解压后,别急着到处翻。我建议先列个清单,知道自己要找什么。一般来说,重点关注三类文件:
4.3.1 配置文件
这些文件藏着设备的「秘密」——默认密码、硬编码密钥、调试接口开关。
- /etc/shadow:用户密码哈希,有时候直接是明文
- /etc/config/*:OpenWrt 风格的配置文件
- *.conf, *.cfg, *.ini:各种应用配置
- /etc/init.d/*:启动脚本,看看哪些服务默认开启
我记得有一次分析某品牌摄像头固件,在 /etc/default.conf 里直接找到了 telnet 的默认密码——admin:123456。这种低级错误在 IoT 设备里太常见了。
4.3.2 二进制文件
重点关注 Web 服务、网络服务、自定义协议处理程序。
- /usr/sbin/*:系统服务,比如
httpd、telnetd - /bin/*:核心命令,看看有没有后门
- 自定义二进制:厂商自己写的程序,通常有漏洞
我的习惯: 先用 find . -type f -executable | head -50 列出所有可执行文件,然后挑出非标准路径下的文件重点分析。标准路径下的 busybox 之类的不用浪费时间。
4.3.3 脚本文件
脚本文件是固件分析的「金矿」。很多厂商喜欢用 shell 脚本做初始化,里面经常暴露敏感信息。
- *.sh, *.bash:shell 脚本
- *.lua:OpenWrt 的 Luci 配置脚本
- *.py:Python 脚本,部分新设备在用
- /etc/init.d/*:启动脚本,看看有没有调试接口
我曾在某款智能网关的 /etc/init.d/debug.sh 里发现一段注释:# TODO: remove this before shipping。结果它没删,里面直接开启了串口调试 shell。这种「开发遗留」问题在固件里比比皆是。
4.4 知识体系总览
下面这张图概括了文件系统分析的核心流程。我画这张图时特意把「提取关键文件」放在最下面,因为它是最终目的——前面所有工作都是为了找到那些有价值的文件。
4.5 实战中的坑与技巧
最后分享几个实战经验,都是我用真金白银换来的教训:
坑一: 我曾经分析一个固件,binwalk 识别出 SquashFS 但 unsquashfs 一直报错。后来发现厂商在文件系统末尾附加了自定义校验数据,把魔数破坏了。解决办法是用 dd 截取前 4MB 再试。
技巧: 如果文件系统挂载后看到一堆乱码文件名,别慌。大概率是文件名被加密或编码了。试试 ls -i 看 inode 号,或者用 find . -type f 按类型搜索。
说白了,文件系统分析就是个「找东西」的过程。你不需要把所有文件都看一遍,那太傻了。带着目的去翻——找密码、找密钥、找调试接口。我一般先看 /etc 和 /var,这两个目录藏了 80% 的敏感信息。
嗯,这一节就到这里。记住:文件系统是固件的血肉,配置文件是它的软肋。拿到固件先拆文件系统,准没错。