第三章:固件结构解剖——Bootloader解析、内核镜像定位、文件系统识别

好,咱们进入正题。拿到一个思科固件,你不能上来就瞎翻。你得知道它长什么样,骨头在哪儿,肉在哪儿。说白了,就是解剖。

我刚开始做固件逆向那会儿,也犯过傻——直接拿二进制编辑器打开,满屏的十六进制看得我眼晕。后来带我的老工程师跟我说了一句话,我记到现在:“先找结构,再找漏洞”。嗯,这句话值不少钱。

3.1 Bootloader:固件的“第一口饭”

Bootloader,就是引导加载程序。思科设备上最常见的是 RedBootU-Boot。它的任务很简单:初始化硬件,加载内核。

怎么识别?我一般这么干:

  • 看开头字符串:RedBoot 的开头通常有 "RedBoot>" 或者 "ECOS" 字样。U-Boot 则会有 "U-Boot 2010.03" 这样的版本号。
  • 找异常向量表:ARM 架构的 Bootloader,开头 0x00 位置一定是中断向量表。你看到一堆 B 指令(跳转指令),基本就稳了。
  • 检查校验和区域:思科喜欢在 Bootloader 尾部放一个 CRC32 校验值。我遇到过好几次,固件刷坏了就是因为这个校验没通过。
我的小技巧:用 binwalk -Me 扫描固件,它会自动帮你标出 Bootloader 的起始位置。但别全信,我见过它把一段随机数据误判成 U-Boot 的情况。最后还是得靠人工确认。

3.2 内核镜像定位:找到那个“心脏”

内核镜像,通常是 zImageuImage。思科喜欢用 uImage,因为它带了一个 64 字节的头,里面包含了加载地址、入口点、镜像类型等信息。

定位方法其实不复杂:

  1. 搜索魔数:uImage 的魔数是 0x27051956(大端)。你在十六进制编辑器里搜这个值,一搜一个准。
  2. 看压缩头:如果内核是 gzip 压缩的,开头会有 1F 8B 08。LZMA 压缩则是 5D 00 00
  3. 计算偏移:找到魔数后,往后跳 64 字节,就是真正的内核数据开始处。
# 用 dd 命令提取内核镜像(假设固件文件为 firmware.bin)
# 先找到 uImage 的偏移,比如 0x10000
dd if=firmware.bin of=kernel.uImage bs=1 skip=$((0x10000)) count=$((0x400000))
# 然后解压
dd if=kernel.uImage bs=64 skip=1 | gunzip > kernel.elf
注意:思科有些新固件用了加密内核。你搜魔数可能搜不到。这时候就得靠 Bootloader 里的解密函数了。我曾经在 Cisco ISR 系列上遇到过,内核被 AES 加密,得先逆向 Bootloader 拿到密钥才能解。

3.3 文件系统识别:SquashFS vs JFFS2

文件系统,就是固件里的“肉”。思科最常用的是 SquashFSJFFS2。两者区别很大:

特性 SquashFS JFFS2
压缩方式 gzip/lzma/lzo zlib
读写能力 只读 可读写
典型魔数 hsqssqsh 0x1985(大端)
适用场景 固件镜像 运行时文件系统

识别方法:

  • SquashFS:用 binwalk 扫,它会显示 "SquashFS filesystem, little endian, version 4.0"。然后直接用 unsquashfs 解压。
  • JFFS2:这个稍微麻烦点。你得先确定偏移,然后用 jefferson 工具解压。我遇到过 JFFS2 镜像被分片的情况,得手动拼接。
避坑指南:我曾经在 Cisco 2901 的固件里,发现文件系统被分成了两个部分——前半段是 SquashFS,后半段是 JFFS2。binwalk 只识别出了第一个。后来我手动看了十六进制,才发现第二个文件系统的魔数藏在了一个 padding 区域后面。所以,别只依赖自动化工具

3.4 实战:画一张固件结构图

说了这么多,不如画张图。下面这张 SVG 图,展示了一个典型思科固件的布局:

Bootloader (RedBoot / U-Boot) 异常向量表 | 初始化代码 | 校验和 内核镜像 (uImage / zImage) uImage头 (64字节) | 压缩内核 (gzip/LZMA) | 设备树 (DTB) 魔数: 0x27051956 | 加载地址: 0x80008000 文件系统 (SquashFS / JFFS2) /bin | /sbin | /etc | /lib | /usr 魔数: hsqs / 0x1985 | 压缩: gzip/zlib 尾部数据 (配置分区 / 日志 / 填充) 偏移 0x0000 偏移 0x10000 偏移 0x500000

这张图你看明白了吗?从上到下依次是:Bootloader、内核、文件系统、尾部数据。每个部分都有固定的魔数和结构特征。你只要掌握了这些特征,解剖固件就跟切豆腐一样简单。

3.5 总结一下

嗯,这一章我们干了三件事:

  • Bootloader:找到它,识别类型,检查校验。
  • 内核镜像:定位魔数,提取数据,解压分析。
  • 文件系统:区分 SquashFS 和 JFFS2,用对工具。

我个人习惯,拿到一个新固件,第一件事就是跑 binwalk -Me,然后对照这张结构图,把每个部分标出来。这样后面做漏洞分析的时候,心里就有底了。

记住一句话:结构不清,分析白忙


公众号:蓝海资料掘金营,微信deep3321