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 固件结构可视化

为了让你更直观地理解固件布局,我画了一张结构图。这张图基本覆盖了大多数物联网设备的固件组成。

物联网固件典型结构图 固件二进制文件(.bin / .img) Bootloader U-Boot / RedBoot Kernel zImage / uImage RootFS SquashFS / JFFS2 配置分区 MAC / 序列号 / 校准参数 应用程序 Web 服务 / 协议栈 / 业务逻辑 说明: • 不同设备固件布局可能不同,部分固件会加密或压缩整个分区 • 有些固件将 Kernel 和 RootFS 合并为一个分区(如 TRX 格式) • 分析前建议先用 file 命令查看固件头部信息

4.3 文件系统提取实战

提取文件系统是固件分析的核心步骤。没有文件系统,你就看不到设备里的配置文件、二进制程序、库文件——SBOM 也就无从谈起。

4.3.1 常用工具

工具 用途 个人评价
binwalk 固件扫描、分区识别、文件提取 入门必备,但别全信它
dd 手动切割固件分区 老派但可靠,我经常用它
unsquashfs 解压 SquashFS 文件系统 SquashFS 的标配工具
jefferson 解压 JFFS2 文件系统 JFFS2 专用,比 binwalk 稳
firmware-mod-kit 固件解包/打包一体化 适合批量处理,但有些旧

4.3.2 标准提取流程

我个人习惯的流程是这样的:

  1. 先看文件头:file firmware.bin,确认固件类型
  2. 扫描分区:binwalk -Me firmware.bin,自动递归提取
  3. 检查结果:进入 _firmware.bin.extracted 目录,看有没有文件系统
  4. 手动修正:如果 binwalk 没识别出来,用 dd 手动切割
  5. 解压文件系统:根据格式选择 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 三板斧,把版本和依赖揪出来