固件逆向基础:从提取到模拟的完整链路
各位同学,今天我们来聊聊固件逆向。说实话,这活儿在软件逆向里算是比较「硬核」的一块。你面对的不再是exe或者apk,而是一坨躺在Flash里的二进制数据——可能是路由器、摄像头,甚至是工控设备。我刚开始接触固件逆向时,第一反应是:这玩意儿怎么下手?
别急,我们一步步来。固件逆向的核心链路其实很清晰:提取 → 分析 → 识别 → 模拟。今天我就把这四个环节掰开揉碎了讲给你听。
一、固件提取:拿到原始数据
没有固件,一切都是空谈。提取方式取决于你手里有什么硬件。
1.1 从固件更新包提取
这是最省事的方式。很多厂商会提供固件升级文件,通常是 .bin、.trx、.img 后缀。我建议你先去官网找找,或者用爬虫抓一下。记得有一次我分析某品牌路由器,官网上的固件包直接就是未加密的——省了我拆机的时间。
1.2 从Flash芯片读取
如果拿不到固件包,就得动硬件了。常见Flash芯片有SPI Flash、NAND Flash、NOR Flash。你需要用编程器(比如CH341A、RT809H)配合夹子或座子来读取。
1.3 通过JTAG/SWD接口提取
如果设备有调试接口,你可以通过OpenOCD或JLink直接dump内存。这需要你找到板子上的JTAG引脚——通常是一排4-6个焊盘。用万用表量一下,GND、TMS、TCK、TDI、TDO,按顺序接上就行。
二、Binwalk分析:固件拆解利器
拿到固件文件后,第一件事就是扔进Binwalk。这工具能自动识别固件里的文件系统和压缩包。说白了,它就像一把瑞士军刀,帮你把固件「拆开」。
2.1 基本扫描
binwalk firmware.bin
输出会告诉你:这里有LZMA压缩数据,那里是Squashfs文件系统,还有一段U-Boot引导程序。我个人习惯先用 binwalk -Me firmware.bin 自动提取所有内容,省得手动一个个解。
2.2 深入分析
有时候Binwalk会漏掉一些东西。比如某些厂商会把文件系统放在偏移量很大的位置,或者用自定义魔数。这时候我会用 -R 参数手动搜索特征字符串:
binwalk -R "hsqs" firmware.bin # 搜索Squashfs魔数
binwalk -E firmware.bin 查看熵图。高熵区域(接近1.0)通常是加密或压缩数据。低熵区域(0.2-0.5)可能是明文代码或配置。
三、嵌入式架构识别:搞清楚它是什么芯片
拆开固件后,你得知道这代码跑在什么CPU上。ARM?MIPS?RISC-V?还是冷门的Xtensa?
3.1 从引导加载器判断
U-Boot是最常见的引导加载器。你可以在固件开头搜索 "U-Boot" 字符串。不同架构的U-Boot编译方式不同,ARM版用Thumb指令集,MIPS版用MIPS32指令集。看一眼反汇编就能分辨。
3.2 从文件系统判断
提取出文件系统后,看看里面的可执行文件。用 file 命令:
file ./sbin/init
# 输出示例:ELF 32-bit LSB executable, ARM, version 1 (SYSV)
这就明确了——ARM架构,32位,小端序。我遇到过一些国产芯片用大端序MIPS,那感觉就像在写反字,特别别扭。
3.3 常见嵌入式架构速查表
| 架构 | 常见芯片 | 字节序 | 典型设备 |
|---|---|---|---|
| ARM | STM32、Allwinner、Rockchip | 小端(默认) | 路由器、摄像头、手机 |
| MIPS | MT7620、AR9331 | 小端/大端 | 老旧路由器、打印机 |
| RISC-V | GD32V、K210 | 小端 | IoT设备、AI加速器 |
| Xtensa | ESP32、ESP8266 | 小端 | WiFi模块、智能家居 |
四、固件模拟:让固件跑起来
分析静态代码只能看到一半。真正有意思的是让固件在模拟器里跑起来——这样你可以动态调试,看它怎么联网、怎么处理输入。
4.1 使用QEMU进行用户态模拟
如果你只想跑某个二进制文件(比如web服务),用QEMU用户态模式就够了:
qemu-arm -L ./extracted_fs ./extracted_fs/usr/bin/httpd
-L 参数指定根文件系统路径。这样QEMU会从那里加载动态库。我遇到过最坑的情况是:固件里缺了某些库文件,程序直接段错误。这时候你得手动从固件里找,或者用 strace 看它到底缺什么。
4.2 全系统模拟
有些固件需要完整的硬件环境——比如依赖特定的GPIO、中断控制器。这时候得用QEMU的系统模式:
qemu-system-arm -M virt -kernel vmlinux -drive file=rootfs.squashfs,format=raw -append "root=/dev/sda"
但说实话,全系统模拟成功率不高。很多嵌入式设备有专有外设,QEMU不支持。我一般先用Firmadyne或FirmAE这类自动化工具试试,它们封装好了很多常见设备的模拟配置。
libnvram 模拟NVRAM,用虚拟网卡模拟物理网口。
4.3 模拟后的调试技巧
固件跑起来后,你可以用GDB远程调试:
qemu-arm -g 1234 ./binary
# 另一个终端
gdb-multiarch
(gdb) target remote localhost:1234
这样就能下断点、看寄存器、单步执行了。我个人习惯在关键函数入口下断点,比如 recv、send、system——这些往往是漏洞触发点。
知识体系总览
下面这张图总结了固件逆向的完整流程。你可以把它当作一个检查清单:
你看,整个流程是线性的,但实际工作中经常需要回溯。比如模拟失败时,你可能要回去重新分析文件系统,看看是不是漏了什么依赖库。这很正常——逆向工程本来就是个迭代过程。
好了,关于固件逆向的基础就讲到这里。记住:提取是前提,分析是核心,识别是关键,模拟是验证。把这四个环节练熟了,大部分嵌入式设备你都能搞定。