3、固件解包与文件系统分析:Binwalk工具使用、文件系统挂载、固件结构识别
各位同学好,我是老周。今天咱们聊固件解包和文件系统分析。说实话,这是支付终端安全检测里最基础、也最核心的一步。你拿到的固件是个黑盒子,不拆开它,后面所有分析都无从谈起。
我刚开始做这行的时候,也踩过不少坑。有一次拿到一个POS机的固件,用Binwalk扫了半天啥也没发现,后来才发现是固件头被厂商做了特殊处理。嗯,今天我就把这些经验都抖出来,咱们一步步来。
3.1 固件结构识别——先摸清底细
拿到一个固件文件,别急着解包。我个人的习惯是:先看看它到底是什么结构。说白了,就是搞清楚这个文件是裸的二进制,还是带了个文件系统,或者是多个分区拼起来的。
怎么识别?最直接的办法是用 file 命令。比如:
$ file pos_firmware.bin
pos_firmware.bin: data
如果返回 data,说明文件头被抹掉了,或者是个裸的二进制。这时候就需要用 Binwalk 来扫描了。
核心思路:固件通常由 Bootloader、内核、文件系统、配置数据等部分组成。识别出这些分区的边界,是解包的第一步。
3.2 Binwalk工具使用——我的瑞士军刀
Binwalk 是我最常用的固件分析工具,没有之一。它本质上是个签名扫描器,能识别出固件里嵌入的各种文件系统和压缩数据。
基本用法很简单:
$ binwalk pos_firmware.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 uImage header, header size: 64 bytes, ...
65536 0x10000 SquashFS filesystem, little endian, ...
131072 0x20000 JFFS2 filesystem, little endian, ...
看到没?它把每个分区的偏移地址和类型都列出来了。我个人习惯先看 DECIMAL 这一列,因为后面挂载文件系统的时候,需要用到这个偏移量。
我曾经遇到过一个案例,厂商把文件系统藏在了固件的中间位置,前面塞了一大堆填充数据。Binwalk 一扫描,直接就把 SquashFS 的起始地址给揪出来了。你想想看,要是手动去翻二进制,那得翻到猴年马月去。
3.2.1 常用参数
| 参数 | 作用 | 我的用法 |
|---|---|---|
-e |
自动提取识别的文件 | 偷懒的时候用,但有时会漏东西 |
-M |
递归扫描(扫描提取出的文件) | 对付多层嵌套的固件很管用 |
-T |
显示文件类型详情 | 我一般配合 -D 一起用 |
-D |
指定提取类型 | 比如只提取 SquashFS |
小技巧:用 binwalk -Me pos_firmware.bin 可以一键递归提取。但注意,如果固件很大,可能会生成大量文件,建议先手动分析偏移量再提取。
3.3 文件系统挂载——把固件变成文件夹
提取出文件系统镜像之后,下一步就是挂载它。说白了,就是把那个二进制文件当成一个硬盘分区,挂到 Linux 的某个目录下,然后像操作普通文件夹一样去浏览它。
支付终端里最常见的三种文件系统:SquashFS、CramFS、JFFS2。我一个个说。
3.3.1 SquashFS——只读的压缩文件系统
SquashFS 是 Linux 嵌入式系统里用得最多的只读文件系统。它压缩率高,读取快,适合存放固件里的程序和数据。
挂载命令:
# 假设从固件偏移 0x10000 处提取出了 squashfs.img
$ unsquashfs squashfs.img
# 或者用 mount 挂载
$ mount -t squashfs squashfs.img /mnt/squashfs -o loop
我个人更推荐用 unsquashfs,因为它直接解压到当前目录,方便后续分析。用 mount 的话,记得用完要 umount,不然会占用资源。
注意:有些厂商会对 SquashFS 做自定义修改,比如改了压缩算法或者加了校验。这时候标准工具可能解不开,需要逆向分析它的解压逻辑。我曾经遇到过一家厂商,把 SquashFS 的魔数从 hsqs 改成了 abcd,害我折腾了一整天。
3.3.2 CramFS——老牌嵌入式文件系统
CramFS 比 SquashFS 更老,现在用得少了,但一些老款支付终端还在用。它的特点是简单、轻量,但压缩率不如 SquashFS。
挂载方法:
$ mount -t cramfs cramfs.img /mnt/cramfs -o loop
嗯,这里要注意,CramFS 不支持写操作,所以挂载后只能读。如果你想修改固件内容,得先解压出来,改完再重新打包。
3.3.3 JFFS2——可读写的闪存文件系统
JFFS2 是专门为 NAND Flash 设计的可读写文件系统。支付终端里,它通常用来存放配置数据、日志文件等需要动态修改的内容。
挂载 JFFS2 稍微麻烦一点,因为它需要模拟一个 MTD 设备:
# 先加载 mtdblock 模块
$ modprobe mtdblock
$ modprobe mtdram total_size=65536 erase_size=256
# 把 JFFS2 镜像写入模拟的 MTD 设备
$ dd if=jffs2.img of=/dev/mtdblock0
# 挂载
$ mount -t jffs2 /dev/mtdblock0 /mnt/jffs2
说实话,这个过程有点绕。我建议你写个脚本,把这几步封装起来,省得每次都要敲一遍。
3.4 实战经验——避坑指南
做固件解包这么多年,我总结了几条血泪教训:
- 先备份,再操作。 我曾经手滑把原始固件覆盖了,结果只能重新下载。浪费时间不说,还差点耽误项目进度。
- 注意字节序。 ARM 和 MIPS 的固件字节序可能不同,Binwalk 有时候会识别错。如果发现解出来的文件系统打不开,试试加
--big-endian或--little-endian参数。 - 别迷信自动提取。 Binwalk 的
-e参数虽然方便,但遇到非标准固件结构时,它可能会漏掉一些分区。我建议先手动分析偏移量,再针对性提取。 - 检查文件系统完整性。 挂载成功后,先看看有没有
bin、etc、usr这些标准目录。如果目录结构很奇怪,可能是提取错了分区。
核心总结:固件解包不是目的,目的是拿到里面的可执行文件、配置文件、脚本等,为后续的漏洞分析、后门检测做准备。所以,解包这一步做得越扎实,后面的分析就越顺利。
3.5 知识体系图
下面这张图是我自己画的,把固件解包与文件系统分析的整个流程串起来了。你照着这个思路走,基本不会迷路。
这张图里,从固件文件开始,经过结构识别、分区提取,再到三种文件系统的挂载方式,一目了然。你把它打印出来贴在工位上,干活的时候瞄一眼,效率能提高不少。
好了,这一章就讲到这里。固件解包是个手艺活,多练几次就熟了。下一章咱们聊聊怎么从解包后的文件系统里找漏洞,那才是真正有意思的部分。