4、固件文件系统分析:识别文件系统类型、挂载与分析文件系统、提取关键文件

拿到一个固件,解压之后面对一堆二进制数据,很多人第一反应是懵的。我刚开始做固件分析时也是这样,对着 hex dump 看了半天,啥也没看出来。后来才明白——文件系统才是固件的骨架。你想想看,路由器、摄像头、IoT 设备,它们的固件本质上就是一个压缩的文件系统镜像。搞懂了文件系统,就等于拿到了设备的「硬盘」。

4.1 识别文件系统类型

这一步是基本功。我习惯先用 binwalk 扫一遍,它会自动识别常见的文件系统签名。但别完全依赖它,有时候签名被抹掉了,或者用了非标准的魔数,binwalk 也会翻车。

常用识别方法:

  • binwalk -Me:自动提取,递归扫描,适合新手
  • hexdump + 手动比对:看文件头魔数,比如 SquashFS 的 hsqs、UBIFS 的 UBI#
  • strings + grep:搜索 squashfsjffs2ubifs 等关键字

常见的嵌入式文件系统就那么几种:

文件系统类型 魔数(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/*:系统服务,比如 httpdtelnetd
  • /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 知识体系总览

下面这张图概括了文件系统分析的核心流程。我画这张图时特意把「提取关键文件」放在最下面,因为它是最终目的——前面所有工作都是为了找到那些有价值的文件。

固件文件系统分析流程 识别文件系统类型 binwalk / hexdump / strings 挂载/解压文件系统 mount / unsquashfs / ubireader 提取关键文件 配置 / 二进制 / 脚本 配置文件 /etc/shadow *.conf / *.cfg 二进制文件 /usr/sbin/* 自定义服务程序 脚本文件 *.sh / *.lua /etc/init.d/* 核心目标 找到硬编码凭据、后门接口、调试开关、未授权访问漏洞

4.5 实战中的坑与技巧

最后分享几个实战经验,都是我用真金白银换来的教训:

坑一: 我曾经分析一个固件,binwalk 识别出 SquashFS 但 unsquashfs 一直报错。后来发现厂商在文件系统末尾附加了自定义校验数据,把魔数破坏了。解决办法是用 dd 截取前 4MB 再试。

技巧: 如果文件系统挂载后看到一堆乱码文件名,别慌。大概率是文件名被加密或编码了。试试 ls -i 看 inode 号,或者用 find . -type f 按类型搜索。

说白了,文件系统分析就是个「找东西」的过程。你不需要把所有文件都看一遍,那太傻了。带着目的去翻——找密码、找密钥、找调试接口。我一般先看 /etc/var,这两个目录藏了 80% 的敏感信息。

嗯,这一节就到这里。记住:文件系统是固件的血肉,配置文件是它的软肋。拿到固件先拆文件系统,准没错。


专注资料整理