3、固件提取工具链:binwalk安装与使用、dd命令、firmware-mod-kit

拿到一个固件文件,第一件事是什么?

不是直接扔进反汇编器,也不是对着十六进制发呆。你得先把它「拆开」,看看里面到底装了些什么。今天咱们就聊聊固件提取的三板斧:binwalk、dd 和 firmware-mod-kit。

核心思路:固件提取的本质就是「逆向打包」。厂商把内核、文件系统、引导程序、配置数据塞进一个二进制文件里,我们要做的就是把这些东西原封不动地掏出来。

3.1 binwalk:固件分析的瑞士军刀

binwalk 是我用得最多的工具,没有之一。它干的事情很简单——扫描固件文件,识别里面嵌入了哪些已知格式的数据块。

3.1.1 安装

我个人习惯用源码安装,因为能拿到最新的签名库。不过用包管理器也完全够用。

# Debian/Ubuntu
sudo apt-get install binwalk

# 或者从 GitHub 拉最新版
git clone https://github.com/ReFirmLabs/binwalk.git
cd binwalk
sudo python3 setup.py install

小提示:如果你打算深度使用,建议装一下 sasquatch 和 jefferson 这两个扩展包。它们能让 binwalk 识别更多类型的 SquashFS 文件系统。我踩过这个坑——没装之前,有个路由器固件死活解不开,装上后一次搞定。

3.1.2 基本用法

先来个最简单的扫描:

binwalk firmware.bin

输出大概长这样:

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header, header size: 64 bytes
64            0x40            LZMA compressed data, properties: 0x5D
2621440       0x280000        SquashFS filesystem, little endian, version 4.0

看到没?它直接告诉你:偏移 0 处是 uImage 头,0x40 开始是 LZMA 压缩数据,0x280000 处有个 SquashFS 文件系统。

要提取的话,加个 -e 参数:

binwalk -e firmware.bin

它会自动把识别出来的每个数据块拆出来,放到 _firmware.bin.extracted 目录里。

3.1.3 我常用的几个参数

参数 作用 说人话版
-e 自动提取 扫描到啥就拆啥
-M 递归提取 拆出来的文件再拆一遍
-D 按类型提取 只提取某种格式的文件
-T 显示时间戳 看看固件啥时候编译的
--dd 自定义提取规则 遇到特定魔数就切一刀

注意:binwalk 不是万能的。它依赖签名库,遇到自定义格式或者加密固件就抓瞎了。我曾经遇到过一个工控设备的固件,binwalk 扫出来全是「Data」——说白了就是啥也没认出来。这时候就得靠 dd 手工切了。

3.2 dd:二进制世界的切刀

dd 命令,老牌 Unix 工具,功能就是「从哪读到哪,写到哪里去」。在固件分析里,它用来按偏移量切分二进制文件。

3.2.1 基本语法

dd if=输入文件 of=输出文件 bs=块大小 skip=跳过块数 count=读取块数

举个例子。假设 binwalk 告诉你文件系统在偏移 0x280000 处,大小约 4MB:

dd if=firmware.bin of=rootfs.squashfs bs=1 skip=$((0x280000)) count=$((4*1024*1024))

这样就把从 0x280000 开始的 4MB 数据切出来了。

3.2.2 实战技巧

我一般这么用:先用 binwalk 扫出大概位置,再用 dd 精确切割。为什么?因为 binwalk 的自动提取有时候会多拆或少拆,手工切更可控。

比如,你想看看固件开头 1KB 是什么:

dd if=firmware.bin of=header.bin bs=1 count=1024

或者,你想跳过开头 512 字节,把剩下的全倒出来:

dd if=firmware.bin of=body.bin bs=512 skip=1

经验之谈:bs 设成 1 虽然最精确,但速度慢。如果固件很大(比如几十 MB),我习惯先设 bs=1024 或 bs=4096,然后调整 skip 和 count 的值。算偏移的时候记得换算单位就行。

3.3 firmware-mod-kit:固件修改工具箱

这个工具包,说白了就是帮你「拆开固件 → 修改内容 → 重新打包」的一条龙服务。它主要针对嵌入式 Linux 固件,尤其是那些用 SquashFS 或 CramFS 文件系统的。

3.3.1 安装

git clone https://github.com/rampageX/firmware-mod-kit.git
cd firmware-mod-kit
./setup.sh

装完之后,你会得到一堆脚本。最常用的几个:

  • extract-firmware.sh — 拆固件
  • build-firmware.sh — 打包固件
  • unsquashfs_all.sh — 批量解压 SquashFS

3.3.2 拆固件

./extract-firmware.sh firmware.bin

它会自动识别固件格式,把内核、文件系统、引导程序分别拆到不同目录。拆完后你会看到类似这样的结构:

fmk/
├── rootfs/          # 解压后的文件系统
├── kernel.bin       # 内核镜像
├── image_parts/     # 固件各分区的原始数据
└── config.log       # 拆解日志

3.3.3 改固件

拆完之后,你就可以在 rootfs/ 目录里为所欲为了——加后门、改配置、换二进制,随你便。

改完之后,重新打包:

./build-firmware.sh fmk/ new_firmware.bin

坑来了:重新打包的固件大小必须和原来一致,或者至少不能超过 Flash 分区大小。我见过有人改了固件后没注意大小,刷进去直接变砖。嗯,那哥们后来花了一下午焊 SPI Flash 编程器。

3.4 三者的配合套路

在实际项目中,我很少只用其中一个工具。标准流程是这样的:

  1. binwalk 扫一遍,看看固件里有什么东西,记下关键偏移。
  2. dd 精确切割,把文件系统、内核等分区单独切出来。
  3. firmware-mod-kit 拆包,把文件系统解压成目录结构。
  4. 修改完后,firmware-mod-kit 重新打包。

你想想看,如果只靠 binwalk 的 -e,遇到识别不出来的格式就卡住了。但配合 dd 手工切,再加上 firmware-mod-kit 的打包能力,基本上能覆盖 90% 的固件提取场景。

一句话总结:binwalk 负责「看」,dd 负责「切」,firmware-mod-kit 负责「拆和装」。三个工具各司其职,组合起来就是一套完整的固件提取工具链。

3.5 知识体系图

下面这张图把本章的核心逻辑串起来了:

固件提取工具链知识体系 固件提取工具链 固件二进制文件 binwalk 扫描识别 签名匹配 → 格式识别 自动提取 (-e) dd 精确切割 按偏移量切分 手工控制精度 firmware-mod-kit 拆包 → 修改 → 打包 支持 SquashFS/CramFS 提取出文件系统/内核 三者配合:binwalk 看全局 → dd 精确切分 → firmware-mod-kit 拆装修改

3.6 避坑指南

最后,分享几个我踩过的坑:

  • binwalk 误识别:有时候它会把随机数据当成某种格式。我建议你每次提取后,用 file 命令验证一下提取出来的文件类型。
  • dd 的 bs 参数:设成 1 虽然精确,但读大文件时慢得让人抓狂。我一般先算好偏移,用 bs=1024 配合 skip 和 count 来提速。
  • firmware-mod-kit 打包失败:最常见的原因是文件系统大小变了。改完文件后,记得检查一下新文件系统的大小,别超出原始固件的分区限制。
  • 权限问题:解压出来的文件系统里,设备文件(/dev 下的那些)在普通 Linux 系统上可能无法直接操作。用 sudo 或者加 --no-devices 参数可以绕过。

嗯,工具链就聊到这儿。记住,工具是死的,思路是活的。遇到奇葩固件时,别死磕一个工具,三个轮着上,总有一款能搞定。