第四章 ARM与MIPS逆向环境搭建:QEMU模拟器、交叉编译工具链、GDB调试器、IDA Pro配置、Ghidra配置
做ARM和MIPS逆向,环境搭建是第一道坎。我见过太多人卡在这一步,工具链没配好,连个hello world都跑不起来,更别说分析固件了。这一章咱们就把这些工具挨个捋一遍,从模拟器到调试器,从反汇编到交叉编译,一次性搞定。
4.1 QEMU模拟器:让固件跑起来
QEMU是个好东西。它能在你的x86电脑上模拟ARM、MIPS、RISC-V等各种架构。说白了,就是一台虚拟的嵌入式设备。
4.1.1 安装QEMU
我个人习惯用源码编译,但为了省事,直接用包管理器也行:
# Ubuntu/Debian
sudo apt-get install qemu-system-arm qemu-system-mips qemu-user-static
# macOS (Homebrew)
brew install qemu
# 验证安装
qemu-system-arm --version
qemu-mipsel-static --version
小提示:qemu-user-static 用于运行单个二进制文件,qemu-system-* 用于模拟完整系统。做CTF时,前者用得更多。
4.1.2 运行ARM二进制文件
拿到一个ARM的ELF文件,怎么跑?直接./binary肯定不行,得用QEMU用户态模拟:
# 运行ARM 32位程序
qemu-arm-static ./binary
# 如果依赖库缺失,指定库路径
qemu-arm-static -L /usr/arm-linux-gnueabihf/ ./binary
# 运行MIPS小端程序
qemu-mipsel-static ./binary
嗯,这里要注意:-L参数指定的是根文件系统路径。我曾经在分析一个路由器固件时,忘了加这个参数,结果程序一直段错误,折腾了半小时才发现是动态链接器版本不对。
4.1.3 调试模式启动
QEMU内置了GDB stub,可以远程调试:
# 启动QEMU并等待GDB连接
qemu-arm-static -g 1234 ./binary
# 另一个终端启动GDB
arm-linux-gnueabihf-gdb ./binary
(gdb) target remote localhost:1234
(gdb) b main
(gdb) c
避坑指南:我曾经遇到过QEMU版本太旧,不支持某些ARM指令集扩展的情况。建议用QEMU 5.0以上版本,对ARMv8和MIPS64的支持更完善。
4.2 交叉编译工具链:从源码到目标架构
交叉编译,就是在x86上编译出ARM或MIPS的可执行文件。工具链的选择很多,我推荐这几个:
| 架构 | 工具链名称 | 安装命令 | GDB名称 |
|---|---|---|---|
| ARM 32位 | arm-linux-gnueabihf | sudo apt install gcc-arm-linux-gnueabihf | arm-linux-gnueabihf-gdb |
| ARM 64位 | aarch64-linux-gnu | sudo apt install gcc-aarch64-linux-gnu | aarch64-linux-gnu-gdb |
| MIPS 小端 | mipsel-linux-gnu | sudo apt install gcc-mipsel-linux-gnu | mipsel-linux-gnu-gdb |
| MIPS 大端 | mips-linux-gnu | sudo apt install gcc-mips-linux-gnu | mips-linux-gnu-gdb |
4.2.1 编译测试程序
# 编译ARM 32位程序
arm-linux-gnueabihf-gcc -o test_arm test.c -static
# 编译MIPS小端程序
mipsel-linux-gnu-gcc -o test_mips test.c -static
# 用QEMU运行
qemu-arm-static ./test_arm
qemu-mipsel-static ./test_mips
关键点:CTF中经常遇到静态编译的二进制文件,所以建议编译时加
-static,避免动态链接库的麻烦。
4.3 GDB调试器:动态分析的利器
GDB配合QEMU,是ARM/MIPS逆向的黄金组合。你想想看,能在源码级调试,也能在汇编级单步,还能查看内存和寄存器,这比纯静态分析强太多了。
4.3.1 多架构GDB配置
我建议安装所有架构的GDB,省得来回切换:
# 安装各架构GDB
sudo apt install gdb-multiarch
sudo apt install gdb-arm-none-eabi # 裸机ARM
sudo apt install gdb-mipsel-linux-gnu # MIPS小端
# 或者用gdb-multiarch统一管理
gdb-multiarch -q ./binary
(gdb) set architecture arm
(gdb) target remote localhost:1234
4.3.2 GDB常用调试技巧
做CTF时,我经常用这几个命令:
# 查看寄存器
(gdb) info registers
(gdb) info registers r0 r1 r2 # ARM
(gdb) info registers $a0 $a1 # MIPS
# 查看内存
(gdb) x/10wx $sp # 查看栈顶10个字
(gdb) x/10i $pc # 查看当前指令附近10条
# 设置断点
(gdb) b *0x400010 # 在地址处断点
(gdb) b main # 在函数入口断点
# 修改寄存器/内存
(gdb) set $r0 = 0x1
(gdb) set {int}0x400010 = 0xdeadbeef
小技巧:在GDB中可以用
define命令自定义宏。我曾经写过一个宏,一键打印ARM的异常向量表,省了不少事。
4.4 IDA Pro配置:反汇编的瑞士军刀
IDA Pro对ARM和MIPS的支持相当好,但需要一些配置才能发挥全部威力。
4.4.1 处理器模块选择
打开IDA时,选择正确的处理器类型:
| 架构 | IDA处理器类型 | 说明 |
|---|---|---|
| ARM 32位 | ARM Little-Endian (ARM) | 大多数嵌入式设备用 |
| ARM 64位 | ARM Little-Endian (AArch64) | 新设备、手机SoC |
| MIPS 小端 | MIPS Little-Endian (MIPSEL) | 路由器、IoT设备 |
| MIPS 大端 | MIPS Big-Endian (MIPS) | 老设备、某些交换机 |
4.4.2 常用插件与脚本
我习惯装这几个插件:
- FindCrypt2:自动识别加密算法,对分析固件很有用
- Keypatch:内联汇编修改,方便patch二进制
- LazyIDA:一键提取字符串、注释、重命名
- ARM_Thumb_Helper:自动识别Thumb/ARM模式切换
注意:IDA的ARM反汇编有时会误判Thumb/ARM模式。如果发现反汇编结果明显不对,手动按
Alt+G切换处理器模式试试。
4.5 Ghidra配置:开源的反汇编引擎
Ghidra是NSA开源的逆向工具,对ARM和MIPS的支持不输IDA,而且免费。
4.5.1 安装与初始配置
# 下载Ghidra(需要Java 11+)
wget https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_10.3_build/ghidra_10.3_PUBLIC_20230711.zip
unzip ghidra_10.3_PUBLIC_20230711.zip
cd ghidra_10.3_PUBLIC
# 启动
./ghidraRun
4.5.2 导入ARM/MIPS二进制
导入时,Ghidra会自动识别架构。但有时需要手动指定:
- Language:选择ARM/MIPS对应的指令集
- Compiler:选择gcc或clang
- Endianness:注意大小端,选错会导致反汇编结果完全混乱
4.5.3 Ghidra脚本与自动化
Ghidra支持Python和Java脚本。我常用这个Python脚本批量分析:
# analyze_headless.py
from ghidra.app.util.headless import HeadlessAnalyzer
# 批量分析固件
analyzer = HeadlessAnalyzer()
analyzer.initialize("/path/to/project", "MyProject")
analyzer.addBinary("/path/to/firmware.bin", "ARM:LE:32:default")
analyzer.analyze()
analyzer.saveProject()
经验之谈:Ghidra的自动分析比IDA慢,但反汇编质量很高,尤其是对MIPS的延迟槽处理,比IDA更准确。
4.6 环境搭建知识体系
下面这张图总结了本章的核心内容,帮你理清各工具之间的关系:
4.7 常见问题与避坑指南
搭建环境时,有几个坑我踩过,写出来你们别重蹈覆辙:
我曾经...在分析一个MIPS路由器固件时,QEMU怎么都跑不起来,后来发现是固件用了MIPS16e指令集,而我的QEMU版本不支持。换用QEMU 6.0以上版本后问题解决。
- 大小端搞混:ARM默认小端,MIPS大小端都有。用
readelf -h binary查看,Data: little endian或big endian - 动态链接库缺失:用
-L指定正确的sysroot,或者直接编译静态版本 - GDB版本不匹配:QEMU的GDB stub和GDB版本要对应,建议都用最新版
- IDA反汇编错误:ARM的Thumb/ARM模式切换,MIPS的延迟槽,都需要手动确认
我的习惯:每次拿到新固件,先用
file命令看架构,再用readelf -h确认大小端和入口点,最后才决定用哪套工具链。这一步能省下后面80%的调试时间。