3、固件结构剖析:Bootloader、内核、文件系统、配置分区
拿到一个固件,别急着反汇编。我个人的习惯是,先把它拆开看看——就像拆快递一样,看看里面到底装了啥。固件结构说白了就是三件套:Bootloader、内核、文件系统,再加上一个容易被忽略的配置分区。今天咱们就把这四块掰开揉碎了讲。
3.1 Bootloader:固件的“第一口奶”
Bootloader 是硬件上电后第一个跑起来的程序。它的任务很简单:初始化硬件,然后跳转到内核入口。嗯,这里要注意,不同芯片的 Bootloader 差别很大。
常见的 Bootloader 有这些:
- U-Boot:Linux 世界的标配,功能强大,支持网络启动、Flash 读写
- Barebox:U-Boot 的现代替代品,代码更干净
- RedBoot:eCos 生态的,现在用得少了
- CFE:Broadcom 芯片专用,博通路由器里常见
我在项目中遇到过一台老式路由器,死活刷不进新固件。后来一查,是 Bootloader 里的 Flash 分区表写死了,内核大小超限就直接覆盖了配置分区。那次之后,我养成了习惯——先 dump 出 Bootloader 的配置参数看看。
strings 命令扫一下,能发现很多配置信息。
3.2 内核:固件的大脑
内核是 Linux 的核心,负责管理硬件资源、调度进程、提供系统调用。在固件里,内核通常被压缩成 zImage 或 uImage 格式。
内核镜像的典型结构:
+------------------+
| 解压缩代码 | (自解压头)
+------------------+
| 压缩后的内核 | (gzip/lzma/lzo)
+------------------+
| DTB (设备树) | (可选,描述硬件)
+------------------+
你想想看,为什么固件里的内核这么小?因为嵌入式设备资源有限,内核都是裁剪过的。我见过最夸张的一个路由器固件,内核只有 1.2MB——去掉了所有不用的驱动和模块。
识别内核版本有个小窍门:用 binwalk -e 解压后,在解压目录里搜 Linux version 字符串。这个字符串会告诉你内核版本、编译时间、编译器版本。这些信息对找漏洞很有用——比如某个版本的内核有已知的 CVE。
3.3 文件系统:固件的“家当”
文件系统里装着所有用户态程序、配置文件、Web 界面、库文件。嵌入式设备常用的文件系统有三种,各有各的脾气。
3.4 SquashFS:只读的压缩文件系统
SquashFS 是嵌入式设备最常用的文件系统。它是只读的,数据压缩存储,解压后挂载。优点是体积小、读取快。
SquashFS 的版本和压缩方式:
| 版本 | 压缩算法 | 最大文件大小 | 常见场景 |
|---|---|---|---|
| v3.0 | gzip | 2GB | 老旧路由器 |
| v4.0 | gzip/lzma/lzo/xz | 16TB | 现代设备 |
提取 SquashFS 很简单:unsquashfs firmware.squashfs。但要注意,有些厂商会魔改 SquashFS 的魔数(magic number),导致 unsquashfs 认不出来。我遇到过一家厂商把魔数从 hsqs 改成了 hsqS,折腾了我半天。
3.5 JFFS2:针对 NAND Flash 的日志型文件系统
JFFS2 是专门为 NAND Flash 设计的。它支持磨损均衡、掉电保护。但缺点也很明显——挂载慢,内存占用高。
JFFS2 的典型应用场景:
- 需要频繁写入的配置分区
- 日志记录分区
- 用户数据分区
提取 JFFS2 需要点技巧:
# 先找到 JFFS2 镜像的偏移
binwalk firmware.bin | grep JFFS2
# 然后用 dd 切出来
dd if=firmware.bin of=jffs2.img bs=1 skip=0x123456
# 挂载到本地
sudo mount -t jffs2 jffs2.img /mnt/jffs2
modprobe jffs2 是否成功。我踩过这个坑——折腾了半天才发现内核模块没加载。
3.6 YAFFS2:专为 NAND Flash 优化的文件系统
YAFFS2 比 JFFS2 更轻量,挂载速度更快。它没有压缩功能,但读写性能更好。很多 Android 设备的 /data 分区就用 YAFFS2。
YAFFS2 的特点:
- 没有压缩,占用空间更大
- 挂载速度极快(毫秒级)
- 对 NAND Flash 的坏块处理更激进
提取 YAFFS2 可以用 unyaffs2 工具。但要注意,YAFFS2 的镜像通常包含 OOB(Out-of-Band)数据,提取时得带上 -o 参数。
3.7 配置分区:固件的“小本本”
配置分区是很多人容易忽略的部分。它通常是一个独立的小分区,用来存 MAC 地址、WiFi 校准数据、设备序列号等。
配置分区的常见格式:
- MTD 分区:直接映射到 Flash 的某个区域
- UBI 卷:在 UBI 层上创建的卷
- Raw 数据:没有任何文件系统,直接读写
我曾经分析过一个智能家居网关,它的配置分区里存着 WiFi 密码——明文!厂商觉得没人会去读 Flash,所以没加密。嗯,这个漏洞我报给了厂商,后来他们加了 AES 加密。
hexdump 查看配置分区,搜索 "MAC"、"password"、"ssid" 等关键词。很多厂商的配置格式是固定的,找到规律后就能批量提取。
3.8 知识体系总览
下面这张图总结了固件结构的核心逻辑,我建议你保存下来,分析固件时对照着看:
这张图把固件拆成了四个模块。你分析的时候,按这个顺序来就行。先看 Bootloader 有没有漏洞,再看内核版本有没有已知 CVE,然后解压文件系统找敏感信息,最后别忘了检查配置分区——那里经常藏着惊喜。
公众号:蓝海资料掘金营,微信deep3321