逆向工程实战手册 第 37 章

第 37 章 radare2 / Cutter 深度使用与脚本化

第 4 章讲了 radare2 的入门工作流,本章深入:r2 命令体系的内在逻辑、r2pipe 脚本化、自定义命令与插件、Cutter(GUI)、以及与 IDA/Ghidra 的工作流衔接。CLI 工具掌握得深,才能在无 GUI 环境(服务器/CI/容器)里照样逆向。

📍 知识点地图 | 主题:radare2深度 | 前置:第4章 | 后续:— | 核心概念:命令体系、r2pipe、Cutter、自动化

37.1 r2 命令体系的内在逻辑(掌握命令规律)

r2 命令不是死记硬背,而是有一套统一语法

[.][命令][参数][@地址]      # 在指定地址执行命令
[命令][?]                    # 查看子命令帮助
[.] 前缀                     # 静默执行(不打印)
[~] 后缀                     # grep 过滤(如 afl~main)
[;] 分号                     # 命令串联
[%] 前缀                     # 遍历(如 %s 对所有字符串)

核心命令族速记

命令族 功能 例子
a* 分析 aaa / afl / afi / axt
i* 文件信息 iI / iS / iz / ii / ie
s 跳转 s main / s 0x401000
p* 打印 pdf / pd 20 / px 64 / psz
d* 调试 db / ds / dc / dr
w* 写(patch) wa nop / wx 90
x* 十六进制 x / xx
f* 标志 f / f label @ addr
e 配置 e asm.syntax=intel
? 表达式/帮助 ? 0x10+0x20 / ?v main

学习法? 查看任意命令的子命令列表(如 p? 看所有打印命令),比背表快。

37.2 深度分析命令(进阶必会)

函数与交叉引用

afl                # 函数列表
afi                # 函数详细信息(含调用者/参数猜测)
axt <addr>         # 谁引用了该地址(xref to)
axf <addr>         # 该地址引用了谁(xref from)
agf                # 函数图(ASCII)

字符串与数据

iz                 # 数据段字符串
izz                # 全文件字符串(含隐藏段)
psz @ 0x405000     # 读该地址字符串
px 32 @ 0x405000   # 十六进制 32 字节
pcp <addr> <n>     # 输出为 C 数组(喂 Python 脚本)

搜索

/ 41414141         # 搜字节
/x 48 89            # 搜十六进制(支持 ?? 通配)
/r 0x401000        # 搜引用该地址的指令
/v 42              # 搜立即数

逆向辅助

aan                # 分析并命名自动变量
aaa                # 标准分析
aaaa               # 更深分析(慢)
ar                 # 寄存器(调试)
ao <addr>          # 单条指令操作码分析

37.3 r2pipe:用 Python 驱动 r2(自动化核心)

import r2pipe

# 打开文件(只读/写模式)
r = r2pipe.open("target.exe")
# r2pipe.open("target.exe", flags=["-w"])   # 写模式

# 执行命令
print(r.cmd("aaa"))
print(r.cmd("afl"))
print(r.cmd("iz~http"))

# 获取 JSON 结构化输出
funcs = r.cmdj("aflj")          # 函数列表 JSON
strings = r.cmdj("izj")         # 字符串 JSON

# 循环处理
for f in funcs:
    name = f["name"]
    if "sub" in name:
        print(name, hex(f["offset"]))

批量分析管道(r2pipe 实战)

# 自动化: 批量导入 → 提取 → 报告
import r2pipe, json

def analyze(filepath):
    r = r2pipe.open(filepath)
    r.cmd("aaa")
    result = {
        "file": filepath,
        "funcs": len(r.cmdj("aflj")),
        "strings": [s["string"] for s in r.cmdj("izj") if "http" in s["string"]],
        "imports": r.cmdj("iij"),
    }
    r.quit()
    return result

samples = ["a.exe", "b.exe", "c.exe"]
for s in samples:
    print(json.dumps(analyze(s)))

37.4 自定义命令与脚本(r2lang)

批处理文件

# 文件 myscript.r2
aaa
afl~main
s main
pdf
q

# 执行
r2 -i myscript.r2 target.exe

自定义宏命令

(every_string, iz)          # 定义宏
(every_string)              # 执行宏

r2lang / R2Pipe 插件

r2 支持用 C/Vala 写核心插件,或用 r2pipe 脚本封装常用工作流
场景: 团队共享分析命令 → 封装成 r2lang 脚本 → 全员复用

37.5 Cutter(r2 的 GUI)

Cutter = r2 内核 + GUI 界面
能力: 反编译(集成 r2ghidra 插件 → Ghidra 反编译器!)
用途: 需要 GUI 时用 Cutter,服务器上用纯 r2 → 同一内核,同一心智模型
# 安装 r2ghidra(Cutter 内获取 Ghidra 反编译能力)
r2pm -ci r2ghidra

37.6 r2 与 IDA/Ghidra 的工作流衔接

快速侦察(服务器/大批量):  r2 + r2pipe 脚本
深度单点分析(GUI):       IDA 或 Cutter/Ghidra
脚本化批量:                r2pipe(轻) vs Ghidra headless(重)
两者衔接: 
  r2 导出符号/注释 → IDA 导入(或反之)
  r2 定位可疑地址 → IDA 打开同一文件深挖
  IDA 分析完 → r2 快速 patch 验证

37.7 r2 深度工作流(综合实战)

1. rabin2 -I/-z/-i 快速侦察
2. r2 -A 打开 → afl → 定位可疑函数
3. 交叉引用链: 字符串 → axt → 函数 → 深挖
4. r2pipe 批量提取 → JSON → LLM 分类(第 29 章)
5. 需要 GUI 时 → Cutter + r2ghidra 反编译
6. 动态验证: r2 调试模式(r2 -d)或转 GDB
7. patch 验证: r2 -w + wa/wx

动手练习

  1. ? 探索命令树:找出 p 家族全部命令,试验其中 10 个。
  2. 写一个 r2pipe 脚本:批量分析 3 个文件,输出每个文件的函数数+可疑字符串列表。
  3. pcp 导出一个常量数组为 C 代码,粘贴进 Python 脚本完成一次解密。
  4. 用 r2 的调试模式(r2 -d)下一个断点,观察寄存器变化(对比 GDB 的体验差异)。

深入阅读

  • 仓库:skills/radare2/SKILL.md(CLI 工作流与脚本)
  • 仓库:skills/radare2/references/cheatsheet.md(命令速查)
  • 仓库:skills/radare2/scripts/recon.ps1(侦察脚本范例)
  • 仓库:skills/reverse-engineering/tools.md(r2pipe 自动化)
  • 仓库:skills/reverse-engineering/patterns*.md(r2 实战案例)