4. 物联网固件分析基础:固件结构、文件系统提取、二进制分析入门
做物联网安全,绕不开固件分析。说白了,你得先知道设备里跑的是什么,才能谈得上管理它的 SBOM。我见过太多团队,拿着 SBOM 工具直接扫,结果扫出一堆乱码——为什么?因为连固件都没解开,工具根本读不到文件系统。
这一章,我们就从最基础的固件结构讲起,手把手带你完成文件系统提取,再聊聊二进制分析的入门套路。嗯,都是我在项目里踩过坑之后总结出来的经验。
4.1 固件到底是什么?
固件,就是设备的操作系统加上应用程序的打包体。它通常包含 Bootloader、内核、文件系统、配置参数这几大块。我刚开始做分析时,以为固件就是个 bin 文件,直接 binwalk 一把梭就行。后来发现,事情没那么简单。
固件典型结构(以嵌入式 Linux 为例):
- Bootloader:引导程序,如 U-Boot、RedBoot
- Kernel:Linux 内核,通常是 zImage 或 uImage
- RootFS:根文件系统,常见格式有 SquashFS、JFFS2、YAFFS2、CramFS
- 配置分区:存储 MAC 地址、序列号、校准参数等
- 应用程序:设备业务逻辑,Web 服务、协议栈等
你想想看,如果连固件里有哪些分区都不清楚,SBOM 的扫描范围就是盲目的。我曾经接手过一个项目,客户说固件是完整的,结果 binwalk 一跑,发现文件系统被加密了——白忙活半天。
4.2 固件结构可视化
为了让你更直观地理解固件布局,我画了一张结构图。这张图基本覆盖了大多数物联网设备的固件组成。
4.3 文件系统提取实战
提取文件系统是固件分析的核心步骤。没有文件系统,你就看不到设备里的配置文件、二进制程序、库文件——SBOM 也就无从谈起。
4.3.1 常用工具
| 工具 | 用途 | 个人评价 |
|---|---|---|
| binwalk | 固件扫描、分区识别、文件提取 | 入门必备,但别全信它 |
| dd | 手动切割固件分区 | 老派但可靠,我经常用它 |
| unsquashfs | 解压 SquashFS 文件系统 | SquashFS 的标配工具 |
| jefferson | 解压 JFFS2 文件系统 | JFFS2 专用,比 binwalk 稳 |
| firmware-mod-kit | 固件解包/打包一体化 | 适合批量处理,但有些旧 |
4.3.2 标准提取流程
我个人习惯的流程是这样的:
- 先看文件头:
file firmware.bin,确认固件类型 - 扫描分区:
binwalk -Me firmware.bin,自动递归提取 - 检查结果:进入
_firmware.bin.extracted目录,看有没有文件系统 - 手动修正:如果 binwalk 没识别出来,用
dd手动切割 - 解压文件系统:根据格式选择 unsquashfs 或 jefferson
小技巧: 我建议你在提取前先用 hexdump -C firmware.bin | head -50 看一眼固件头部。很多固件会在头部明文写分区偏移和大小,比 binwalk 还准。
4.3.3 代码示例:手动提取 SquashFS
有一次我遇到一个固件,binwalk 死活识别不出文件系统。后来我手动找到了 SquashFS 的魔数 hsqs,用 dd 切出来的。代码是这样的:
# 查找 SquashFS 魔数偏移
grep -oba "hsqs" firmware.bin
# 假设偏移是 0x1a0000,大小是 0x800000
dd if=firmware.bin bs=1 skip=$((0x1a0000)) count=$((0x800000)) of=rootfs.squashfs
# 解压
unsquashfs -d rootfs rootfs.squashfs
嗯,这里要注意:skip 和 count 的单位是字节,别搞错了。我曾经因为单位写错,解出来一堆乱码,排查了半天才发现是偏移算错了。
4.4 二进制分析入门
文件系统提取出来之后,下一步就是分析里面的二进制文件。这部分是 SBOM 生成的关键——你得知道固件里用了哪些库、哪些版本、有没有已知漏洞。
4.4.1 识别二进制文件类型
拿到一个二进制文件,第一件事就是看它是什么架构的。用 file 命令就够了:
file /rootfs/usr/sbin/httpd
# 输出示例:
# /rootfs/usr/sbin/httpd: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 2.6.16, stripped
看到 ARM、MIPS、stripped 这些关键词了吗?这些信息直接决定了你后续用什么工具分析。
4.4.2 字符串分析
字符串分析是最快了解二进制文件功能的方法。我习惯用 strings 配合 grep:
strings /rootfs/usr/sbin/httpd | grep -i "version\|build\|compile\|gcc\|openssl\|libc"
这样能快速找到软件版本、编译工具链、依赖库等信息。这些就是 SBOM 的原始素材。
注意: 如果二进制文件被 strip 过,符号表会被删除,但字符串通常还在。不过有些固件会加密或混淆字符串,这时候 strings 就不好使了。我曾经遇到过一个设备,所有字符串都是 XOR 加密的,最后只能靠动态调试才拿到明文。
4.4.3 依赖库分析
动态链接的二进制文件会依赖一堆 .so 库。用 readelf 或 ldd 可以查看:
readelf -d /rootfs/usr/sbin/httpd | grep NEEDED
# 输出示例:
# 0x00000001 (NEEDED) Shared library: [libssl.so.1.0.0]
# 0x00000001 (NEEDED) Shared library: [libcrypto.so.1.0.0]
# 0x00000001 (NEEDED) Shared library: [libc.so.6]
看到 libssl.so.1.0.0 了吗?OpenSSL 1.0.0 系列有很多已知漏洞,比如 Heartbleed。这就是 SBOM 要记录的关键信息。
4.4.4 版本号提取
版本号是 SBOM 的核心字段。提取方法有几种:
- strings 搜索:
strings libssl.so | grep -E "^[0-9]+\.[0-9]+\.[0-9]+" - 查看符号表:
nm -D libssl.so | grep version - 动态分析:在 QEMU 模拟环境中运行,查看版本输出
避坑指南: 我曾经在分析一个路由器固件时,strings 搜出来的版本号是 1.0.2,但实际漏洞库匹配的是 1.0.1。后来发现是厂商自己改了版本字符串,但代码还是 1.0.1 的。所以,版本号不能只看字符串,最好结合哈希校验或漏洞特征码来确认。
4.5 本章小结
固件分析是 SBOM 管理的地基。你只有把固件拆开、把文件系统提取出来、把二进制文件里的依赖和版本信息挖出来,才能生成一份靠谱的 SBOM。我见过太多人跳过这一步,直接拿工具扫,结果扫出来的 SBOM 全是错的——那还不如不做。
记住三个关键点:
- 先看结构:用 binwalk 或手动分析固件分区
- 再提文件系统:根据格式选对工具,必要时手动切割
- 最后挖二进制:strings、readelf、nm 三板斧,把版本和依赖揪出来