# 需求：加壳检测与异常分析增强

## 1. 背景与目标

### 1.1 背景

在一次 UPX 加壳 crackme 二进制文件的分析中，系统暴露出以下严重问题：

1. **segments 查询完全失败**：`query.py:570` 调用 `ida_segment.get_qty()` 返回 0（该 API 在 IDA 9.1 中不存在），导致 AI 无法获取段信息，浪费了多轮对话在无效猜测上
2. **无壳检测能力**：当 IDA 仅识别出 1 个函数、0 个导入时，系统没有任何机制识别"这是一个加壳二进制"，AI 盲目尝试各种查询直到发现异常
3. **无处理策略指导**：`ida-pro-analysis.md`（496 行）中没有任何关于 UPX、packer、obfuscation、OEP、entropy 的说明，AI 在遇到加壳场景时缺乏应对策略
4. **静默错误吞噬**：`query.py:577-579` 的 `segm_class()` 异常被 `except: pass` 吞噬，违反项目编码规范

**失败案例数据**：
- 8 次 idat 调用，4 个手写脚本，约 12 轮对话，3 次失败
- AI 浪费 6+ 轮在加壳二进制上盲目尝试查询，最终靠手动 PE 解析解决

### 1.2 目标

通过 4 个改进方案，使系统能够：
- **正确获取段信息**（修复 bug）
- **自动检测加壳/混淆**（新增查询类型）
- **AI 遇到加壳时有明确的应对策略**（增强 prompt）
- **段查询提供异常信号标注**（增强现有查询）

### 1.3 评估维度关联

| 方案 | 减少上下文 | 减少对话轮数 | 提升速度 | 提升准确性 |
|------|-----------|-------------|---------|-----------|
| 方案1（segments bug 修复） | ✅ | ✅ 减少 3-4 轮 | ✅ | ✅ 消除错误数据 |
| 方案2（packer_detect 查询） | ✅ 一次返回结构化结果 | ✅ 减少 6+ 轮 | ✅ | ✅ |
| 方案3（prompt 加壳策略） | ✅ | ✅ 减少 3-5 轮 | ✅ | ✅ |
| 方案5（segments 异常标注） | ✅ | ✅ | — | ✅ 提前发现异常 |

---

## 2. 技术方案

### 2.1 方案1：修复 segments 查询 API bug

**问题**：`query.py:570` 使用 `ida_segment.get_qty()` 获取段数量，该函数在 IDA 9.1 中不存在（返回 0 或抛出 AttributeError），导致 segments 查询始终返回空列表。

**修复**：将 `ida_segment.get_qty()` 替换为 `ida_segment.get_segm_qty()`。

同时修复 `query.py:577-579` 的静默异常吞噬问题。

**影响范围**：`query.py` 的 `_query_segments()` 函数（约 20 行）。

### 2.2 方案2：新增 packer_detect 查询类型

**新增查询类型 `packer_detect`**，通过多维信号分析检测加壳/混淆：

| 信号 | 检测逻辑 | 权重 |
|------|---------|------|
| 段名特征 | 段名包含 "UPX"、".upy"、".nsp0"、".nsp1"、".pec2"、"MPRESS" 等已知壳段名 | 高 |
| 段数量异常 | 段数量 ≤ 2 且代码段占比 > 95%（典型加壳特征） | 中 |
| 函数数量异常 | 函数总数 ≤ 5 且有入口点 | 高 |
| 导入数量异常 | 导入函数总数 = 0 或 ≤ 3 | 高 |
| entropy 估算 | 对代码段采样字节分布，高熵（>7.0）暗示加密/压缩 | 中 |

**输出结构**：

```json
{
  "packer_detected": true,
  "confidence": "high",
  "packer_name": "UPX",
  "signals": [
    {"type": "segment_name", "detail": "段 UPX0 存在", "weight": "high"},
    {"type": "segment_name", "detail": "段 UPX1 存在", "weight": "high"},
    {"type": "function_count", "detail": "仅 1 个函数", "weight": "high"},
    {"type": "import_count", "detail": "0 个导入函数", "weight": "high"}
  ],
  "recommendation": "检测到 UPX 壳，建议先脱壳后分析。可尝试 upx -d <file> 脱壳后重新加载到 IDA。",
  "stats": {
    "segment_count": 3,
    "function_count": 1,
    "import_count": 0,
    "entry_points": 1
  }
}
```

**实现要点**：
- 在 `query.py` 中新增 `_query_packer_detect()` 函数
- 注册到 `_QUERY_HANDLERS` 字典
- 纯 IDAPython 实现，不依赖外部工具（不调用 `upx` 命令）
- 采样式 entropy 估算：取段的前 1024 字节计算 Shannon entropy

### 2.3 方案3：ida-pro-analysis.md 增加加壳处理策略

在 `ida-pro-analysis.md` 的"执行流程"部分之后、"进度输出规范"之前，新增一节 **"加壳/混淆二进制处理策略"**：

**内容要点**：
1. **何时触发**：首次查询 entry_points 或 segments 后，主动调用 `packer_detect` 检查
2. **检测到加壳后的推荐流程**：
   - 告知用户检测到壳类型及置信度
   - 建议先脱壳再分析
   - 如果用户坚持分析加壳版本，提供有限的分析能力（entry_point 附近的手动反汇编等）
3. **不推荐的操作**：不要在加壳二进制上盲目执行 functions/decompile/strings 等查询（结果无意义）

### 2.4 方案5：增强 segments 查询的异常信号标注

在 `_query_segments()` 的输出中，为每个段增加 `anomaly_hints` 字段，标注可能是加壳指示器的异常信号：

```json
{
  "segments": [
    {
      "name": "UPX0",
      "start": "0x401000",
      "end": "0x403000",
      "size": 8192,
      "type": "",
      "perm": "r",
      "anomaly_hints": ["known_packer_segment:UPX", "zero_perm_or_readonly_code"]
    },
    {
      "name": "UPX1",
      "start": "0x403000",
      "end": "0x405000",
      "size": 8192,
      "type": "",
      "perm": "rw",
      "anomaly_hints": ["known_packer_segment:UPX"]
    }
  ],
  "packer_warning": {
    "detected": true,
    "packer_name": "UPX",
    "confidence": "high"
  }
}
```

**异常信号检测逻辑**（内联在 `_query_segments()` 中）：

| 信号 | 检测条件 | hint 文本 |
|------|---------|----------|
| 已知壳段名 | 段名匹配 UPX/MPRESS/Themida/VMProtect 等模式 | `known_packer_segment:<壳名>` |
| 超大代码段 | 单个段占总体积 > 90% | `oversized_segment` |

---

## 3. 实现规格

### 3.1 修改文件清单

| 文件 | 修改类型 | 依赖 |
|------|---------|------|
| `query.py` | 修改 `_query_segments()`，新增 `_query_packer_detect()` | 依赖 `_base.py`、`_utils.py` |
| `ida-pro-analysis.md` | 新增加壳处理策略章节 | 无代码依赖 |

### 3.2 依赖关系

```
_base.py ← _utils.py ← query.py（现有依赖，不变）
                        ↕
                  ida-pro-analysis.md（prompt 文档，独立修改）
```

- 方案1 和方案5 修改 `_query_segments()` → 同一个函数，合并实现
- 方案2 新增 `_query_packer_detect()` → 独立函数，依赖 `_utils.py` 的 `hex_addr` 等
- 方案3 修改 `ida-pro-analysis.md` → 完全独立

### 3.3 实现顺序（按依赖关系）

1. **任务 A**：修复 `_query_segments()` bug + 异常信号标注（方案1 + 方案5 合并）
2. **任务 B**：新增 `_query_packer_detect()` 查询类型（方案2）
3. **任务 C**：更新 `ida-pro-analysis.md` 加壳处理策略（方案3）

### 3.4 API 使用说明

- `ida_segment.get_segm_qty()`：IDA 9.x 正确 API（替换 `get_qty()`）
- `ida_segment.getnseg(i)`：按索引获取段对象（现有用法，正确）
- `ida_segment.get_segm_name(seg)`：获取段名（现有用法，正确）
- `ida_segment.segm_class(seg)`：获取段类（现有用法，需正确处理异常）

### 3.5 已知壳段名模式

```python
_PACKER_SEGMENT_PATTERNS = {
    "UPX": ["UPX0", "UPX1", "UPX2", ".upx"],
    "MPRESS": [".nsp0", ".nsp1", ".nsp2"],
    "Themida": [".themida", ".winlice"],
    "VMProtect": [".vmp0", ".vmp1"],
    "ASPack": [".aspack"],
    "PECompact": [".pec2"],
    "Enigma": [".enigma1", ".enigma2"],
}
```

### 3.6 Entropy 估算算法

对段的起始 1024 字节（或全部，如果段更短）计算 Shannon entropy：

```python
import math
import ida_bytes

def _estimate_entropy(ea, size):
    sample_size = min(size, 1024)
    freq = [0] * 256
    for i in range(sample_size):
        b = ida_bytes.get_byte(ea + i)
        freq[b] += 1
    entropy = 0.0
    for count in freq:
        if count > 0:
            p = count / sample_size
            entropy -= p * math.log2(p)
    return entropy
```

- 高熵阈值 > 7.0：暗示加密/压缩数据
- 正常代码段 entropy 通常在 5.0-6.5 之间

---

## 4. 验收标准

### 4.1 方案1（segments bug 修复）

- [ ] `_query_segments()` 使用 `ida_segment.get_segm_qty()` 而非 `get_qty()`
- [ ] `segm_class()` 异常不再被静默吞噬，改为返回空字符串并记录日志
- [ ] 语法检查通过：`python3 -c "compile(open('query.py').read(), 'query.py', 'exec')"`
- [ ] 在真实 UPX 加壳 .i64 文件上 segments 查询返回非空段列表

### 4.2 方案2（packer_detect 查询）

- [ ] `_QUERY_HANDLERS` 中包含 `"packer_detect"` 键
- [ ] 在 UPX 加壳二进制上执行 `packer_detect` 查询返回 `packer_detected: true`
- [ ] 在正常未加壳二进制上执行 `packer_detect` 查询返回 `packer_detected: false`
- [ ] 输出包含 `signals`、`recommendation`、`stats` 字段
- [ ] `recommendation` 中包含脱壳建议
- [ ] 语法检查通过

### 4.3 方案3（prompt 加壳策略）

- [ ] `ida-pro-analysis.md` 包含"加壳/混淆二进制处理策略"章节
- [ ] 章节说明何时触发检测、检测到后的推荐流程
- [ ] 章节说明不推荐的操作（避免盲目查询加壳二进制）
- [ ] query.py 查询类型表中包含 `packer_detect` 的说明

### 4.4 方案5（segments 异常标注）

- [ ] segments 查询结果中每个段包含 `anomaly_hints` 字段（数组）
- [ ] 已知壳段名（如 UPX0、UPX1）被标注为 `known_packer_segment:UPX`
- [ ] segments 结果中包含 `packer_warning` 顶层字段（检测到壳时）
- [ ] 正常段 `anomaly_hints` 为空数组

### 4.5 端到端验证

- [ ] 使用 UPX 加壳二进制（如 `crackme_crypto.exe.i64`）执行完整流程：
  1. `segments` 查询 → 返回段列表 + `packer_warning`
  2. `packer_detect` 查询 → 返回 `packer_detected: true, packer_name: "UPX"`
- [ ] 使用未加壳二进制执行 `packer_detect` → 返回 `packer_detected: false`

---

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

| 现有文档 | 关系 |
|---------|------|
| [需求-IDA-Pro-AI智能分析命令-v2](需求-IDA-Pro-AI智能分析命令-v2.md) | 本需求是 v2 的增量增强，修改其产出的 `query.py` 和 `ida-pro-analysis.md` |
| [AGENTS.md](../../AGENTS.md) | 遵循其中的编码规范（禁止 import idc/idaapi、双引号、中文日志） |
| [rules/headless-automation-guide.md](../../rules/headless-automation-guide.md) | 遵循 headless 脚本的三模式实现规范 |

---

## 6. 不做的事

以下内容在本需求中**不**实现，作为未来优化方向：

1. **自动脱壳**：不集成 `upx -d` 或其他脱壳工具（超出 IDAPython 脚本职责范围）
2. **OEP（原始入口点）查找**：不实现运行时 OEP 定位（需要调试器支持，当前系统以 headless 分析为主）
3. **更多壳类型签名**：仅覆盖常见壳（UPX、MPRESS、Themida、VMProtect 等），不建立完整壳签名库
4. **entropy 精确计算**：使用采样估算而非全段扫描，平衡速度和精度
