# 需求：动态分析能力与脱壳流程增强

## 1. 背景与目标

### 1.1 来源

复盘 CCG Crypto Crackme v1.0（自定义 UPX 壳）的完整分析过程（约 3-4 小时、25+ 手写脚本、20+ 次失败），识别出 6 个通用改进点。

### 1.2 痛点与数据

| 痛点 | 浪费时间 | 根因 |
|------|---------|------|
| 脱壳后没用 idat 加载 dump，用 capstone 手动反汇编 | ~60 分钟 | 缺少"解壳后必须加载到 IDA"的规则 |
| Frida API 反复试错（v17 变更 + GUI 阻塞） | ~60 分钟 | 无动态分析知识库 |
| Unicorn 模拟反复失败，没及时切换动态脱壳 | ~30 分钟 | 缺少静态 vs 动态决策树 |
| 算法理解反复出错（MD5 前/后 8 字节搞反） | ~30 分钟 | 手动 capstone 反汇编难以准确追踪数据流 |
| 每次手写 Frida 脱壳脚本，重复踩 API 坑 | ~15 分钟 | 无通用脱壳脚本模板 |
| 密码学算法识别慢 | ~10 分钟 | 无常见模式参考 |

### 1.3 目标

通过知识库增强 + 主 prompt 规则 + 通用脚本模板，让类似场景下次能在 30 分钟内完成，不卡住。

---

## 2. 技术方案

### 2.1 改动总览

| ID | 方案 | 改动文件 | 类型 |
|----|------|---------|------|
| A | packer-handling.md 增加动态脱壳 + 决策树 | `ida-pro-analysis-knowledge-base/packer-handling.md` | 修改（现有 128 行，扩充至 ~210 行） |
| B | 新建 dynamic-analysis.md | `ida-pro-analysis-knowledge-base/dynamic-analysis.md` | 新增（~120 行） |
| C | 主 prompt 增加解壳后加载 IDA 规则 | `ida-pro-analysis.md` | 修改（+5 行） |
| D | 通用 Frida 脱壳脚本（已有） | `disassembler/frida_unpack.py`（现有 460 行，增强） | 修改（增加 64-bit PE 支持等） |
| E | 密码学验证模式库 | `ida-pro-analysis-knowledge-base/crypto-validation-patterns.md` | 新增（~80 行） |
| F | 静态 vs 动态决策树 | 合入方案 A（packer-handling.md） | 不单独占主 prompt 行数 |

### 2.2 依赖关系

```
C（主 prompt 规则）
  └── 引用 A（packer-handling.md）
        ├── 包含 F（决策树）
        └── 引用 D（disassembler/frida_unpack.py）

B（dynamic-analysis.md）— 独立知识库
E（crypto-validation-patterns.md）— 独立知识库
```

### 2.3 方案 A+F：packer-handling.md 增加动态脱壳 + 决策树

**现状**：`packer-handling.md` 只有 3 个阶段（壳检测 → 已知壳 → 静态分析脱壳），缺少动态脱壳路径和决策树。

**改动内容**：

1. 在阶段 2 和阶段 3 之间插入**决策树**（方案 F）：

```
静态脱壳 vs 动态脱壳决策：
  1. 先尝试静态脱壳（分析 stub → Python 脱壳机）— 适合简单变换（XOR/ADD/ROL）
  2. 静态脱壳失败 2 次后 → 立即切换动态脱壳（使用 disassembler/frida_unpack.py）
  3. 禁止在静态脱壳上花费超过 30 分钟
  4. 动态脱壳成功后 → 解壳后加载规则（方案 C）
```

2. 新增**阶段 3.5：动态脱壳**（方案 A）：

```
阶段 3.5：动态脱壳（Frida 进程 dump）

当静态脱壳失败时，使用 Frida 启动目标进程，等待代码解壳后 dump 内存。

步骤：
  1. 执行 frida_unpack.py
     python disassembler/frida_unpack.py <目标二进制> -o <输出路径>
  2. 脚本会：spawn 进程 → resume → 轮询检测代码段 → dump 内存 → 重建 PE → 保存
  3. 验证输出文件（file 命令 + 大小检查）
  4. 将 dump 文件加载到 IDA（见主 prompt 解壳后加载规则）
  5. 用 query.py 全部分析能力分析解壳后的二进制

注意：
  - 需要 frida（`pip install frida frida-tools`）。如未安装，脚本会提示安装命令并退出，此时回退到静态脱壳并告知用户限制
  - 部分壳会检测 Frida，可能需要反反调试（不在本方案范围内）
  - dump 时机很重要：太早代码还没解壳，太晚可能有反调试。脚本已内置轮询机制
  - 当前仅支持 EXE（DLL 需宿主进程，不在模板自动处理范围内）
  - 命令中 `python` 在部分系统上可能需要改为 `python3`
```

3. 新增**解壳后后续流程（增强版）**：

```
脱壳成功后（无论静态还是动态）：
  1. 将解壳产物加载到 IDA（见主 prompt 解壳后加载规则）
  2. 用新 .i64 文件路径继续正常分析流程
  3. 脱壳机/dump 脚本保留在 $TASK_DIR/
```

4. 将现有 `packer-handling.md` 第 95 行的"3 次仍失败 → 告知用户静态分析无法完成脱壳，建议使用调试器或其他工具"修改为"2 次失败后 → 切换到动态脱壳（阶段 3.5）"。
5. 替换现有 `packer-handling.md` 第 109-114 行（"脱壳后后续流程"章节）为增强版内容（自动加载到 IDA，不再提示用户手动操作）。

### 2.4 方案 B：dynamic-analysis.md

**新建文件**：`ida-pro-analysis-knowledge-base/dynamic-analysis.md`

包含以下章节：

#### §1 触发条件

- 需要运行时验证算法理解是否正确
- 需要动态脱壳（已由 packer-handling.md 引导至此）
- 需要追踪运行时数据流
- GUI 程序需要自动化交互

#### §2 Frida 版本适配

关键 API 差异表（Frida 16 → 17）：

| Frida 16 | Frida 17 | 说明 |
|----------|----------|------|
| `Memory.readU8(ptr(0xaddr))` | `ptr(0xaddr).readU8()` | 读取方法挂在指针对象上 |
| `Memory.readByteArray(ptr, n)` | `ptr.readByteArray(n)` | 同上 |
| `Memory.writeUtf8String(ptr, s)` | `ptr.writeUtf8String(s)` | 写入同理 |
| `Module.getExportByName("dll", "func")` | `Process.getModuleByName("dll").getExportByName("func")` | 先获取模块对象 |
| `Memory.allocUtf8String(s)` | 不变 | |
| `NativeFunction(...)` | 不变 | |

适配策略：脚本开头检测 `Frida.version`，根据版本选择 API 风格。或者直接使用 Frida 17 风格（当前主流版本）。

#### §3 加壳程序动态分析模式

```
spawn → attach → resume → 轮询解壳 → dump/hook

关键发现：spawn 后代码仍是加密的！必须 resume 后等待解壳。
检测解壳完成：轮询入口点地址，直到字节变为合法指令（如 0x55 = push ebp）。
```

#### §4 GUI 程序处理模式（仅 Windows）

> 以下 Win32 API 自动化模式仅适用于 Windows 平台。Linux/macOS 需使用 X11/Wayland 自动化（不在本方案范围内）。

1. **禁止** `SendMessageA(BM_CLICK)` — 同步调用，MessageBox 弹出后阻塞脚本线程
2. **使用** `PostMessageA(hwnd, WM_COMMAND, btn_id, btn_hwnd)` — 异步，不阻塞
3. **使用** `SetDlgItemTextA(hwnd, ctrl_id, text_ptr)` 设置编辑框内容 — 不要直接写内存缓冲区
4. **读取结果**：`EnumWindows` + `GetWindowTextA` 遍历窗口找 MessageBox

#### §5 NativeFunction 调用限制

加壳/SEH 程序中 `NativeFunction` 直接调用可能崩溃（Frida JIT 与 SEH handler 冲突）。替代方案：
- Hook 目标函数的返回点，通过 GUI 输入模拟触发
- 用 `Interceptor.attach` 监控而非直接调用

#### §6 进程清理模板

```
每次 Frida 脚本执行必须有严格超时：
  - Python 端：time.sleep(max_wait) 后 kill 进程（Windows: `taskkill /PID {pid} /F`，Unix: `kill -9 {pid}`）
  - JS 端：setTimeout(cleanup, max_wait_ms)
  - 无论成功失败，最后都 session.detach()
  - GUI 程序弹出模态对话框时进程不会自行退出，必须 kill
```

### 2.5 方案 C：主 prompt 增加解壳后加载规则

在 `ida-pro-analysis.md` 的"加壳/混淆二进制处理策略"小节（第 192-200 行）增加 5 行规则：

```
**解壳后加载规则**（脱壳成功后必须遵守）：
将解壳产物（脱壳机输出或 Frida dump）加载到 IDA：
  "$IDAT" -A -S"$SCRIPTS_DIR/query.py" -L"$TASK_DIR/load.log" "$TASK_DIR/<脱壳产物文件名>"
然后用 query.py 的全部分析能力（decompile/strings/xrefs 等）进行分析。
禁止在解壳产物上用 capstone/手动反汇编代替 idat — idat 的反编译器更准确。
```

### 2.6 方案 D：通用 Frida 脱壳脚本（已有）

**已有文件**：`disassembler/frida_unpack.py`（460 行），功能完整的 Frida PE 脱壳工具。

**已有能力**：
1. `frida.spawn()` 目标进程
2. `frida.attach()` + `session.create_script()` 加载 JS 监控代码
3. JS 端：解析 PE 结构 → 监控代码段写入 → 检测写入稳定后自动 dump
4. Python 端：重建 PE 文件（修正段表）→ 输出可执行文件
5. 异常处理：进程崩溃/超时仍尝试 dump 当前状态

**调用方式**：
```bash
python disassembler/frida_unpack.py <目标二进制> [-o <输出路径>] [-w <等待秒数>]
```

**需要增强的点**：
- 支持 64-bit PE（当前仅 32-bit：`Memory.readU32` 读取 ImageBase 和 SizeOfImage）
  - 检测 PE magic：PE32（0x10B）vs PE32+（0x20B），PE32+ 的 ImageBase 在 offset 24、8 字节
- 支持 DLL 目标（当前仅 EXE）
  - DLL 需要宿主进程（如 `rundll32.exe`），使用 `frida.attach()` 而非 `frida.spawn()`
  - 不在本次增强范围内，在 `packer-handling.md` 中注明此限制

脚本不在 `scripts/registry.json` 中注册（不在 idat 中运行），在 `packer-handling.md` 中引用其路径和用法。

Frida 未安装时不自动安装（避免修改用户环境），输出安装提示并回退到静态脱壳。

### 2.7 方案 E：密码学验证模式库

**新建文件**：`ida-pro-analysis-knowledge-base/crypto-validation-patterns.md`

包含常见密码学验证模式，帮助 AI 快速识别和逆向：

#### §1 MD5 + 比较
- 识别特征：常量 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476
- 常见变体：比较全部 16 字节 / 前 8 字节 / 后 8 字节 / 转为 hex 字符串再比较
- 注意：MD5 context 结构中 digest 的偏移（通常 state(16) + count(8) + buffer(64) = 88 字节后）

#### §2 RSA 签名验证
- 识别特征：常量 65537（0x10001），大数运算，modpow 函数
- 常见变体：公钥验证（msg^e mod n == expected）、私钥签名（sig^e mod n == msg）
- 逆向策略：分解 n 得到 p、q → 计算 d = e^(-1) mod φ(n) → 伪造签名

#### §3 RC4
- 识别特征：256 字节 S-box 初始化 + i/j 双指针交换
- 关键：RC4 是对称的，加密 = 解密（同一密钥）

#### §4 Base64 编解码
- 识别特征：字母表 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
- 4 字符 → 3 字节映射，'=' 填充
- 查找表函数：通常对输入字符做范围判断（'A'-'Z' → 0-25, 'a'-'z' → 26-51, '0'-'9' → 52-61）

#### §5 Hex 编解码
- 识别特征：查找表 "0123456789ABCDEF"，每个字节拆为高低 nibble
- 常见用途：将二进制数据转为可读 hex 字符串用于比较

#### §6 组合模式
- 最常见：Base64Decode(Serial) → RC4 解密 → MD5 比较 + RSA 签名验证
- 识别策略：从字符串（Base64 字母表、数字串、hex 串）反推编码层次

### 2.8 主 prompt 触发机制

在 `ida-pro-analysis.md` 的现有"加壳/混淆二进制处理策略"小节中，增加对 B 和 E 的触发引用：

```
**触发条件**（新增）：
- 需要动态分析（如：静态分析无法确定运行时行为、算法验证需要实际输入/输出对比、需要 hook 运行时函数）时 → 读取 `$SCRIPTS_DIR/ida-pro-analysis-knowledge-base/dynamic-analysis.md`
- 反编译代码中出现已知密码学常量（0x67452301 等 MD5 初始化值、65537/0x10001 等 RSA 指数、S-box 初始化模式）或 Base64/Hex 字母表时 → 读取 `$SCRIPTS_DIR/ida-pro-analysis-knowledge-base/crypto-validation-patterns.md`
```

---

## 3. 实现规范

### 3.1 改动范围表

| 文件 | 改动类型 | 行数变化 | 影响范围 |
|------|---------|---------|---------|
| `ida-pro-analysis.md` | 修改 | +10 行（192-200 行区域） | 主 prompt，AI 编排行为 |
| `packer-handling.md` | 修改 | +80 行（现有 128 → ~210） | 知识库，按需加载 |
| `dynamic-analysis.md` | 新增 | ~120 行 | 知识库，按需加载 |
| `crypto-validation-patterns.md` | 新增 | ~80 行 | 知识库，按需加载 |
| `disassembler/frida_unpack.py` | 修改 | +20 行（增加 64-bit PE 支持） | 独立脚本，不在 idat 中运行 |

### 3.2 不修改的文件

- `_base.py`、`_utils.py`、`query.py`、`update.py` — 无变更
- `scripts/registry.json` — frida_unpack.py 不在 idat 中运行，不注册
- `script-generation.md` — 无变更

### 3.3 编码规则

- `disassembler/frida_unpack.py` 是纯 Python 脚本（不依赖 IDAPython），不受 AGENTS.md 编码规范约束
- 知识库 .md 文件必须自包含（不依赖主 prompt 上下文即可理解）
- 主 prompt 中使用相对路径引用知识库文件

---

## 4. 验收标准

### 4.1 功能验收

- [ ] A: `packer-handling.md` 包含阶段 3.5（动态脱壳）和决策树
- [ ] B: `dynamic-analysis.md` 包含 Frida 版本适配表、GUI 处理模式、进程清理模板
- [ ] C: `ida-pro-analysis.md` 包含"解壳后加载规则"（禁止 capstone，必须用 idat）
- [ ] D: `disassembler/frida_unpack.py` 支持 64-bit PE（检测 PE32/PE32+ magic）
- [ ] E: `crypto-validation-patterns.md` 包含 MD5/RSA/RC4/Base64/Hex/组合模式
- [ ] F: 决策树合入 packer-handling.md（静态 2 次失败 → 切动态）
- [ ] 主 prompt 中有 B 和 E 的触发引用

### 4.2 回归验收

- [ ] 非加壳二进制分析流程不受影响（策略仅在 packer_detected 或特定触发条件时激活）
- [ ] 已知壳（UPX）场景仍优先使用 `upx -d`
- [ ] 主 prompt 总行数 ≤ 500 行（当前 488 + 10，含 2 行实现余量）
- [ ] 知识库文件自包含，可独立理解

### 4.3 架构验收

- [ ] 依赖方向合规：主 prompt → 知识库 → 脚本模板（单向）
- [ ] frida_unpack.py 不在 idat 中运行，不注册到 registry.json
- [ ] 知识库文件全部位于 `ida-pro-analysis-knowledge-base/` 目录

---

## 5. 与现有文档的关系

| 现有文档 | 关系 |
|---------|------|
| [需求-加壳二进制静态分析脱壳流程](需求-加壳二进制静态分析脱壳流程.md) | 本次需求是其后续进化：静态脱壳 → 增加"动态脱壳"分支 + 决策树 + 解壳后加载规则 |
| [需求-加壳检测与异常分析增强](需求-加壳检测与异常分析增强.md) | 上上次进化，本次增强其产出的 `packer-handling.md` 知识库 |
| [需求-进化流程渐进式披露与Prompt瘦身](需求-进化流程渐进式披露与Prompt瘦身.md) | 本次新增内容主要通过知识库按需加载，主 prompt 仅增加 ~10 行 |
