3、固件获取与预处理:固件提取方法、文件系统解析、固件解包与重打包技术

固件Fuzzing的第一步并非直接执行目标代码,而是需要从硬件设备、厂商官网或OTA升级包中获取原始固件镜像,并对其进行结构化解析与预处理。这一阶段的质量直接决定了后续逆向分析、模拟执行和模糊测试的可行性与效率。本章将系统讲解固件获取的三大渠道、文件系统识别与挂载技术、以及解包与重打包的完整工程流程,帮助读者建立从“二进制黑盒”到“可分析文件系统”的标准化处理能力。

固件获取与预处理工程链路 固件获取渠道 ① 官网/厂商支持页 ② 硬件提取(SPI Flash/UBoot) ③ OTA/固件更新包 镜像类型识别 binwalk 扫描 file/hexdump 头信息 熵分析/压缩检测 文件系统解析 SquashFS/JFFS2 CramFS/UBIFS ext2/3/4, FAT, ROMFS 解包与重打包 unsquashfs / jefferson 修改/注入后重打包 固件签名绕过 核心工具链:binwalk → file → unsquashfs → jefferson → firmware-mod-kit → sasquatch 输出:可读文件系统目录 + 可重打包的镜像 + 提取的二进制目标 关键检查点 • 固件头偏移量(Header Offset) • 压缩算法(gzip/lzma/xz) • 文件系统魔数(Magic Number) • 架构信息(ARM/MIPS/RISC-V) 常见风险 • 加密固件(需先解密) • 签名校验(需绕过或提取密钥) • 非标准文件系统(需定制工具) • 固件损坏(需修复或重下) 输出产物 • 解包后的文件系统目录树 • 可重打包的镜像文件 • 提取的ELF二进制/共享库 • 配置文件/启动脚本/密钥

3.1 固件获取渠道与合法性边界

3.1.1 核心原理:固件来源的三种路径

固件获取是Fuzzing工作的起点,其核心目标是获得目标设备的完整可执行镜像。根据设备类型和厂商策略,固件获取通常分为三种路径:官方渠道下载、硬件直接提取和OTA/更新包捕获。官方渠道适用于路由器、智能家居网关、网络摄像头等消费级产品,厂商通常会在支持页面提供固件下载链接,文件格式多为ZIP、TRX、BIN或IMG。硬件提取则适用于无法从官方获取固件的场景,例如已停止维护的设备或定制化工业控制器,常见方法包括使用编程器读取SPI NOR Flash芯片、通过UBoot命令行导出NAND Flash分区、或利用JTAG/SWD调试接口转储内存。OTA捕获则针对支持远程升级的设备,通过搭建代理服务器(如mitmproxy)拦截HTTPS流量,或使用Firmware Analysis Comparison Toolkit(FACT)等工具分析更新协议。

在合法性方面,安全研究人员必须遵守《计算机软件保护法》和厂商的最终用户许可协议(EULA)。建议在获取固件前,先确认是否属于以下合法场景:(1)自有设备——你拥有该硬件设备,且仅用于安全研究;(2)厂商授权——已获得厂商的书面渗透测试许可;(3)漏洞披露计划——参与厂商或第三方漏洞众测平台(如Bugcrowd、HackerOne)的项目。对于硬件提取,还需注意不要破坏设备保修标签或造成物理损坏。

风险提示:未经授权获取或逆向固件可能违反DMCA(数字千年版权法)第1201条关于反规避技术措施的规定。即使设备归你所有,若固件包含加密或签名保护,绕过这些机制也可能构成法律风险。建议在课程实验环境中使用厂商明确允许研究的设备,或使用开源硬件(如OpenWrt支持的设备)进行练习。

3.1.2 操作流程:从官网到本地镜像

以最常见的官网下载为例,标准流程如下:

  1. 确定设备型号与固件版本:通过设备底部标签或系统设置页面获取型号(如TP-Link Archer AX6000)和当前固件版本(如1.0.5 Build 20231015)。
  2. 访问厂商支持页面:在官网“下载中心”或“支持”栏目中,输入型号搜索固件。注意区分硬件版本(V1/V2/V3),不同硬件版本的固件通常不兼容。
  3. 下载并校验文件:使用wget或浏览器下载固件包,然后计算SHA-256哈希值与官网公布的校验值比对,确保文件完整性。
  4. 初步识别文件类型:使用file命令查看文件类型,例如file firmware.bin可能输出“data”或“u-boot legacy uImage”。
# 示例:下载并校验固件
wget https://example.com/firmware/ax6000_v1.0.5.bin
sha256sum ax6000_v1.0.5.bin
# 输出: 3a7b...f9e2  ax6000_v1.0.5.bin
file ax6000_v1.0.5.bin
# 输出: ax6000_v1.0.5.bin: u-boot legacy uImage, ...

3.1.3 案例拆解:从路由器Flash芯片提取固件

假设需要分析一台已停产的工业路由器,官网已无固件下载。设备主板上有一颗Winbond W25Q128JV SPI NOR Flash芯片(16MB容量)。操作步骤如下:

  • 准备工具:CH341A编程器、SOP8测试夹、杜邦线、Flash芯片型号识别软件(如FlashROM)。
  • 连接芯片:使用测试夹夹住芯片,注意引脚1方向标记(通常为圆点或斜切角)。连接编程器到电脑USB口。
  • 读取固件:在编程器软件中选择芯片型号W25Q128JV,设置读取范围为0x000000-0xFFFFFF,点击“读取”并保存为router_full.bin(16MB)。
  • 验证读取结果:使用binwalk router_full.bin扫描,若输出包含“SquashFS filesystem”或“JFFS2 filesystem”等条目,说明读取成功。

此案例的关键在于:SPI Flash通常包含Bootloader(UBoot)、内核、根文件系统和配置分区。读取后需进一步解析分区布局,才能定位到文件系统起始偏移。

3.1.4 常见误区与复盘

  • 误区1:忽略硬件版本差异——下载了错误硬件版本的固件,导致后续分析时内核模块不匹配。复盘:下载前务必核对设备标签上的硬件版本号。
  • 误区2:直接使用编程器读取NAND Flash——NAND Flash存在坏块管理机制,直接读取会产生大量错误数据。复盘:NAND应使用专用读取器或通过UBoot命令nand read导出。
  • 误区3:忽略OTA流量加密——部分设备使用HTTPS传输固件,直接抓包只能看到密文。复盘:需在设备中安装自定义CA证书,或使用Firmware Analysis Framework的OTA分析模块。

3.2 文件系统解析与识别技术

3.2.1 核心原理:嵌入式文件系统的多样性

嵌入式设备常用的文件系统包括SquashFS、JFFS2、CramFS、UBIFS、ext2/3/4、FAT32和ROMFS。每种文件系统都有独特的魔数(Magic Number)和结构特征。例如,SquashFS的魔数为hsqs(0x73717368),JFFS2的魔数为0x1985,CramFS的魔数为0x28cd3d45。识别文件系统的核心方法是使用binwalk工具进行签名扫描,它通过匹配已知文件头特征来定位文件系统在固件中的偏移位置。

除了binwalk,还可以使用file命令识别文件系统类型,但该命令对嵌入式文件系统的识别率较低。更可靠的方法是使用binwalk -A(执行熵分析)和binwalk -e(自动提取)。熵分析可以识别加密或压缩区域,帮助判断固件是否被加密。

文件系统魔数/特征典型用途提取工具
SquashFShsqs (0x73717368)只读根文件系统,压缩率高unsquashfs, sasquatch
JFFS20x1985 (大端)NOR/NAND Flash可写文件系统jefferson, jffs2dump
CramFS0x28cd3d45早期只读压缩文件系统cramfsck, cramfsswap
UBIFSUBI# (0x55424923)NAND Flash日志型文件系统ubireader_extract_files
ext2/3/40x53EF (超级块)SD卡/USB存储debugfs, mount -o loop
FAT320x55AA (引导扇区)SD卡/分区mount -t vfat

3.2.2 判断方法:binwalk深度扫描与手动验证

使用binwalk扫描固件时,建议执行以下命令组合:

# 基础扫描
binwalk firmware.bin

# 详细扫描(显示所有签名)
binwalk -A firmware.bin

# 熵分析(识别加密/压缩区域)
binwalk -E firmware.bin

# 自动提取已知文件
binwalk -e firmware.bin

当binwalk输出包含类似以下内容时,说明找到了文件系统:

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             u-boot legacy uImage, ...
262144        0x40000         SquashFS filesystem, little endian, version 4.0, compression:lzma, size: 8388608 bytes

此时,文件系统起始偏移为0x40000(262144字节),大小为8MB。可以使用dd命令提取该区域:

dd if=firmware.bin of=squashfs.img bs=1 skip=262144 count=8388608

3.2.3 案例拆解:解析一个混合固件镜像

某IP摄像头固件(camera_fw.bin)经binwalk扫描后,发现包含两个文件系统:一个SquashFS(偏移0x10000)和一个JFFS2(偏移0x800000)。分析过程如下:

  • 提取SquashFS:使用unsquashfs -s squashfs.img查看文件系统信息,确认压缩算法为LZMA。然后使用unsquashfs -d ./squashfs-root squashfs.img解包到目录。
  • 提取JFFS2:使用jefferson jffs2.img工具解包,该工具能处理大端和小端JFFS2镜像。
  • 对比分析:SquashFS中存放只读系统文件(/bin, /usr, /etc),JFFS2中存放可写配置(/etc/config, /var)。Fuzzing目标通常是SquashFS中的网络服务二进制(如/usr/sbin/httpd)。

此案例的关键在于:一个固件可能包含多个文件系统,分别对应不同分区。必须完整提取所有分区,才能获得完整的文件系统视图。

3.2.4 常见误区与复盘

  • 误区1:binwalk扫描不到文件系统——可能因为固件被加密或使用了非标准文件系统。复盘:使用binwalk -E查看熵值,若熵值接近1.0则可能加密;尝试使用binwalk -A扫描更多签名。
  • 误区2:unsquashfs解包失败——SquashFS版本或压缩算法不兼容。复盘:使用sasquatch工具(支持更多SquashFS变体),或手动指定-comp参数。
  • 误区3:忽略文件系统字节序——JFFS2和SquashFS都有大端/小端变体。复盘:使用file命令查看字节序,或使用hexdump -C检查魔数。

3.3 固件解包与重打包技术

3.3.1 核心原理:解包与重打包的对称性

固件解包是将固件镜像还原为可读文件系统的过程,而重打包则是将修改后的文件系统重新封装为固件镜像。两者在技术上是对称的:解包需要识别文件系统类型并调用对应工具,重打包则需要使用相同工具的反向功能。重打包在Fuzzing中的核心价值在于:(1)注入测试代码——在文件系统中添加自定义的Fuzzing harness或调试工具;(2)修改配置——开启调试接口、关闭ASLR或修改启动参数;(3)替换二进制——用打了补丁的版本替换目标服务。

重打包的难点在于保持固件结构的一致性。大多数固件使用固定偏移和大小,修改文件系统后可能导致分区大小变化,需要调整固件头中的长度字段。此外,部分固件包含签名校验,重打包后必须绕过或重新签名。

3.3.2 操作流程:以SquashFS为例

以下是一个完整的解包-修改-重打包流程:

  1. 解包:unsquashfs -d ./rootfs ./squashfs.img
  2. 修改文件系统:在./rootfs目录中添加或修改文件。例如,在/etc/init.d/下添加启动脚本,或在/usr/bin/下放置Fuzzing工具。
  3. 重打包:mksquashfs ./rootfs ./new_squashfs.img -comp lzma -b 131072。注意压缩算法和块大小必须与原文件系统一致。
  4. 替换固件中的文件系统:使用dd命令将新文件系统写入原固件偏移处:dd if=new_squashfs.img of=new_firmware.bin bs=1 seek=262144 conv=notrunc。
  5. 修复固件头:如果文件系统大小变化,需要更新固件头中的长度字段。使用hexdump定位并修改。
经验提示:对于包含多个分区的固件,建议使用firmware-mod-kit(FMK)工具包,它提供了extract-firmware.sh和build-firmware.sh脚本,能自动处理分区偏移和大小调整。FMK支持SquashFS、CramFS、JFFS2等常见文件系统。

3.3.3 案例拆解:为路由器固件注入Fuzzing Harness

目标设备是一台运行OpenWrt的智能路由器,固件为openwrt.bin。需要注入一个用于Fuzzing HTTP服务的harness程序。具体步骤如下:

  • 解包:使用FMK的extract-firmware.sh openwrt.bin,输出目录为fmk/rootfs/。
  • 编写harness:在宿主机上编写一个简单的C程序,调用目标HTTP服务的API,并接受外部输入。交叉编译为MIPS架构:mips-linux-gnu-gcc -static -o harness harness.c。
  • 复制harness:将编译好的harness复制到fmk/rootfs/usr/bin/。
  • 修改启动脚本:在fmk/rootfs/etc/rc.local中添加/usr/bin/harness &,确保开机自动运行。
  • 重打包:运行build-firmware.sh,生成新固件openwrt_modified.bin。
  • 刷入设备:通过Web管理界面或TFTP方式刷入新固件,启动后验证harness是否运行。

此案例的关键在于:交叉编译环境必须与目标架构匹配(MIPS、ARM等),且harness应静态编译以避免依赖问题。重打包后需验证固件完整性,避免因分区大小变化导致启动失败。

3.3.4 常见误区与复盘

  • 误区1:重打包后固件无法启动——通常是因为文件系统大小变化导致分区重叠或固件头校验失败。复盘:使用binwalk重新扫描新固件,确认分区偏移正确;使用qemu模拟启动测试。
  • 误区2:忽略签名校验——部分设备在启动时校验固件签名,重打包后签名失效。复盘:提取设备中的公钥,使用openssl dgst -verify验证签名;或使用firmware-mod-kit的签名绕过功能。
  • 误区3:修改文件系统后权限错误——解包后文件属主和权限可能丢失。复盘:使用chown -R root:root和chmod -R 755重置权限,或使用cp -a保留属性。

3.4 固件预处理综合实战与总结

3.4.1 综合案例:从零开始处理一个未知固件

假设收到一个未知固件unknown.bin,大小8MB。完整处理流程如下:

步骤命令/工具预期输出关键决策点
1. 文件类型识别file unknown.bin“data”或“u-boot legacy uImage”若为“data”,需进一步扫描
2. 签名扫描binwalk unknown.bin列出偏移和文件系统类型确认是否存在SquashFS/JFFS2
3. 熵分析binwalk -E unknown.bin熵值曲线图高熵区域可能加密
4. 提取文件系统binwalk -e unknown.bin生成_unknown.bin.extracted/目录检查提取的文件是否完整
5. 解包文件系统unsquashfs -d ./rootfs ./squashfs.img文件系统目录树若失败,尝试sasquatch
6. 分析关键文件ls -la ./rootfs/etc/init.d/启动脚本列表定位网络服务启动项
7. 提取目标二进制file ./rootfs/usr/sbin/httpdELF 32-bit LSB executable, ARM确认架构,准备交叉编译环境

3.4.2 常见误区总结

  • 误区1:跳过熵分析直接解包——若固件加密,解包工具会报错或产生垃圾数据。复盘:始终先执行binwalk -E,若熵值持续接近1.0,则需先解密。
  • 误区2:使用错误架构的工具链——例如用x86工具链处理ARM固件。复盘:使用readelf -h查看ELF头确认架构,再选择对应的交叉编译器。
  • 误区3:重打包后不验证——直接刷入设备导致变砖。复盘:在QEMU中模拟运行新固件,或使用binwalk验证分区结构。
核心要点:固件获取与预处理是Fuzzing的基础工程,其核心能力在于:(1)多渠道获取固件——官网、硬件提取、OTA捕获;(2)准确识别文件系统——binwalk扫描、熵分析、魔数验证;(3)灵活解包与重打包——使用unsquashfs、jefferson、FMK等工具,并处理签名和大小调整。掌握这些技术后,才能为后续的固件模拟执行和Fuzzing测试提供干净、可控的输入。

在实际项目中,建议建立标准化的固件处理流水线,将上述步骤脚本化,并记录每个固件的处理日志(包括偏移、大小、工具版本、修改内容)。这样既能提高效率,也能在出现问题时快速回溯。下一阶段,我们将进入固件模拟执行技术,探讨如何在主机环境中运行提取出的固件,为Fuzzing提供可观测的执行环境。