固件逆向基础:提取、解包与文件系统分析

各位同学,欢迎来到第二章。上一章我们聊了固件安全的整体威胁模型,今天咱们要动真格的了——把固件从芯片里“请”出来,拆开看看里面到底装了些什么。

我经常跟团队里新人说一句话:你连固件都拿不到,谈什么逆向? 提取是第一步,也是最容易踩坑的一步。我自己早年做第一个路由器漏洞挖掘时,就因为没注意SPI Flash的电压问题,连续烧了三块开发板……嗯,从那以后我养成了先看datasheet再动手的习惯。

本章核心目标:掌握从硬件和软件两个维度获取固件的方法,学会解包/打包常见固件格式,并能独立分析文件系统结构。

2.1 固件提取技术

固件提取,说白了就是把二进制镜像从存储介质里读出来。根据你的目标设备不同,手段也完全不一样。我把它分成两大类:硬件提取和软件提取。

2.1.1 硬件提取:直接与芯片对话

当设备没有开放调试接口、固件更新包又加密时,硬件提取往往是唯一出路。最常见的场景就是嵌入式设备上的SPI Flash或NAND Flash。

常用工具清单:

工具 适用场景 个人评价
CH341A编程器 SPI Flash(8脚/16脚) 便宜好用,入门首选,但速度慢
树莓派 + flashrom SPI Flash在线读取 灵活,适合现场快速提取
JTAG/SWD调试器 MCU内部Flash 需要找到调试引脚,有时得刮漆
NAND读取器 NAND Flash(BGA封装) 贵,但遇到大容量存储必须上

我个人习惯先用flashrom配合树莓派做SPI Flash提取。为什么?因为不用拆焊芯片,直接在电路板上夹住引脚就能读。但要注意——目标设备必须断电,否则轻则读错数据,重则烧掉IO口。

避坑指南:我曾经遇到过一块看似正常的SPI Flash,读出来的数据校验总是失败。折腾了半天才发现,是夹子接触不良导致某根数据线虚接。后来我养成了习惯:每次读取前先用万用表测一遍引脚通断。

2.1.2 软件提取:从系统内部下手

如果设备已经跑起来了,或者你能拿到固件更新包,那软件提取就省事多了。常见途径包括:

  • 固件更新包抓取:用Wireshark抓OTA升级流量,或者从SD卡/USB升级文件里直接提取.bin文件
  • /dev/mem或/dev/flash:在已root的设备上,直接dd整个Flash分区
  • Bootloader交互:通过U-Boot的md命令或fastboot协议读取内存
  • 调试串口:在系统启动时中断进入uboot shell,用sf read命令导出

举个例子,我在分析某款IP摄像头时,发现它的固件更新包是个加密的.bin文件。但通过抓取串口启动日志,我找到了uboot环境变量里存储的解密密钥——这就是典型的“硬件泄露软件秘密”案例。

2.2 固件解包与打包

拿到原始二进制文件后,下一步就是把它拆开。固件通常不是单一的文件,而是由Bootloader、内核、文件系统、配置分区等多个部分拼接而成。

2.2.1 识别固件结构

我一般先用binwalk做快速扫描。这个工具能自动识别固件里嵌入的文件系统和压缩数据。

# 基本扫描
binwalk firmware.bin

# 递归扫描并提取
binwalk -Me firmware.bin

# 查看熵值,判断是否加密
binwalk -E firmware.bin

输出结果会告诉你:偏移地址、文件类型、大小。比如看到“Squashfs filesystem, little endian”这样的标记,就说明文件系统找到了。

注意:binwalk不是万能的。如果固件头部被篡改或加密,它可能什么都识别不出来。这时候我会手动用hexdump或010 Editor查看文件头特征——比如U-Boot的“uImage”头以“27051956”开头,这是经验活。

2.2.2 常用解包工具

工具 用途 命令示例
binwalk 自动识别与提取 binwalk -Me firmware.bin
unsquashfs 解压SquashFS unsquashfs rootfs.squashfs
jefferson 解压JFFS2 jefferson rootfs.jffs2
ubireader 解压UBIFS ubireader_extract_images firmware.bin
firmware-mod-kit 解包/打包一体化 ./extract-firmware.sh firmware.bin

说到打包,很多同学只解不解,改完东西装不回去。我建议你从一开始就养成习惯:解包前先备份原始固件,并记录每个分区的偏移和大小。打包时用mksquashfs或ubinize重新生成,再用dd拼回完整镜像。

# 重新打包SquashFS示例
mksquashfs extracted_rootfs/ new_rootfs.squashfs -comp xz -b 131072

# 拼回完整固件
dd if=bootloader.bin of=new_firmware.bin bs=1 conv=notrunc
dd if=kernel.bin of=new_firmware.bin bs=1 seek=0x80000 conv=notrunc
dd if=new_rootfs.squashfs of=new_firmware.bin bs=1 seek=0x300000 conv=notrunc

个人经验:我曾经在打包时忘了对齐分区边界,结果刷进去后内核能启动,但文件系统挂载失败。折腾了两天才发现是偏移地址没对齐到Flash的擦除块大小(通常是64KB或128KB)。记住:分区偏移必须是擦除块大小的整数倍。

2.3 固件文件系统分析

文件系统是固件里最“有料”的部分。Web服务、二进制程序、配置文件、脚本……漏洞往往就藏在这些文件里。

2.3.1 常见嵌入式文件系统

类型 特点 常见设备
SquashFS 只读、高压缩比 路由器、摄像头
JFFS2 可写、支持NAND Flash 老旧嵌入式设备
UBIFS 新一代、支持大容量NAND 高端路由器、IoT网关
CramFS 古老、已淘汰 早期Linux设备
initramfs 内存文件系统 临时启动环境

解包完成后,我通常会按以下顺序做初步分析:

  1. 查看/etc/passwd和/etc/shadow——找硬编码密码或弱哈希
  2. 检查/etc/init.d/或/etc/rc.d/——看启动脚本里有没有可疑服务
  3. 搜索/bin和/usr/bin下的二进制文件——用file命令确认架构,用strings找敏感字符串
  4. 查看Web目录(/www、/htdocs等)——找后门、硬编码Token、命令注入点
  5. 检查/lib和/usr/lib下的动态库——看有没有过时的OpenSSL或libcurl版本

一个实用技巧:用grep -r "password\|secret\|token\|admin" extracted_rootfs/快速扫描硬编码凭据。我在某款智能门锁的固件里,就靠这行命令找到了一个硬编码的API密钥——厂商居然把它写死在/lib/libauth.so里。

2.3.2 文件系统结构图

下面这张图展示了典型嵌入式Linux固件的文件系统层次,以及各目录在安全分析中的关注点。

嵌入式固件文件系统分析结构图 嵌入式固件文件系统分析结构图 / (根文件系统) /bin /sbin /etc /usr /lib busybox / dropbear passwd / shadow / config init.d / rc.d 启动脚本 /www / /cgi-bin Web服务 /lib 动态库 / 内核模块 🔍 安全分析关注点 • /bin: 检查是否有telnetd、调试shell等后门程序 • /etc: 硬编码密码、弱SSH密钥、不安全的默认配置 • /www: 命令注入、文件包含、未授权访问 • /lib: 过时库版本、已知CVE漏洞 分析顺序建议:/etc → /www → /bin → /lib → 启动脚本 /tmp (运行时数据) /var (日志/缓存) ← 这两个目录在运行时才有内容,静态分析时为空

2.4 本章小结

这一章我们走完了固件逆向的“三板斧”:提取、解包、分析。你想想看,从一块芯片上的二进制数据,到能逐行阅读的源代码和配置文件,这个过程本身就是一种“破解”的快感。

最后提醒一句:拿到固件只是开始,不是结束。下一阶段我们要在这些文件里“挖洞”——但那是后面章节的事了。今天的内容,足够你回去拿手边的路由器练练手了。

课后练习建议:找一个开源路由器的固件(比如OpenWrt或DD-WRT),用binwalk解包后,尝试找到Web管理界面的登录页面文件,看看有没有硬编码的测试账号。我当年第一次做这个练习时,就在一个厂商的固件里找到了“admin:admin”的备份账号——他们居然忘了删掉。