4、二进制文件分析基础:file命令、binwalk、strings、hexdump、熵分析
拿到一个固件,第一件事是什么?
我个人的习惯是——先别急着拆,先看看它到底是什么东西。就像你收到一个快递,总得先看看包装上的标签吧?二进制文件分析,就是给固件「验明正身」的过程。
4.1 file命令:三秒看穿文件本质
file 命令是我用得最多的工具,没有之一。它不依赖文件扩展名,而是通过检查文件头部的魔数(Magic Number)来判断文件类型。
核心原理:每个文件格式都有独特的头部签名。比如 ELF 文件以 7f 45 4c 46 开头,JPEG 以 ff d8 ff 开头。file 命令就是靠这些签名来识别的。
# 基本用法
$ file firmware.bin
firmware.bin: data
# 如果固件是已知格式
$ file u-boot.bin
u-boot.bin: u-boot legacy uImage, Linux Kernel Image, ...
# 查看压缩包
$ file rootfs.squashfs
rootfs.squashfs: Squashfs filesystem, little endian, version 4.0
我在项目中遇到过好几次,甲方给的固件后缀是 .bin,但用 file 一看,其实是 ZIP 压缩包。你想想看,如果直接当二进制去逆向,那得多走多少弯路?
小技巧:用 file -k 可以强制显示所有匹配的类型,有时候一个文件可能包含多层结构。
4.2 binwalk:固件拆解瑞士军刀
binwalk 是我做固件逆向时离不开的工具。它不仅能识别文件类型,还能帮你把固件里的各个组件拆出来。
说白了,binwalk 就是 file 命令的「超级增强版」。它会扫描整个二进制文件,寻找已知的文件签名,然后告诉你:这里有个 LZMA 压缩块,那里有个 Squashfs 文件系统。
# 扫描固件中的文件签名
$ binwalk firmware.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 u-boot legacy uImage, Linux Kernel Image
64 0x40 LZMA compressed data
131072 0x20000 Squashfs filesystem, little endian, version 4.0
# 提取所有识别到的文件
$ binwalk -e firmware.bin
# 只提取特定偏移的文件
$ binwalk -D 'squashfs:rootfs:squashfs' firmware.bin
我曾经接手过一个路由器固件,用 binwalk 一扫描,发现里面嵌套了 3 层压缩:先是 gzip,然后是 LZMA,最后才是真正的文件系统。如果没有 binwalk,手动找这些边界点会非常痛苦。
注意:binwalk 的签名数据库不是万能的。遇到自定义加密或混淆的固件,它可能什么都识别不出来。这时候就需要结合熵分析来人工判断了。
4.3 strings:从二进制中捞取文本信息
strings 命令看似简单,但用好了能挖出不少线索。它会从二进制文件中提取可打印的字符串序列。
# 提取所有长度 >= 4 的字符串
$ strings firmware.bin
# 提取所有字符串(包括短字符串)
$ strings -n 2 firmware.bin
# 同时显示偏移地址
$ strings -t x firmware.bin
# 结合 grep 快速定位关键信息
$ strings firmware.bin | grep -i "version\|model\|build"
嗯,这里要注意:strings 只能提取连续的 ASCII 或 Unicode 字符串。如果固件用了简单的 XOR 加密,字符串就看不到了。我遇到过一些 IoT 设备,厂商会把关键字符串做异或处理,这时候 strings 就抓瞎了。
实战经验:我习惯先用 strings 看看固件里有没有文件路径、IP 地址、版本号这些信息。这些往往是逆向的突破口。比如看到 /etc/config/network,基本就能确定这是 OpenWrt 系的固件。
4.4 hexdump:二进制文件的「X光片」
hexdump(或 xxd、od)能让你看到二进制文件的原始字节。虽然看起来是一堆十六进制数字,但经验丰富的工程师能从中读出很多信息。
# 查看文件头部(前 64 字节)
$ hexdump -C firmware.bin | head -n 4
00000000 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 02 00 03 00 01 00 00 00 54 80 04 08 34 00 00 00 |........T...4...|
# 查看指定偏移
$ hexdump -s 0x20000 -n 128 firmware.bin
# 用 xxd 更方便
$ xxd firmware.bin | head -n 10
为什么还要学 hexdump?因为有些时候,binwalk 和 file 都认不出来的东西,你用手动看头部字节反而能发现规律。比如我看到 1f 8b 08 就知道是 gzip 压缩,看到 89 50 4e 47 就知道是 PNG 图片。
需要记住的常见魔数:
| 魔数(十六进制) | 文件类型 |
|---|---|
| 7f 45 4c 46 | ELF |
| 1f 8b 08 | gzip |
| 42 5a 68 | bzip2 |
| 89 50 4e 47 | PNG |
| ff d8 ff | JPEG |
| 55 aa | MBR 引导扇区 |
4.5 熵分析:识别加密与压缩的利器
熵(Entropy)这个概念,说白了就是衡量数据「混乱程度」的指标。纯文本的熵值较低(大约 4-5),而加密或压缩后的数据熵值接近 8(最大值)。
为什么这个重要?因为固件里经常有加密的代码段或压缩的数据块。用肉眼很难看出来,但熵分析能一目了然。
# 使用 binwalk 的熵分析功能
$ binwalk -E firmware.bin
# 输出会生成一个 ASCII 图表,显示每个区域的熵值
# 高熵区域(接近 8.0)通常是加密或压缩数据
# 低熵区域(接近 4.0)通常是明文代码或数据
我记得有一次分析一个工控设备的固件,binwalk 什么都没扫出来。但我用熵分析一看,发现 0x10000 到 0x20000 这段区域的熵值高达 7.9,明显是加密或压缩数据。后来手动分析发现,厂商把文件系统做了 XOR 加密,密钥就藏在固件的另一段低熵区域里。
实用技巧:我经常把熵分析和 binwalk 结合起来用。先用熵分析找出可疑的高熵区域,再用 binwalk 去针对性扫描这些区域。这样能大大提高识别成功率。
4.6 综合实战:一个完整的分析流程
说了这么多,我们来走一遍完整的流程。假设你拿到一个叫 fw_update.bin 的文件:
- 第一步:file 命令 — 看看文件类型,结果是
data,说明不是标准格式。 - 第二步:strings 快速扫描 — 发现
U-Boot、kernel、rootfs等关键词,确认是嵌入式固件。 - 第三步:binwalk 扫描 — 识别出 uImage 头部、LZMA 压缩数据、Squashfs 文件系统。
- 第四步:熵分析 — 确认各区域的熵值分布,验证 binwalk 的识别结果。
- 第五步:hexdump 验证 — 手动查看关键偏移处的字节,确认魔数是否正确。
- 第六步:binwalk -e 提取 — 拆解固件,得到内核镜像和文件系统。
避坑指南:我曾经遇到过一个固件,binwalk 识别出了 Squashfs,但提取后挂载失败。后来用 hexdump 一看,发现文件系统的魔数被厂商篡改了一个字节。这种「反逆向」手段在商业固件中并不少见。
4.7 知识体系总览
下面这张图总结了二进制文件分析的核心工具和它们之间的关系:
这五个工具,说白了就是固件逆向的「五件套」。先用 file 和 strings 快速摸底,再用 hexdump 验证细节,最后用 binwalk 和熵分析做深度拆解。这套流程我用了快十年,基本没失手过。
核心要点回顾:
- file 看类型,strings 找线索,hexdump 看细节
- binwalk 是固件拆解的主力,但别完全依赖它
- 熵分析能发现加密和压缩区域,是逆向的「透视眼」
- 五个工具配合使用,才能全面掌握固件结构
公众号:蓝海资料掘金营,微信deep3321