固件基础与文件系统:固件结构分析、常见文件系统、固件解包与打包工具

做固件逆向,第一步就是面对那个二进制大块头。说实话,很多人一上来就想着怎么反汇编、怎么找漏洞,结果连固件都解不开,卡在第一步。我见过不少新手,拿着binwalk跑一遍,看到一堆东西就以为完事了——其实远远不够。

今天我们就聊聊固件的基础结构,以及那些你一定会打交道的文件系统。嗯,这部分内容很基础,但基础往往最容易被忽视。

固件结构:它到底长什么样?

一个典型的嵌入式固件,说白了就是一堆东西拼在一起。我拆过的固件少说也有上百个了,结构上大同小异。通常包含这么几块:

  • 引导加载程序(Bootloader):比如U-Boot,负责初始化硬件、加载内核。这部分通常是固定的,很少改动。
  • 内核(Kernel):Linux内核或者RTOS内核,压缩过的居多。
  • 文件系统(Rootfs):存放应用程序、配置、库文件的地方。这是逆向分析的重点区域。
  • 配置分区(Config/Data):保存设备设置、日志等。有时候加密,有时候明文。
  • 头部信息(Header):包含魔数、版本、校验和、大小等。不同厂商的头部格式千奇百怪。

你想想看,固件逆向的第一步,其实就是把这些部分拆开。拆不开,后面什么都做不了。

核心要点:固件逆向的起点是识别结构,而不是直接反汇编。先搞清楚固件怎么组织的,再谈后续分析。

我习惯用十六进制编辑器先看一眼固件头部。比如看到 HDR0U-Boot7375 之类的魔数,基本就能判断是哪家的东西。有一次我遇到一个路由器固件,头部全是乱码,折腾了半天才发现厂商把头部做了简单的XOR加密——嗯,这种坑踩过一次就记住了。

常见文件系统:SquashFS、JFFS2、YAFFS2

嵌入式设备里,文件系统就那么几种。我列个表,你一看就明白:

文件系统 特点 常见场景 压缩方式
SquashFS 只读、高压缩比、支持多种压缩算法 固件根文件系统(最常见) gzip / lzma / lzo / xz
JFFS2 可读写、支持磨损均衡、掉电安全 配置分区、日志分区 zlib / 无压缩
YAFFS2 专为NAND Flash设计、速度快 老旧设备、部分工业设备 无压缩(按页存储)

SquashFS:你遇到最多的那个

说实话,现在90%以上的路由器、摄像头、IoT设备,根文件系统都是SquashFS。为什么?因为它只读,压缩率高,而且挂载速度快。你想想看,设备启动时不需要写文件系统,直接解压到内存就能跑,多省事。

我在项目中遇到过一台智能音箱,固件解包后发现SquashFS用了LZMA压缩。当时binwalk默认的gzip解压没跑出来,我还以为固件加密了。后来手动指定了 -e -M lzma 参数才搞定。所以啊,别太依赖工具的自动识别。

小技巧:binwalk -Me 固件.bin 可以递归解压,但有时候需要手动指定压缩算法。试试 binwalk -e -M lzma 固件.bin

JFFS2:可读写,但有点慢

JFFS2是日志结构的文件系统,支持掉电安全。说白了就是不怕突然断电。但它的缺点也很明显——挂载慢,尤其是分区大的时候。我记得有一次分析一个工业网关,JFFS2分区有64MB,挂载花了将近两分钟。嗯,这种场景下,现在更多人用UBIFS了。

解包JFFS2其实不难。用 jefferson 这个工具就行:

# 安装 jefferson
pip install jefferson

# 解包 JFFS2 镜像
jefferson rootfs.jffs2 -d output_dir

打包回去的话,稍微麻烦一点。需要用 mkfs.jffs2 工具,注意指定页大小和擦除块大小。我曾经因为页大小没对齐,导致固件刷进去设备变砖——还好有备份。

警告:JFFS2的页大小和擦除块大小必须与目标设备匹配。不匹配的话,设备可能无法启动。建议从原固件中提取这些参数。

YAFFS2:老古董,但还在用

YAFFS2是专门为NAND Flash设计的。它没有压缩,直接按页存储数据。所以解包起来反而最简单——基本上就是直接提取文件。但它的缺点也很明显:空间利用率低。

我最近一次遇到YAFFS2,是在一个2015年的工业相机上。说实话,现在新设备很少用YAFFS2了,UBIFS基本取代了它。但如果你做逆向,难免会遇到老设备,所以还是得会处理。

解包YAFFS2可以用 unyaffs2

# 解包 YAFFS2 镜像
unyaffs2 rootfs.yaffs2 output_dir

固件解包与打包工具:binwalk 和 firmware-mod-kit

工具这块,我重点说两个:binwalkfirmware-mod-kit。这两个基本覆盖了90%的场景。

binwalk:你的瑞士军刀

binwalk 是固件逆向的标配工具。它能做的事情很多:

  • 扫描固件中的文件签名(魔数)
  • 自动提取已知格式的文件
  • 支持递归解包
  • 自定义签名规则

我常用的命令就这几个:

# 扫描固件,看看里面有什么
binwalk 固件.bin

# 自动提取所有已知文件
binwalk -e 固件.bin

# 递归解包(遇到压缩文件继续解)
binwalk -Me 固件.bin

# 只提取特定偏移的文件
binwalk -D 'squashfs:rootfs.squashfs' 固件.bin

binwalk 的原理其实很简单——它维护了一个签名数据库,扫描二进制文件时匹配这些签名。比如看到 hsqs 就知道是SquashFS,看到 U-Boot 就知道是引导程序。

个人经验:binwalk 的签名数据库可以自己扩展。我在 ~/.config/binwalk/magic/ 下加过几个厂商自定义的魔数,效果不错。

firmware-mod-kit:打包利器

binwalk 擅长解包,但打包回去就有点力不从心了。这时候 firmware-mod-kit 就派上用场了。它本质上是一堆脚本的集合,封装了各种文件系统的打包工具。

基本用法:

# 解包固件
./extract-firmware.sh 固件.bin

# 修改文件系统后,重新打包
./build-firmware.sh 固件.bin/ 新固件.bin

我曾经用 firmware-mod-kit 修改过一个路由器的固件,把里面的telnetd换成了dropbear,然后重新打包刷回去。整个过程很顺利,但要注意一点——打包时一定要保持原固件的头部信息不变,否则设备不认。

避坑指南:我曾经因为修改了固件头部的大小字段,导致设备刷入后无法启动。后来发现厂商在头部做了CRC校验。所以修改固件后,记得重新计算校验和。用 firmware-mod-kit--fix-checksum 参数可以自动修复。

知识体系:一张图看懂

下面这张图,是我自己总结的固件逆向入门知识体系。你看一眼,心里就有数了:

固件逆向入门知识体系 固件结构分析 常见文件系统 解包与打包工具 Bootloader / Kernel Rootfs / 配置分区 头部信息 / 魔数 SquashFS(只读) JFFS2(可读写) YAFFS2(NAND专用) binwalk(扫描/解包) firmware-mod-kit(打包) jefferson / unyaffs2 核心流程:识别结构 → 解包文件系统 → 分析内容 → 修改 → 重新打包 注意:头部校验、压缩算法、对齐参数是常见坑点

这张图把固件逆向的入门路径画得很清楚了。从左到右,先分析结构,再识别文件系统,最后用工具解包打包。每一步都有对应的知识点和工具。

好了,固件基础这部分就聊到这儿。记住一句话:解包是逆向的第一步,也是最重要的一步。解不开,后面都是白搭。下次遇到固件,先别急着反汇编,花点时间把结构搞清楚——你会发现后面的事情顺利很多。


公众号:蓝海资料掘金营,微信deep3321