第二章 固件获取与提取:从官网、设备、OTA包获取固件,使用binwalk、dd等工具提取文件系统

做固件安全分析,第一步就是拿到固件。这听起来简单,但实际坑不少。我见过很多新手上来就问「有没有现成的固件下载链接」,其实获取渠道远不止官网一种。今天我把常用的三种途径——官网下载、设备直读、OTA包抓取——都捋一遍,再讲讲怎么用binwalk和dd把文件系统完整地扒出来。

2.1 固件获取的三种主流途径

固件藏在哪儿?说白了就三个地方:厂商的服务器、设备本身的存储芯片、以及你手机或路由器收到的更新包。每个渠道都有自己的脾气,咱们一个一个说。

2.1.1 从官网下载固件

这是最省事的办法。大部分厂商会在技术支持页面提供固件下载。但有个问题——他们往往只放最新版。你想分析旧版本?对不起,可能早就下架了。

我个人习惯是先去官网翻一遍,重点看这几个地方:

  • 支持中心:通常叫「下载中心」或「固件升级」
  • 产品页面:有些藏在「技术规格」的折叠菜单里
  • FTP服务器:部分厂商(比如某些网络设备商)有公开的FTP目录

举个例子,我去年分析某品牌路由器时,官网只放了最新版。但我发现它的下载链接有规律——版本号是递增的。稍微改一下URL里的数字,就把历史版本全拉下来了。嗯,这招不是每次都灵,但值得一试。

小技巧:如果官网找不到,试试用搜索引擎搜「产品型号 + firmware + download」,或者去第三方固件存档站碰碰运气。

2.1.2 从设备中读取固件

官网没有?那就直接从设备上读。这需要点硬件手段,但往往能拿到最原始的固件镜像。

常见做法是拆机,找到Flash芯片,用编程器或JTAG/SWD接口读取。我建议优先用SPI Flash编程器,比如CH341A,便宜又好用。操作步骤大致是:

  1. 拆开设备,找到Flash芯片(通常是8脚或16脚的SOIC封装)
  2. 用夹子或焊接方式连接编程器
  3. 用软件(如FlashROM、SPI Flash Tool)读取全片数据
  4. 保存为.bin文件

这里有个坑——有些芯片有读保护。我曾经遇到一个智能插座,读出来的数据全是0xFF。后来发现是芯片的Security Bit被置位了。解决办法?要么用暴力手段(比如高压编程),要么换思路从OTA包入手。

注意:拆机可能失去保修,而且操作不当会损坏设备。如果你不熟悉硬件操作,建议先从软件渠道入手。

2.1.3 从OTA包中提取固件

OTA(Over-The-Air)更新包是另一个宝库。很多物联网设备会通过手机App或云端推送更新。抓取OTA包的方法有几种:

  • 抓包工具:用Wireshark或Fiddler监听设备与服务器的通信
  • App逆向:从手机App的安装包里提取下载链接
  • 日志分析:有些设备会把更新URL写在系统日志里

我记得有一次分析某摄像头,它的App在更新时会先请求一个JSON接口,里面包含了固件下载地址。我用Fiddler抓到了这个请求,然后直接下载了固件。整个过程没碰硬件,省了不少事。

OTA包通常不是裸固件,而是经过打包的格式。常见的有:

格式 特征 常见场景
.bin 裸二进制,可能带头部 路由器、智能家居
.zip/.tar 压缩包,解压后得到固件 部分Linux设备
.img 完整磁盘镜像 树莓派、开发板
.pkg/.swu 自定义打包格式 工业设备、汽车ECU

2.2 固件提取:从二进制到文件系统

拿到固件文件后,它只是一堆二进制数据。我们需要从中提取出文件系统,才能分析里面的配置、二进制程序、Web页面等。这一步,binwalk是首选工具。

2.2.1 使用binwalk分析固件

binwalk是个神器,它能自动识别固件里嵌入的文件系统和压缩数据。基本用法很简单:

# 扫描固件,列出所有可识别的文件
binwalk firmware.bin

# 提取所有文件
binwalk -e firmware.bin

# 递归提取(处理嵌套的压缩包)
binwalk -Me firmware.bin

运行后,binwalk会输出类似这样的结果:

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             TRX firmware header, little endian, image size: 8388608 bytes
256           0x100           LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes
1310720       0x140000        Squashfs filesystem, little endian, version 4.0, compression:lzma

看到Squashfs了吗?这就是我们要的文件系统。binwalk会自动把它提取到_firmware.bin.extracted目录下。

但binwalk不是万能的。我遇到过几次它识别失败的情况,比如:

  • 固件头部被加密或混淆
  • 文件系统使用了非标准压缩算法
  • 固件被拆分成多个片段

这时候就需要手动分析了。我会用hexdumpstrings先看看固件里有没有明显的特征字符串,比如「Squashfs」、「ubifs」、「jffs2」等。

核心思路:binwalk靠的是特征签名识别。如果它认不出来,说明固件可能被魔改了。这时候可以试试更新binwalk的签名库,或者自己写签名。

2.2.2 使用dd命令手动切割

有时候binwalk提取出来的文件系统不完整,或者我们需要精确控制切割位置。这时候dd命令就派上用场了。

假设我们从binwalk的输出中知道Squashfs文件系统起始于偏移量0x140000,大小是6MB。可以用dd把它切出来:

# 从偏移量0x140000开始,读取6MB数据
dd if=firmware.bin of=squashfs.img bs=1 skip=$((0x140000)) count=$((6*1024*1024))

参数说明:

  • if:输入文件
  • of:输出文件
  • bs=1:块大小为1字节(方便精确控制)
  • skip:跳过多少字节
  • count:读取多少字节

切出来后,可以用unsquashfs解压:

unsquashfs squashfs.img

如果文件系统是UBIFS或JFFS2,则需要用对应的工具(如ubireaderjefferson)。

避坑指南:我曾经因为算错偏移量,切出来的文件系统全是乱码。后来我养成了一个习惯——先用binwalk -E查看固件的熵值分布,熵值高的区域通常是压缩数据或加密数据,低熵区可能是文件系统头部。这能帮你确认切割位置是否准确。

2.2.3 处理加密和混淆的固件

有些厂商会对固件进行加密或混淆,防止被轻易提取。常见的手段有:

  • XOR加密:整个固件与一个固定密钥异或
  • AES加密:需要密钥才能解密
  • 自定义头部:在固件前加一个专有头部,隐藏真实偏移

遇到加密固件怎么办?我的经验是:

  1. 找密钥:密钥可能藏在设备的Bootloader、U-Boot环境变量、或者App的代码里
  2. 分析更新流程:设备在接收固件后,会先解密再写入Flash。如果能模拟这个流程,就能还原出明文
  3. 硬件调试:用JTAG/SWD接口在设备运行时读取内存,拿到解密后的数据

我记得有一次分析某智能门锁,固件头部有256字节的魔数。我花了三天时间逆向它的Bootloader,才发现密钥其实是设备序列号的MD5值。嗯,这种「偷懒」的设计反而帮了我大忙。

2.3 本章核心知识图谱

下面这张图总结了固件获取与提取的完整流程,从源头到文件系统,每一步的关键工具和方法都标出来了。

固件获取与提取流程 官网下载 设备直读 OTA包抓取 固件二进制文件 (.bin/.img/.pkg) binwalk 扫描 / hexdump 分析 / strings 查看 binwalk -e 自动提取 dd 手动切割 + unsquashfs 文件系统 (Squashfs/UBIFS/JFFS2)

从图上能看出来,整个流程是线性的:先通过各种渠道拿到固件,然后用binwalk或dd把文件系统提取出来。如果遇到加密,就需要额外花功夫去逆向解密逻辑。

2.4 实战中的几个提醒

最后,分享几个我在项目中踩过的坑,希望能帮你少走弯路:

  • 不要迷信binwalk:它识别不出来不代表固件有问题,可能是签名库太旧。试试binwalk --update更新一下。
  • 注意大小端:ARM设备多用小端,MIPS设备可能用大端。用dd切割时,偏移量计算要小心。
  • 保留原始文件:每次操作前,先备份原始固件。我因为手滑覆盖过原始文件,结果不得不重新下载。
  • 检查文件系统完整性:提取出来后,用file命令确认一下类型。如果显示「data」,说明可能没切对。

好了,这一章的内容就到这里。固件拿到手、文件系统提取出来,下一步就是深入分析里面的配置和二进制程序了。不过那是后面的事,先把基础打牢再说。


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