第三章:固件提取与解包
固件分析的第一步,说白了就是拿到固件,然后把它拆开。这一步做不好,后面所有分析都是空中楼阁。我见过太多人卡在这一步,明明固件就在眼前,就是打不开。今天咱们就把这事彻底聊透。
3.1 固件获取途径
固件从哪来?这个问题看似简单,实际门道不少。我总结了几条主要渠道:
- 官方渠道下载:厂商官网、FTP服务器、GitHub releases。这是最正规的途径,但要注意版本匹配。
- 设备备份提取:通过串口、JTAG、SPI Flash编程器直接读取。我在项目中遇到过,有些设备根本不提供固件下载,只能硬读。
- OTA抓包:用Wireshark抓取升级流量,分析HTTP/FTP/TFTP协议。嗯,这里要注意,有些固件是加密传输的。
- 第三方聚合站:比如OpenWrt、DD-WRT社区,或者一些安全研究者的公开仓库。
个人经验:我建议优先走官方渠道。有一次我图省事从第三方站点下载固件,结果里面被人植入了后门。从那以后,我每次都会校验MD5/SHA256。
3.2 Binwalk固件扫描与提取
Binwalk是固件分析的瑞士军刀。它通过特征签名识别固件中的文件系统、压缩包、引导加载程序等。我个人习惯先用它扫一遍,看看固件里到底藏了什么。
3.2.1 基本扫描
# 扫描固件中的文件签名
binwalk firmware.bin
# 递归扫描,显示详细信息
binwalk -Me firmware.bin
# 只显示已知签名
binwalk -B firmware.bin
输出结果会告诉你:偏移地址、文件类型、描述。比如看到Squashfs文件系统、LZMA压缩数据、U-Boot镜像等。
3.2.2 自动提取
# 自动提取所有识别到的文件
binwalk -e firmware.bin
# 提取并递归解包
binwalk -Me firmware.bin
# 指定提取目录
binwalk -e -C ./output firmware.bin
避坑指南:我曾经遇到一个固件,Binwalk扫描显示有Squashfs,但提取出来却是空的。后来发现是固件头部有自定义魔数,Binwalk没识别到真正的偏移。解决办法是手动指定偏移量。
3.2.3 高级用法
# 提取特定偏移和大小的数据
binwalk -D 'squashfs:0:0' firmware.bin
# 使用熵分析识别加密或压缩区域
binwalk -E firmware.bin
# 生成熵图
binwalk -e -E firmware.bin
熵分析特别有用。如果某段数据的熵值接近1.0,说明它很可能是加密或压缩过的。我经常用这个来判断固件是否被混淆。
3.3 手动解包
Binwalk不是万能的。有些固件用了非标准格式,或者被故意混淆,这时候就得手动来。我把它分成三种常见情况:
3.3.1 dd命令:精准切割
dd是Linux下的数据复制工具,但它的精髓在于精准定位。你想想看,固件里可能混着多个文件系统,你得知道每个部分的起始和结束位置。
# 从偏移0x100000处提取128KB数据
dd if=firmware.bin of=part1.bin bs=1 skip=$((0x100000)) count=$((128*1024))
# 提取从0x200000到0x400000的数据
dd if=firmware.bin of=part2.bin bs=1 skip=$((0x200000)) count=$((0x200000))
# 跳过头部,提取剩余所有
dd if=firmware.bin of=rest.bin bs=1 skip=$((0x50000))
个人技巧:我习惯先用hexdump或010 Editor查看固件头部,找到文件系统的魔数(比如Squashfs的"hsqs"),然后计算偏移。这样比盲目猜测准确得多。
3.3.2 cpio:老牌归档格式
cpio在嵌入式Linux中很常见,尤其是initramfs。它的结构简单,但有时候会被压缩。
# 解压cpio归档
cpio -idmv < initramfs.cpio
# 如果被gzip压缩,先解压
gunzip -c initramfs.cpio.gz | cpio -idmv
# 查看cpio内容但不解压
cpio -itv < initramfs.cpio
为什么用cpio?因为它支持硬链接和特殊文件,tar有时候会丢失这些信息。我在分析一个路由器固件时,发现它的文件系统就是cpio格式,用tar解出来全是乱码。
3.3.3 Squashfs:嵌入式最爱
Squashfs是嵌入式Linux最常用的只读文件系统。它压缩率高,支持大文件。但不同版本的工具不兼容,这是个坑。
# 安装工具
sudo apt-get install squashfs-tools
# 解压Squashfs文件系统
unsquashfs rootfs.squashfs
# 查看信息而不解压
unsquashfs -s rootfs.squashfs
# 指定解压目录
unsquashfs -d ./extracted rootfs.squashfs
注意:Squashfs有多个版本(v3、v4、v4.2等)。我曾经用v4工具去解v3的镜像,结果报错。后来发现需要安装squashfs-tools-legacy版本。建议先用unsquashfs -s查看版本信息。
3.4 常见文件系统分析
除了上面几种,嵌入式固件里还会遇到其他文件系统。我整理了一个表格:
| 文件系统 | 特征魔数 | 常见用途 | 解包工具 |
|---|---|---|---|
| Squashfs | hsqs / sqsh | 只读根文件系统 | unsquashfs |
| Cramfs | 0x28cd3d45 | 老式只读系统 | cramfsck / cramfsswap |
| JFFS2 | 0x1985 | NAND Flash | jefferson / jffs2dump |
| YAFFS2 | 无固定魔数 | NAND Flash | unyaffs / yaffs2utils |
| UBIFS | UBI# | MLC NAND | ubireader / ubi_reader |
| ext2/3/4 | 0xEF53 | 通用Linux | mount / debugfs |
识别文件系统类型,我一般三步走:
- 用Binwalk扫描,看它识别出什么
- 用hexdump查看魔数,手动确认
- 用对应工具尝试解包,不行就换
核心思路:固件解包的本质是「定位-切割-解压」。不管用什么工具,你都得先知道数据从哪里开始、是什么格式。我建议新手先学会用hexdump和dd,这两个工具能解决80%的问题。
3.5 知识体系结构图
下面这张图概括了本章的核心逻辑:
嗯,这张图把整个流程串起来了。从固件获取开始,到Binwalk扫描,再到手动解包,最后落到文件系统分析。每一步都有对应的工具和方法。
最后说一句:固件解包没有银弹。我见过用Binwalk一把梭成功的,也见过花三天手动分析才解开的。关键是理解底层原理,而不是死记命令。你想想看,如果连文件系统魔数都不认识,工具报错你都不知道怎么修。