2. 固件提取与镜像分析

固件安全工程师的第一项硬功夫,是把目标设备里的固件“完整、可复现”地取出来。取不到镜像,后面的漏洞挖掘、后门排查、签名校验分析都无从谈起。本节围绕三类主流存储介质——SPI Flash、eMMC、UFS——讲清楚它们的读取路径,并用binwalk与firmware-mod-kit完成一次从原始镜像到可读文件系统的拆解。

一、先判断介质类型,再决定读取方式

拿到一块路由器、摄像头或工控板,第一步不是直接上夹子,而是确认存储介质。SPI Flash通常是8脚或16脚的小芯片,容量1MB~32MB,常见型号如W25Q128、MX25L256;eMMC是BGA封装,容量4GB~64GB,走MMC协议;UFS同样是BGA,但走M-PHY/UniPro,容量更大、速度更快,常见于手机和高端车机。判断依据有三点:芯片丝印、主控手册、以及PCB上是否有eMMC/UFS的专用供电与时钟走线。

介质不同,读取策略完全不同。SPI Flash可以离线读取,也可以在线读取;eMMC/UFS通常需要设备进入可访问状态,或直接拆焊后用专用编程器读取。面试中常被追问“为什么eMMC不能像SPI那样随便夹”,答案在于eMMC的BGA焊球间距小、信号完整性要求高,飞线极易导致读取失败或损坏芯片。

二、SPI Flash读取:离线与在线两条路

离线读取是最稳妥的方式。用热风枪拆下SPI Flash,放入编程器(如CH341A、RT809H),选择对应型号后读取。以W25Q128为例,容量16MB,读取命令如下:

flashrom -p ch341a_spi -r firmware.bin
flashrom -p ch341a_spi -w firmware.bin

读取完成后必须校验:连续读两次,用sha256sum比对哈希值。若两次不一致,说明接触不良或芯片老化,需要重新读取。在线读取则通过SPI总线夹子(如SOIC8夹)在设备通电状态下读取,优点是无需拆焊,缺点是主控可能干扰总线,导致读取数据不完整。判断依据是:读取后binwalk能识别出文件系统,且哈希稳定。

三、eMMC与UFS读取:从设备节点到镜像

eMMC在Linux下通常表现为/dev/mmcblk0,UFS表现为/dev/sda或/dev/ufs0。如果设备能进入系统或恢复模式,直接dd即可:

dd if=/dev/mmcblk0 of=emmc_full.bin bs=1M conv=noerror,sync
dd if=/dev/sda of=ufs_full.bin bs=1M conv=noerror,sync

关键参数是conv=noerror,sync,遇到坏块时用零填充并继续,避免中断。读取后检查分区表:

fdisk -l emmc_full.bin
parted emmc_full.bin unit B print

如果设备无法进入系统,就需要拆焊后用专用编程器(如Easy JTAG Plus、UFI Box)读取。UFS读取还需要注意LUN配置,因为UFS通常有多个逻辑单元,需要分别读取。面试中常考“eMMC的boot分区怎么读”,答案是/dev/mmcblk0boot0和/dev/mmcblk0boot1,这两个分区存放一级引导程序,往往包含关键密钥。

四、binwalk实战:从原始镜像到文件系统

拿到镜像后,先用binwalk做签名扫描:

binwalk firmware.bin

典型输出会显示Squashfs、JFFS2、UBI、gzip等签名及其偏移。例如:

DECIMAL       HEXADECIMAL     DESCRIPTION
0             0x0             uImage header
64            0x40            LZMA compressed data
131072        0x20000         Squashfs filesystem, little endian

看到Squashfs后,用binwalk -e firmware.bin自动提取。若自动提取失败,可手动指定偏移:

dd if=firmware.bin of=squashfs.img bs=1 skip=131072
unsquashfs squashfs.img

提取出的squashfs-root就是完整的根文件系统。此时重点检查/etc/passwd、/etc/shadow、/etc/init.d/、/usr/bin/,寻找硬编码凭据、启动脚本和可疑二进制。

五、firmware-mod-kit:拆解与重打包

firmware-mod-kit适合处理带有多层封装的固件。以extract-firmware.sh为例:

./extract-firmware.sh firmware.bin

它会自动识别uImage、Squashfs、Cramfs等,并输出到fmk/目录。拆解后可在fmk/rootfs/中修改文件,再用build-firmware.sh重打包。重打包时要注意:如果原固件有签名校验,修改后无法启动,此时需要先分析签名机制,或寻找未签名分区。

一个常见教学示例:某路由器固件拆解后,在/etc/init.d/rcS中发现telnetd -l /bin/sh,说明存在调试后门。修改该文件后重打包,若设备能启动且telnet可连,说明签名校验未覆盖该分区。若无法启动,则需进一步分析bootloader的校验逻辑。

六、结果判断与常见陷阱

判断提取是否成功,有三个标准:一是binwalk能识别出至少一个文件系统;二是unsquashfs或mount能正常挂载;三是文件系统内文件数量与预期相符。常见陷阱包括:SPI Flash在线读取时主控干扰导致数据错位;eMMC读取时未处理坏块导致镜像截断;UFS多LUN未全部读取导致遗漏关键分区;binwalk自动提取时因偏移错误提取出损坏文件系统。

最后给出一份可执行的检查清单,供实际工作时逐项核对:

检查项操作判断依据
介质确认查看丝印与主控手册SPI/eMMC/UFS型号明确
读取完整性连续读两次比对哈希哈希一致
分区识别fdisk/parted查看分区表分区偏移与大小合理
文件系统提取binwalk -e或手动dd+unsquashfs能挂载且文件完整
敏感文件排查检查passwd、shadow、init.d发现硬编码凭据或后门
重打包验证build-firmware.sh后刷入设备能启动且修改生效