4、固件解包:使用Binwalk、dd、unsquashfs、jefferson等工具解包不同文件系统

拿到一个固件,第一件事是什么?

不是直接逆向,也不是扔进IDA。你得先把它拆开,看看里面到底装了啥。就像收到一个快递,总得先拆箱子吧?

固件解包这事儿,我干了快十年了。说实话,刚开始那会儿我也踩过不少坑。有一次分析某款路由器固件,用Binwalk扫了半天啥也没发现,后来才发现是文件头被篡改了。嗯,这些经验教训,今天一并分享给你。

4.1 固件解包的核心思路

固件本质上就是一个大二进制文件。它可能包含:

  • Bootloader(引导程序)
  • 内核镜像
  • 文件系统(SquashFS、JFFS2、CramFS等)
  • 配置文件、Web界面资源
  • 各种二进制可执行文件

解包的目标,就是把这些东西从固件里提取出来。说白了,就是做"逆向拆解"。

核心原则:先识别,再提取。别上来就一顿操作猛如虎,先搞清楚固件是什么格式、用了什么文件系统。

我个人习惯,拿到固件后先跑一遍 file 命令和 binwalk,看看能发现什么。

4.2 Binwalk:固件分析的瑞士军刀

Binwalk 是我用得最多的工具,没有之一。它就像一个"固件CT扫描仪",能帮你快速定位固件里的各个组件。

4.2.1 基本用法

# 扫描固件,识别文件类型和偏移
binwalk firmware.bin

# 提取所有识别的文件
binwalk -e firmware.bin

# 递归提取(遇到嵌套固件继续解包)
binwalk -Me firmware.bin

# 只提取特定类型的文件
binwalk -D 'squashfs:rootfs.squashfs' firmware.bin

你想想看,一个简单的 -e 参数,就能把固件拆得七零八落。但要注意,Binwalk 不是万能的。

避坑指南:我曾经遇到一个固件,Binwalk 扫描出来一堆偏移,但提取出来的文件全是坏的。后来发现是固件用了自定义的魔数(Magic Number),Binwalk 的签名库没覆盖到。这时候就得手动分析了。

4.2.2 进阶技巧

Binwalk 的熵分析功能很实用。它能帮你判断固件是否加密或压缩。

# 生成熵图
binwalk -E firmware.bin

# 指定偏移范围扫描
binwalk -e -o 0x100000 firmware.bin

熵值高的区域,通常是压缩或加密数据。熵值低的区域,可能是明文数据或填充字节。这个技巧我在分析某款IoT摄像头固件时用过,一下子就定位到了加密的配置文件。

4.3 dd:最朴素的切割工具

别小看 dd,它虽然古老,但关键时刻能救命。当 Binwalk 识别出偏移量但提取失败时,我就用 dd 手动切割。

# 从固件中切割指定偏移和大小的数据
dd if=firmware.bin of=header.bin bs=1 skip=0 count=512

# 切割文件系统部分
dd if=firmware.bin of=rootfs.squashfs bs=1 skip=0x100000 count=0x500000

参数说明:

参数 含义
if 输入文件
of 输出文件
bs 块大小(通常设为1,按字节操作)
skip 跳过多少字节开始读取
count 读取多少字节

我的经验:dd 时,bs=1 虽然慢,但最精确。如果固件很大,可以先用 bs=1024 试切,确认偏移后再用 bs=1 精切。

4.4 SquashFS:最常见的嵌入式文件系统

SquashFS 是嵌入式设备中最常见的只读文件系统。压缩率高,读取快,非常适合资源受限的设备。

4.4.1 使用 unsquashfs 解包

# 解包 SquashFS 镜像
unsquashfs rootfs.squashfs

# 指定输出目录
unsquashfs -d ./extracted_rootfs rootfs.squashfs

# 查看 SquashFS 信息(不解包)
unsquashfs -s rootfs.squashfs

解包后,你会得到一个完整的文件系统目录树。里面通常有 /bin/usr/etc/www 等目录。

4.4.2 处理变种 SquashFS

有些厂商会对 SquashFS 做魔改。比如修改压缩算法、改变块大小等。这时候标准 unsquashfs 会报错。

我记得有一次分析某品牌路由器固件,unsquashfs 直接报 "Unknown compression type"。后来我查了源码,发现它用了 LZMA 压缩,但标准工具只支持 ZLIB。解决办法是重新编译带 LZMA 支持的 unsquashfs。

# 编译支持 LZMA 的 unsquashfs
cd squashfs-tools
make
# 然后使用编译后的版本

注意:如果遇到 "Failed to read superblock" 错误,说明文件系统可能被加密或损坏。别急着放弃,先检查一下偏移是否正确。

4.5 JFFS2:日志结构的文件系统

JFFS2 是另一种常见的嵌入式文件系统,特别适合闪存设备。它支持磨损均衡和掉电保护。

4.5.1 使用 jefferson 解包

jefferson 是目前最常用的 JFFS2 解包工具。它比老旧的 jffs2dump 好用得多。

# 安装 jefferson
pip install jefferson

# 解包 JFFS2 镜像
jefferson rootfs.jffs2

# 指定输出目录
jefferson -d ./extracted_jffs2 rootfs.jffs2

jefferson 会自动处理 JFFS2 的节点结构,提取出完整的文件系统。

4.5.2 处理 JFFS2 的常见问题

JFFS2 镜像有时会包含 OOB(Out-of-Band)数据。这些数据是闪存的额外信息,jefferson 默认会忽略它们。

如果遇到 "No JFFS2 nodes found" 错误,可能是镜像被截断了,或者包含了额外的头部信息。这时候可以试试:

# 先跳过前 N 字节再解包
dd if=rootfs.jffs2 of=clean.jffs2 bs=1 skip=256
jefferson clean.jffs2

小技巧:JFFS2 的魔数是 0x1985(小端序)。你可以用 hexdumpbinwalk 搜索这个值,快速定位文件系统的起始位置。

4.6 其他文件系统及工具

除了 SquashFS 和 JFFS2,你还会遇到:

文件系统 解包工具 特点
CramFS cramfsckcramfsswap 老式只读文件系统,已较少使用
UBIFS ubireaderubi_reader 用于 NAND Flash,支持动态坏块管理
YAFFS2 unyaffs 专为 NAND Flash 设计,日志结构
ROMFS romfsck 极简只读文件系统,常用于 Bootloader
# CramFS 解包示例
cramfsck -x ./extracted_cramfs rootfs.cramfs

# UBIFS 解包示例
ubireader_extract_files rootfs.ubi

# YAFFS2 解包示例
unyaffs rootfs.yaffs2 ./extracted_yaffs

4.7 实战:完整解包流程

下面是一个典型的固件解包流程。我拿一个虚构的路由器固件做演示。

# 1. 初步扫描
file firmware.bin
# 输出: data

binwalk firmware.bin
# 输出:
# DECIMAL       HEXADECIMAL     DESCRIPTION
# 0             0x0             TRX firmware header, little endian
# 256           0x100           LZMA compressed data
# 131072        0x20000         SquashFS filesystem, little endian

# 2. 提取文件系统
dd if=firmware.bin of=rootfs.squashfs bs=1 skip=131072
unsquashfs -d ./rootfs rootfs.squashfs

# 3. 检查提取结果
ls -la ./rootfs/
# 应该看到 bin, etc, lib, usr 等目录

# 4. 如果遇到问题,尝试其他偏移
binwalk -E firmware.bin  # 查看熵图
binwalk -A firmware.bin  # 查看 CPU 指令

核心要点:

  • 先扫描,再提取。别跳过 binwalk 这一步。
  • 确认偏移量。错误的偏移会导致提取失败或数据损坏。
  • 检查文件系统类型。不同文件系统用不同工具。
  • 遇到错误别慌。先看错误信息,再查资料。

4.8 知识体系图

下面这张图展示了固件解包的核心流程和工具选择逻辑。

固件解包知识体系 固件二进制文件 第一步:识别(file + binwalk) 文件系统类型? SquashFS unsquashfs JFFS2 jefferson CramFS/UBIFS/YAFFS2 对应工具 第二步:提取(dd + 对应工具) 文件系统目录树

4.9 常见问题与排错

解包过程中,你肯定会遇到各种问题。我把最常见的几个列出来:

  • Binwalk 扫描结果为空:固件可能被加密或使用了自定义格式。试试熵分析,看看数据分布。
  • 提取的文件无法解包:偏移量可能不对。用 hexdump 手动确认文件系统魔数位置。
  • 解包后文件系统不完整:固件可能被分割成多个部分。检查是否有其他偏移位置。
  • 工具报错 "Unknown compression":厂商可能魔改了压缩算法。需要找对应版本的解包工具。

我的建议:建立一个"固件解包工具箱",把常用的工具和脚本放在一起。遇到新固件,先跑一遍自动化脚本,能省不少时间。

好了,固件解包这部分就讲到这里。工具和方法都给你了,剩下的就是多练。记住,每个固件都有自己的脾气,别指望一招鲜吃遍天。


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