3、固件获取与预处理:从芯片、开发板、OTA包、官网等途径获取固件,固件格式识别与解包

固件获取是嵌入式逆向工程的起点,其质量与完整性直接决定后续分析的深度与效率。在实际项目中,固件可能以裸二进制(Raw Binary)、Intel HEX、Motorola S-Record、U-Boot镜像、文件系统镜像(如SquashFS、JFFS2、CramFS)、OTA差分包、加密签名包等多种形态存在。本章将系统讲解从芯片引脚、开发板调试接口、OTA升级链路、厂商官网等渠道获取固件的方法,并深入探讨固件格式的识别技巧与解包工具链的使用,帮助读者建立一套可复用的固件预处理工作流。

固件获取与预处理工程链路 获取途径 ① 芯片/板载Flash ② 开发板调试口 ③ OTA升级包 ④ 官网/论坛/固件库 ⑤ 串口/网口导出 ⑥ 逻辑分析仪抓取 (含硬件接口与协议) 预处理核心 ① 格式识别 ② 头部分析/魔数 ③ 熵值检测 ④ 文件系统提取 ⑤ 压缩/加密处理 ⑥ 符号/字符串提取 输出产物 ① 可分析固件镜像 ② 文件系统树 ③ 内核/引导加载器 ④ 配置/密钥/证书 ⑤ 反汇编目标 ⑥ 漏洞分析输入 工具链与关键步骤 硬件读取 - SPI Flash 编程器 - JTAG/SWD 调试器 - 串口 Bootloader - 逻辑分析仪/示波器 格式识别 - binwalk / file - hexdump 头部分析 - 熵值计算 - 字符串搜索 解包提取 - binwalk -e - unsquashfs / jefferson - firmware-mod-kit - 7z / unzip / tar 验证与整理 - 文件系统挂载 - 内核解压(vmlinuz) - 符号表恢复 - 哈希校验

上图展示了固件获取与预处理的完整工程链路。左侧为六种常见获取途径,中间为预处理核心步骤,右侧为最终输出产物,底部则对应各阶段常用的工具链。整个流程强调从物理介质到逻辑文件的逐层抽象,每一步都需要结合硬件知识、文件系统原理与二进制分析技巧。

3.1 固件获取途径与硬件操作要点

3.1.1 核心原理:固件的物理存在形态

固件本质上存储在非易失性存储器中,常见介质包括 SPI NOR Flash、NAND Flash、eMMC、SD卡以及芯片内部OTP/Flash。不同介质对应不同的读取方式:SPI NOR Flash 可通过编程器夹子或插座直接读取;NAND Flash 由于存在坏块管理和页/块结构,读取后需要额外处理;eMMC 则需通过 SD 卡座或 eMMC 转接板读取。对于 MCU 内部 Flash,通常依赖 JTAG/SWD 调试接口或芯片厂商提供的 Bootloader 模式导出。

理解固件的物理布局至关重要。例如,典型的路由器固件在 SPI Flash 中的布局为:Bootloader(U-Boot)→ 内核(Kernel)→ 根文件系统(RootFS)→ 配置分区(NVRAM/Config)。若直接读取整个 Flash,得到的镜像将包含多个逻辑分区,需要后续识别与切割。

3.1.2 操作流程:从硬件到二进制文件

  1. SPI Flash 读取:使用 CH341A、RT809H 等编程器,配合 SOP8/SOP16 测试夹或拆焊后读取。读取前需确认 Flash 型号、电压(3.3V/1.8V)与引脚顺序。读取完成后保存为 .bin 文件,并记录 Flash 容量(如 16MB)。
  2. JTAG/SWD 导出:对于 ARM Cortex-M/A 系列芯片,使用 OpenOCD + FT2232H 调试器,通过 flash read_bank 0 firmware.bin 命令导出内部 Flash 内容。需注意芯片是否锁定调试端口(读保护)。
  3. OTA 包捕获:在设备升级时,通过代理工具(如 Burp Suite、Fiddler)拦截 HTTPS 请求,或搭建本地升级服务器,获取固件下载链接。OTA 包常为 .tar.gz、.zip、.bin 或自定义格式,需进一步解包。
  4. 官网/论坛收集:厂商官网的“支持/下载”页面、GitHub Releases、第三方固件社区(如 OpenWrt、DD-WRT)是重要来源。注意核对固件版本、硬件版本(HW Ver)与地区码。
  5. 串口导出:部分设备 U-Boot 提供 loadb、tftp 命令,可通过串口或网口将内存中的固件导出。例如在 U-Boot 提示符下执行 md 0x80000000 0x10000 查看内存,再用 mw 配合 tftp 上传。
经验提醒:读取 SPI Flash 前务必确认电压与引脚接触良好,避免短路损坏芯片。对于 NAND Flash,建议先读取坏块标记(Bad Block Table),否则解包后文件系统可能损坏。使用编程器时,优先选择“完整读取”而非“快速读取”,确保数据完整性。

3.1.3 案例拆解:从智能插座提取固件

某智能插座采用 ESP8266 模组,固件存储在 2MB SPI Flash 中。初始现象:设备无法通过官方 App 升级,需要提取固件进行漏洞分析。操作过程如下:

  • 拆开外壳,找到 PCB 上的 25Q16 芯片(2MB SPI NOR Flash)。
  • 使用 CH341A 编程器配合 SOP8 测试夹,连接 MOSI、MISO、CLK、CS、VCC、GND 引脚。
  • 读取 Flash 内容保存为 smartplug_full.bin,大小 2,097,152 字节。
  • 使用 binwalk smartplug_full.bin 扫描,发现偏移 0x0 处为 Bootloader,0x1000 处为固件头部,0x100000 处为文件系统。
  • 提取后得到三个独立文件,进一步分析发现固件未加密,但包含硬编码的 Wi-Fi 密码与云平台 。

复盘:该案例中,由于 Flash 容量小且未启用加密,直接读取即可获得完整固件。若遇到加密固件,则需结合芯片数据手册查找 AES 密钥存储位置或利用 Bootloader 漏洞绕过校验。

3.1.4 常见误区与总结

  • 误区一:认为所有固件都是单个 .bin 文件。实际上,许多设备使用 U-Boot + FIT 镜像或自定义容器格式,需先解析头部。
  • 误区二:忽略 Flash 的字节序与位序。SPI Flash 通常为 MSB 优先,但某些 MCU 内部 Flash 可能采用 LSB 优先,读取后需字节交换。
  • 误区三:OTA 包直接解压后即为完整文件系统。OTA 包可能包含元数据、签名、差分包,需先验证签名并还原完整镜像。
风险提示:拆焊 Flash 芯片存在损坏 PCB 焊盘的风险,建议优先使用测试夹。对于 BGA 封装的 eMMC,需使用专用座子或热风枪拆焊,操作不当可能导致设备永久损坏。此外,读取他人设备固件时需遵守当地法律法规,仅用于授权测试或学习研究。

3.2 固件格式识别与解包技术

3.2.1 核心原理:魔数、熵与文件系统特征

固件格式识别的核心在于寻找“魔数”(Magic Number)——文件头部的特定字节序列。例如,U-Boot 镜像以 27 05 19 56 开头;SquashFS 文件系统以 hsqs(0x68737173)开头;JFFS2 以 85 19 开头;gzip 压缩数据以 1F 8B 开头。此外,熵值(Entropy)分析可判断数据是否加密或压缩:高熵值(接近 8.0)通常表示加密或压缩数据,低熵值(低于 6.0)则可能是明文代码或未压缩数据。

文件系统识别还需关注其超级块(Superblock)中的魔数与版本信息。例如,CramFS 的魔数为 0x28CD3D45,SquashFS 的魔数为 0x73717368(小端序)。通过 file 命令可快速识别已知格式,但自定义格式需手动分析。

3.2.2 操作流程:使用 binwalk 与手动分析

# 1. 基础扫描
binwalk firmware.bin

# 2. 详细扫描(包含熵分析)
binwalk -E firmware.bin

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

# 4. 手动查看头部
hexdump -C firmware.bin | head -20

# 5. 搜索字符串
strings -n 8 firmware.bin | grep -i "squashfs\|uboot\|kernel"

当 binwalk 无法识别时,需手动分析:

  1. 使用 hexdump 查看文件头部 256 字节,寻找可读字符串或规律性结构。
  2. 计算分段熵值,定位高熵区域(加密/压缩)与低熵区域(代码/数据)。
  3. 尝试常见文件系统偏移:SquashFS 通常从 0x100000 或 0x200000 开始,JFFS2 从 0x1F0000 开始。
  4. 使用 dd 命令按偏移切割镜像,再对切割后的文件进行识别。

3.2.3 案例拆解:识别并解包某 IP 摄像头的未知固件

某 IP 摄像头固件 ipcam_fw.bin 大小为 8MB,binwalk 扫描无结果。初始现象:文件头部为 00 00 00 00,无任何魔数。分析过程:

  • 使用 binwalk -E 发现文件前 1MB 熵值约为 5.5,后 7MB 熵值约为 7.9,推测前段为 Bootloader 或未压缩代码,后段为压缩/加密数据。
  • 在偏移 0x100000 处发现字符串 hsqs,确认存在 SquashFS 文件系统。
  • 使用 dd if=ipcam_fw.bin of=rootfs.squashfs bs=1 skip=1048576 count=7340032 提取文件系统。
  • 使用 unsquashfs rootfs.squashfs 成功解包,得到完整的 Linux 根文件系统,包含 /bin、/etc、/usr 等目录。

复盘:该案例中,固件头部被厂商自定义的 1MB 引导代码填充,导致 binwalk 无法自动识别。通过熵值分析定位高熵区域,再结合字符串搜索,成功找到文件系统偏移。此方法适用于大多数“伪装”固件。

3.2.4 常见误区与总结

  • 误区一:完全依赖 binwalk 自动提取。binwalk 对未知格式或加密固件无效,需结合手动分析。
  • 误区二:忽略文件系统对齐。SquashFS 通常按 4KB 对齐,偏移可能为 0x1000 的倍数,切割时需注意。
  • 误区三:混淆大小端。ARM 小端设备与 MIPS 大端设备的文件系统魔数可能不同,需根据架构调整。
核心工具清单:
工具用途典型命令
binwalk固件扫描与提取binwalk -e firmware.bin
file识别已知文件类型file rootfs.squashfs
hexdump查看二进制头部hexdump -C -n 256 firmware.bin
unsquashfs解包 SquashFSunsquashfs -d ./rootfs rootfs.squashfs
jefferson解包 JFFS2jefferson rootfs.jffs2
firmware-mod-kit自动化固件解包/重打包./extract-firmware.sh firmware.bin
7z解压常见压缩格式7z x firmware.tar.gz

3.3 固件预处理:从原始镜像到可分析目标

3.3.1 核心原理:分区切割与文件系统挂载

获取的原始固件通常包含多个逻辑分区,预处理的目标是将这些分区分离,并转换为可挂载、可浏览的文件系统。对于 Linux 设备,常见分区包括:Bootloader、Kernel(zImage/uImage)、RootFS(SquashFS/EXT4/JFFS2)、Config(NVRAM/UBI)。切割后,RootFS 可通过 mount -o loop 挂载(需内核支持),或使用 unsquashfs 等工具直接解包。

对于 NAND Flash 设备,还需处理 OOB(Out-of-Band)数据与坏块标记。通常使用 nanddump 工具读取时自动跳过坏块,但若手动读取,需在预处理阶段过滤 OOB 区域。

3.3.2 操作流程:标准化预处理步骤

  1. 镜像完整性校验:计算 SHA-256 哈希,与官方发布值比对(如有)。
  2. 分区扫描与切割:使用 binwalk 或手动分析确定各分区偏移与大小,用 dd 切割。
  3. 内核解压:若内核为 uImage,使用 mkimage -l 查看信息,再用 dd 跳过 64 字节头部提取 vmlinuz,最后用 zcat 或 lzma -d 解压。
  4. 文件系统解包:根据类型选择工具,如 SquashFS 用 unsquashfs,JFFS2 用 jefferson,EXT4 用 mount -o loop。
  5. 符号与配置提取:从解包后的文件系统中提取 /etc/passwd、/etc/shadow、Web 配置文件、SSL 证书、私钥等敏感信息。

3.3.3 案例拆解:某企业级 AP 固件的完整预处理

某企业级无线 AP 固件 ap_fw.bin 大小 32MB,目标为提取 Web 管理后台的源码与默认凭据。操作过程:

  • binwalk 扫描发现:0x0 为 U-Boot,0x80000 为 LZMA 压缩内核,0x200000 为 SquashFS,0x1A00000 为 JFFS2 配置分区。
  • 使用 dd 切割出内核与两个文件系统。
  • 解压内核后,使用 vmlinux-to-elf 工具将 vmlinuz 转换为 ELF 文件,便于 Ghidra 分析。
  • 解包 SquashFS 后,在 /www 目录找到 CGI 脚本与 JavaScript 文件,发现存在命令注入漏洞。
  • 在 JFFS2 配置分区中找到默认管理员密码的 MD5 哈希,通过彩虹表破解。

复盘:该案例体现了预处理对后续漏洞挖掘的关键作用。通过分区切割与文件系统解包,不仅获得了可分析的源码,还提取了敏感配置。若跳过预处理直接分析整个 .bin 文件,将难以定位具体代码模块。

3.3.4 常见误区与总结

  • 误区一:忽略 U-Boot 环境变量。U-Boot 的 env 分区可能包含启动参数、内存布局等关键信息,需单独提取。
  • 误区二:未处理文件系统权限。解包后的文件可能保留原始 UID/GID,在宿主机上浏览时需使用 root 权限或映射用户。
  • 误区三:忘记检查固件更新包中的版本信息。同一设备不同版本的固件,其分区布局可能不同,需以目标版本为准。
经验总结:固件预处理的核心是“分层剥离”——从物理镜像到逻辑分区,再到文件系统,最后到具体文件。每一步都应记录偏移、大小、类型等元数据,形成一份“固件分析报告”,为后续逆向工程提供地图。建议使用 tree 命令生成解包后的目录树,并保存 binwalk 扫描日志,便于回溯。