REA 开发指南:静态 · 动态 · 协议流水线
七天实战
对照 REA 子站 Day3–Day5:静态还原、Frida Hook、协议差分。
一、静态分析流水线
1.1 机器码 → 可理解模型
Ghidra 的价值在于 P-Code:跨架构统一中间层。你要训练的是:何时相信伪代码、何时必须回看汇编 idioms。
1.2 调用约定速记(x86-64)
| System V (Linux) | Win64 | |
|---|---|---|
| 整型/指针参数 | RDI, RSI, RDX, RCX, R8, R9 | RCX, RDX, R8, R9 |
| 返回值 | RAX | RAX |
| 调用者清理 | 多数 | 调用者 |
看到 xor eax,eax 常是清零返回;lea 常兼做算术。
1.3 控制流与数据流
- Xref:字符串 → 代码是最快情报链。
- Jump table:
switch还原的关键。 - 结构体重建:连续偏移
ptr+0x08/+0x10推断字段。 - CFG 回边:循环;平坦化后调度器变量会破坏直觉,需先找状态分发。
1.4 实战:还原校验/加密函数
- 定位:字符串 / 导入的密码学 API / 高熵常量表
- 识别循环与 S-box
- Python 重写并与动态输入对照
- 写单元测试:已知明文-密文对
# 示意:教学用 XOR 轮函数重写
def toy_crypt(data: bytes, key: bytes) -> bytes:
out = bytearray(data)
for i, b in enumerate(out):
out[i] = b ^ key[i % len(key)]
return bytes(out)
二、动态分析流水线
2.1 断点选型
| 类型 | 原理 | 优点 | 风险 |
|---|---|---|---|
| 软件断点 | int3 / 0xCC | 数量多 | 改代码,易被自检 |
| 硬件断点 | DR 寄存器 | 不改代码 | 通常最多 4 个 |
| 内存断点 | 页权限/硬件观察 | 追数据谁改 | 性能/误报 |
| 条件断点 | 表达式过滤 | 降噪 | 实现依赖调试器 |
2.2 Frida 模式
// 示意:Hook 某 Java 方法返回值(Android)
Java.perform(function () {
var Cls = Java.use('com.example.Auth');
Cls.check.implementation = function (user, pass) {
console.log('user=' + user + ' pass=' + pass);
var ret = this.check(user, pass);
console.log('ret=' + ret);
return ret; // 或按实验需要临时改写
};
});
原则:先观察,再篡改。篡改是为了定位校验粒度,不是为了「通关炫耀」。
2.3 反调试初识
常见手段:IsDebuggerPresent、父进程检测、时间差、异常陷阱、调试端口。
绕过思路:补丁检测点、Hook 返回值、硬件断点少改代码。细节见最佳实践文档。
三、协议逆向流水线
3.1 抓包三板斧
- 显示过滤定位会话
- Follow TCP Stream 看完整载荷
- TLS:SSLKEYLOGFILE 或授权 MITM(注意 Pinning)
3.2 字段推断套路
| 信号 | 可能含义 |
|---|---|
| 固定头几个字节 | 魔数 / 版本 |
| 紧随其后的 2/4 字节随长度变 | 长度字段 |
| 尾部 2/4 字节 | CRC / 校验 |
| 改一个输入仅局部字节变 | 该 字段语义 |
3.3 用 construct 描述结构
from construct import Struct, Int32ul, Bytes, Prefixed
Msg = Struct(
'magic' / Bytes(4),
'length' / Int32ul,
'payload' / Bytes(lambda ctx: ctx.length),
)
四、工程化:把分析变成可交付物
每次分析至少产出: