fix(workflow): feasibility gate + side-path patches 6-10 (#65)

- User-command feasibility gate: obey goals not blind step order;
  blocked steps require explain + confirm; forced steps mark quality
- Redo-X clarified: named step or confirmed prerequisite path;
  unpack is prerequisite not substitute for import Evidence
- Patch 6: post-unpack self-check crash -> dynamic CreateFile/GetFileSize
- Patch 7+10: TLS -> EP -> sensitive API -> ExitProcess dump baseline
- Patch 8: high-risk API cluster hints when import table is huge
- Patch 9: SHOULD time-boxes (15min static / ~200 steps dynamic), overridable
- Wire RULES (en/zh), agent-obedience, malware, r2/ida; extend verify asserts
This commit is contained in:
yhc
2026-08-12 15:06:38 +08:00
parent 899fedd36f
commit 831ab83083
8 changed files with 92 additions and 27 deletions
+3 -1
View File
@@ -216,7 +216,9 @@ After task completion (vulnerability verified / reverse complete / flag captured
| "Task is basically done, don't need checklist" | **Task completion = ALL Checklist items checked.** Unchecked checklist = task NOT complete. | | "Task is basically done, don't need checklist" | **Task completion = ALL Checklist items checked.** Unchecked checklist = task NOT complete. |
| "I'll reply to user first, continue after confirmation" | **Don't wait for confirmation on deterministic steps.** Execute while informing user. Only pause at genuine decision points. | | "I'll reply to user first, continue after confirmation" | **Don't wait for confirmation on deterministic steps.** Execute while informing user. Only pause at genuine decision points. |
| "I understand the rules, please tell me your task" | **This is the WORST failure mode.** Correct behavior: proactively match user intent to routing table, output analysis, start executing. | | "I understand the rules, please tell me your task" | **This is the WORST failure mode.** Correct behavior: proactively match user intent to routing table, output analysis, start executing. |
| "User asked to redo import-table / step X, but I did something else more useful" | **Redo = redo the named step.** When user asks to redo X (e.g. import table check), MUST re-execute X and refresh its Evidence. FORBIDDEN to substitute another step or silently skip X. | | "User asked to redo import-table / step X, but I did something else more useful" | **Redo = redo the named step** (or the user-confirmed prerequisite path). MUST refresh Evidence for X. FORBIDDEN to substitute an unrelated step or silently skip X. Unpacking is a **prerequisite** for readable IAT, not a substitute for import Evidence. |
| "User said skip unpack and read IAT on a packed sample; I'll just dump the garbage table as done" | **Feasibility gate:** if X is blocked (packed/unreadable IAT), MUST state the blocker, recommend order (unpack/repair IAT or go dynamic), and **ask confirm**. If user forces X, do it and mark `quality=unreadable/packed`; FORBIDDEN to draw capability-negative conclusions from garbage IAT. |
| "Self-check crash after unpack; keep patching the file on disk" | **Patch 6:** record E-self-check-crash / E-iat-repair-fail, switch to dynamic (bp CreateFile/GetFileSize). FORBIDDEN endless static file thrash. |
| "IAT repair keeps failing; I'll grind more static unpackers" | **IAT repair iron rule:** try auto/semi-auto repair first; on tool error or unreable binary after repair, STOP static IAT, record E-iat-repair-fail, switch to dynamic API breakpoints. FORBIDDEN infinite static IAT thrash. | | "IAT repair keeps failing; I'll grind more static unpackers" | **IAT repair iron rule:** try auto/semi-auto repair first; on tool error or unreable binary after repair, STOP static IAT, record E-iat-repair-fail, switch to dynamic API breakpoints. FORBIDDEN infinite static IAT thrash. |
| "No import table (.NET) so the hard gate does not apply" | **Equivalent anchor still MUST:** .NET → dnSpy/IL/metadata summary into E-imports slot; DLL/SYS → E-exports alongside imports. FORBIDDEN to skip the gate. | | "No import table (.NET) so the hard gate does not apply" | **Equivalent anchor still MUST:** .NET → dnSpy/IL/metadata summary into E-imports slot; DLL/SYS → E-exports alongside imports. FORBIDDEN to skip the gate. |
+3 -1
View File
@@ -315,7 +315,9 @@ AI Agent 在遇到阻力时会自动生成"合理借口"来跳过步骤。以下
| "这个太简单了不需要记录 journal" | **简单任务也有踩坑价值。** 至少记录:目标类型 + 用了什么 + 有无意外。一行也行,但必须写。 | | "这个太简单了不需要记录 journal" | **简单任务也有踩坑价值。** 至少记录:目标类型 + 用了什么 + 有无意外。一行也行,但必须写。 |
| "我先回复用户,等用户确认后再继续" | **不需要等确认。** 如果路由已明确且下一步是确定性的(如安装工具、读取文件),直接执行同时告知用户。不要在每一步都等用户点头。 | | "我先回复用户,等用户确认后再继续" | **不需要等确认。** 如果路由已明确且下一步是确定性的(如安装工具、读取文件),直接执行同时告知用户。不要在每一步都等用户点头。 |
| "我理解了规则,请告诉我你的具体任务" | **这是最严重的失败模式。** 读完规则后的正确行为是主动匹配用户意图到路由表,输出分析,开始执行。不是回传问题给用户。 | | "我理解了规则,请告诉我你的具体任务" | **这是最严重的失败模式。** 读完规则后的正确行为是主动匹配用户意图到路由表,输出分析,开始执行。不是回传问题给用户。 |
| "用户让我重做导入表/某一步,但我改做了别的更有用的步骤" | **重做 = 重做被点名的同一步。** 用户要求重做 X(如导入表检查)时 MUST 重新执行 X 并更新对应 Evidence;禁止用其他步骤冒充完成,禁止静默跳过 X。 | | "用户让我重做导入表/某一步,但我改做了别的更有用的步骤" | **重做 = 重做被点名的同一步**(或经用户确认的合法前提路径)。MUST 更新对应 Evidence;禁止用无关步骤冒充,禁止静默跳过。脱壳是可读 IAT 的**前提**,不是导入表 Evidence 的**替代**。 |
| "用户说加壳样本先别脱壳先看导入表;我直接交花表算完成" | **可行性门闩:** X 被阻塞时 MUST 说明阻塞、给推荐顺序(先脱壳/修 IAT 或转动态)、**请用户确认**。用户强制则执行并标 `quality=unreadable/packed`;禁止用花表下「无网络能力」等结论。 |
| "脱壳后闪退,我继续在磁盘上改文件死磕" | **补丁 6:** 记 E-self-check-crash / E-iat-repair-fail,转动态(bp CreateFile/GetFileSize)。禁止无限静态改文件。 |
| "IAT 修不好,我再静态试几种壳工具拖时间" | **IAT 修复铁律:** 优先自动/半自动修复;工具报错或修完无法运行 → 立即停静态 IAT,记 E-iat-repair-fail,转动态 API 断点抓取。禁止无限静态死磕。 | | "IAT 修不好,我再静态试几种壳工具拖时间" | **IAT 修复铁律:** 优先自动/半自动修复;工具报错或修完无法运行 → 立即停静态 IAT,记 E-iat-repair-fail,转动态 API 断点抓取。禁止无限静态死磕。 |
| ".NET / 没导入表,硬门不适用,我跳过" | **等价锚点仍 MUST:** .NET 用 dnSpy/IL/元数据摘要写入 E-imports 语义槽;DLL/SYS 必须并列 E-exports。禁止空过。 | | ".NET / 没导入表,硬门不适用,我跳过" | **等价锚点仍 MUST:** .NET 用 dnSpy/IL/元数据摘要写入 E-imports 语义槽;DLL/SYS 必须并列 E-exports。禁止空过。 |
+1 -1
View File
@@ -249,7 +249,7 @@ idapro_survey_binary(detail_level="minimal")
- **干净导入表**:注明动态加载嫌疑,推动动态 API 断点验证 - **干净导入表**:注明动态加载嫌疑,推动动态 API 断点验证
- 热门函数(高 xref 计数的函数通常是关键逻辑) - 热门函数(高 xref 计数的函数通常是关键逻辑)
**硬门禁**:未将 imports 视图/分类摘要(或合法等价锚点)写入 Evidence 前,MUST NOT 进入 Step 4 深挖结论,MUST NOT 声称 survey 完成。导入表为空或查询失败时仍 MUST 记录失败现象。加壳 IAT 修复失败时 MUST 记 `E-iat-repair-fail` 并转动态调试抓 API,禁止静态死磕。用户要求重做导入表/IAT 检查时 MUST 重做被点名步骤,禁止改换其他步骤。 **硬门禁**:未将 imports 视图/分类摘要(或合法等价锚点)写入 Evidence 前,MUST NOT 进入 Step 4 深挖结论,MUST NOT 声称 survey 完成。导入表为空或查询失败时仍 MUST 记录失败现象。加壳 IAT 修复失败时 MUST 记 `E-iat-repair-fail` 并转动态调试抓 API,禁止静态死磕。用户要求重做导入表/IAT 检查时 MUST 重做被点名步骤(阻塞时可行性门闩:说明+确认;强制则标 quality=unreadable),禁止改换无关步骤。
### Step 4: 深入关键函数 ### Step 4: 深入关键函数
``` ```
@@ -81,7 +81,9 @@ MAY — 真正可选的
| "我没找到 tool-index,我就直接猜路径" | **缺文件比猜错路径安全 100 倍。** tool-index 缺失时先运行 refresh-tool-index.ps1 生成。 | | "我没找到 tool-index,我就直接猜路径" | **缺文件比猜错路径安全 100 倍。** tool-index 缺失时先运行 refresh-tool-index.ps1 生成。 |
| "用户没明确说要报告,我就不写了" | **报告是默认行为,不是可选。** 安全任务完成后必须生成报告,除非用户明确说"不要报告"。 | | "用户没明确说要报告,我就不写了" | **报告是默认行为,不是可选。** 安全任务完成后必须生成报告,除非用户明确说"不要报告"。 |
| "这个太简单了不需要记录 journal" | **简单任务也有踩坑价值。** 至少记录:目标类型 + 用了什么 + 有无意外,一行也行。 | | "这个太简单了不需要记录 journal" | **简单任务也有踩坑价值。** 至少记录:目标类型 + 用了什么 + 有无意外,一行也行。 |
| "用户让我重做导入表/某一步,但我改做了别的更有用的步骤" | **重做 = 重做被点名的同一步。** 用户要求重做 X(如导入表检查)时 MUST 重新执行 X 并更新对应 Evidence;禁止用其他步骤冒充完成,禁止静默跳过 X。 | | "用户让我重做导入表/某一步,但我改做了别的更有用的步骤" | **重做 = 重做被点名的同一步**(或经用户确认的合法前提路径)。MUST 更新对应 Evidence;禁止用无关步骤冒充,禁止静默跳过。脱壳是可读 IAT 的**前提**,不是导入表 Evidence 的**替代**。 |
| "用户说加壳样本先别脱壳先看导入表;我直接交花表算完成" | **可行性门闩:** X 被阻塞时 MUST 说明阻塞、给推荐顺序、**请用户确认**。用户强制则执行并标 `quality=unreadable/packed`;禁止用花表下能力否定结论。 |
| "脱壳后闪退,我继续在磁盘上改文件死磕" | **补丁 6:** 记 E-self-check-crash / E-iat-repair-fail,转动态(bp CreateFile/GetFileSize)。禁止无限静态改文件。 |
| "IAT 修不好,我再静态试几种壳工具拖时间" | **IAT 修复铁律:** 优先自动/半自动修复;工具报错或修完无法运行 → 立即停静态 IAT,记 E-iat-repair-fail,转动态 API 断点抓取。禁止无限静态死磕。 | | "IAT 修不好,我再静态试几种壳工具拖时间" | **IAT 修复铁律:** 优先自动/半自动修复;工具报错或修完无法运行 → 立即停静态 IAT,记 E-iat-repair-fail,转动态 API 断点抓取。禁止无限静态死磕。 |
| ".NET / 没导入表,硬门不适用,我跳过" | **等价锚点仍 MUST:** .NET 用 dnSpy/IL/元数据摘要写入 E-imports 语义槽;DLL/SYS 必须并列 E-exports。禁止空过。 | | ".NET / 没导入表,硬门不适用,我跳过" | **等价锚点仍 MUST:** .NET 用 dnSpy/IL/元数据摘要写入 E-imports 语义槽;DLL/SYS 必须并列 E-exports。禁止空过。 |
+20 -6
View File
@@ -62,9 +62,13 @@ Triage MUST 清单(Issue #65):
□ 【IAT 修复铁律】优先自动/半自动修复;若工具报错或修复后无法运行: □ 【IAT 修复铁律】优先自动/半自动修复;若工具报错或修复后无法运行:
- 立即终止继续静态 IAT 修复 - 立即终止继续静态 IAT 修复
- MUST 记录 E-iat-repair-fail(命令、工具、现象) - MUST 记录 E-iat-repair-fail(命令、工具、现象)
- ⏩ 转入 Phase 3 动态:API 断点(如 bp CreateFile)/ 硬件断点 / 内存搜索抓取导入 - 转入 Phase 3 动态:API 断点(如 bp CreateFile)/ 硬件断点 / 内存搜索抓取导入
- 这不算跳过导入表:路径已尝试并记 Evidence - 这不算跳过导入表:路径已尝试并记 Evidence
□ 用户要求重做「IAT 修复 / 导入表检查」:MUST 重做被点名步骤,禁止换步骤冒充 □ 【补丁 6】脱壳+修 IAT 后闪退/蓝屏(疑 CRC/大小自校验):
- 放弃继续静态修文件;记 E-self-check-crash 或并入 E-iat-repair-fail
- 转 Phase 3:对 CreateFile / GetFileSize / 哈希相关 API 下断
□ 用户指令可行性(§0.5):加壳时用户抢跑「先别脱壳先看导入表」→ 说明阻塞 + 请确认;强制则记 quality=unreadable/packed,禁止冒充完成有意义 IAT
□ 用户要求重做「IAT 修复 / 导入表检查」:MUST 重做被点名步骤(或经确认的前提协商结果),禁止换无关步骤冒充
``` ```
### Phase 2: 静态分析 ### Phase 2: 静态分析
@@ -84,7 +88,8 @@ Triage MUST 清单(Issue #65):
**DLL/SYS**:MUST 并列记录导出表 Evidence(E-exports,`rabin2 -E` 或等价) **DLL/SYS**:MUST 并列记录导出表 Evidence(E-exports,`rabin2 -E` 或等价)
**.NET**:无传统 IAT 时 MUST 用 dnSpy/IL/元数据/程序集引用与敏感 API 摘要作为等价锚点,写入 E-imports / E-triage-imports 语义槽 **.NET**:无传统 IAT 时 MUST 用 dnSpy/IL/元数据/程序集引用与敏感 API 摘要作为等价锚点,写入 E-imports / E-triage-imports 语义槽
**干净导入表**:仅基础 DLL、几乎无业务 API → MUST 注明动态加载嫌疑(LoadLibrary/GetProcAddress),SHOULD 转入 Phase 3 抓内存 API **干净导入表**:仅基础 DLL、几乎无业务 API → MUST 注明动态加载嫌疑(LoadLibrary/GetProcAddress),SHOULD 转入 Phase 3 抓内存 API
用户要求「重做导入表检查」:MUST 重做本项,禁止改换其他步骤冒充完成 用户要求「重做导入表检查」:MUST 重做本项(阻塞时先走可行性门闩协商),禁止改换其他步骤冒充完成
**高危 API 组合(补丁 8)**:表过长时优先输出恶意组合簇(如 FindWindow+WriteProcessMemory+CreateRemoteThread),过滤纯系统基础调用噪声
□ 资源段 → 嵌入 Payload(.rsrc 节) □ 资源段 → 嵌入 Payload(.rsrc 节)
□ 字符串表 → URL/C2/文件路径/Base64 blob □ 字符串表 → URL/C2/文件路径/Base64 blob
□ TLS 回调 → 调试器启动前执行 □ TLS 回调 → 调试器启动前执行
@@ -99,6 +104,10 @@ Triage MUST 清单(Issue #65):
□ ASD Azul: 开源恶意软件分析平台(2026 新发布) □ ASD Azul: 开源恶意软件分析平台(2026 新发布)
□ Cuckoo Sandbox: 经典开源(逐步被 CAPE 取代) □ Cuckoo Sandbox: 经典开源(逐步被 CAPE 取代)
调试起手式(补丁 7+10 · MUST 顺序,用户态调试器):
□ ① TLS 回调断点 → ② 入口点 EP 断点 → ③ 敏感 API 断点 → ④ ExitProcess/退出路径保底断点
□ ExitProcess 触发时:不急着重启;立即 dump memory,路径写入 Evidence(补丁 10)
监控重点: 监控重点:
□ 进程创建: CreateProcess / ShellExecute □ 进程创建: CreateProcess / ShellExecute
□ 文件操作: WriteFile → 勒索? DeleteFile → Wiper? □ 文件操作: WriteFile → 勒索? DeleteFile → Wiper?
@@ -106,12 +115,16 @@ Triage MUST 清单(Issue #65):
□ 网络: HTTP/DNS → C2 通信 □ 网络: HTTP/DNS → C2 通信
□ 内存: VirtualAllocEx → 进程注入 □ 内存: VirtualAllocEx → 进程注入
□ 服务: CreateService → 持久化 □ 服务: CreateService → 持久化
□ IAT 修复失败样本:在敏感 API 下断点 / 硬件执行断点 / 内存搜索捕捉真实导入 □ IAT 修复失败 / 自校验闪退样本:敏感 API + CreateFile/GetFileSize 断点 / 硬件执行断点 / 内存搜索
无行为应急分支(MUST): 无行为应急分支(MUST):
□ 沙箱无行为、秒退或无限休眠 → 检查反调试/反虚拟机(CPUID、计时、环境特征) □ 沙箱无行为、秒退或无限休眠 → 检查反调试/反虚拟机(CPUID、计时、环境特征)
□ 尝试硬件断点绕过、补丁检测点、或换物理机/更高保真环境 □ 尝试硬件断点绕过、补丁检测点、或换物理机/更高保真环境
□ 将「无行为 + 条件」写入 Evidence;禁止无条件写成「样本无害」 □ 将「无行为 + 条件」写入 Evidence;禁止无条件写成「样本无害」
时间盒(补丁 9 · SHOULD 默认,可覆盖):
□ 静态深挖约 15 分钟无关键路径 → 强制转入本 Phase 动态
□ 动态单步约 200 条指令无恶意线索 → 强制回静态字符串/交叉引用重锚
``` ```
### Phase 4: YARA 规则编写 ### Phase 4: YARA 规则编写
@@ -258,8 +271,9 @@ Triage RE Behav Intel Detect Remed
- [ ] 我是否执行了工作流中的每一步(而不是只阅读)? - [ ] 我是否执行了工作流中的每一步(而不是只阅读)?
- [ ] 导入表 MUST 检查是否已执行并写入 Evidence(E-imports 或 .NET 等价锚点)?DLL/SYS 是否含 E-exports? - [ ] 导入表 MUST 检查是否已执行并写入 Evidence(E-imports 或 .NET 等价锚点)?DLL/SYS 是否含 E-exports?
- [ ] 若 IAT 修复失败:是否记录 E-iat-repair-fail 并转入动态,而非静态死磕或静默跳过? - [ ] 若 IAT 修复失败或自校验闪退:是否记录 E-iat-repair-fail / E-self-check-crash 并转入动态?
- [ ] 重做请求是否回到被点名的同一步?干净导入表/沙箱无行为是否按旁路处理? - [ ] 重做请求是否回到被点名步骤或经确认的前提协商?阻塞时是否说明+请确认而非偷换步骤?
- [ ] 动态是否按 TLS→EP→敏感 API→ExitProcess 保底顺序预置断点?时间盒/高危 API 组合是否按旁路处理?
- [ ] 我是否基于 `tool-index` 使用了真实工具路径? - [ ] 我是否基于 `tool-index` 使用了真实工具路径?
- [ ] 我是否产出了可复现证据(命令/脚本/截图/报告)? - [ ] 我是否产出了可复现证据(命令/脚本/截图/报告)?
- [ ] 我是否完成并回写了 RULES 要求的 Checklist 项? - [ ] 我是否完成并回写了 RULES 要求的 Checklist 项?
+1 -1
View File
@@ -132,7 +132,7 @@ ERROR: Cannot find ...\share\format\dll\*.sdb
- 导入表「过干净」(仅基础 DLL):MUST 注明动态加载嫌疑,SHOULD 转入动态抓 API - 导入表「过干净」(仅基础 DLL):MUST 注明动态加载嫌疑,SHOULD 转入动态抓 API
3. .NET 等无传统 IAT:MUST 走等价锚点(dnSpy/IL/元数据摘要)写入同一 Evidence 语义槽,禁止空过 3. .NET 等无传统 IAT:MUST 走等价锚点(dnSpy/IL/元数据摘要)写入同一 Evidence 语义槽,禁止空过
4. 加壳样本 IAT 修复:x86 用 ImportREC(或等价)、x64 用 Scylla(或等价)。修复失败 MUST 记 `E-iat-repair-fail` 后转动态 API 断点;**禁止**在静态 IAT 上无限死磕(见 `reverse-engineering/references/re-agent-workflow.md` §1.2) 4. 加壳样本 IAT 修复:x86 用 ImportREC(或等价)、x64 用 Scylla(或等价)。修复失败 MUST 记 `E-iat-repair-fail` 后转动态 API 断点;**禁止**在静态 IAT 上无限死磕(见 `reverse-engineering/references/re-agent-workflow.md` §1.2)
5. 用户明确要求「重做导入表检查 / 重新检查导入表 / 重做 IAT」时:MUST 重做被点名步骤本身,**禁止改换为其他步骤冒充完成** 5. 用户明确要求「重做导入表检查 / 重新检查导入表 / 重做 IAT」时:MUST 重做被点名步骤本身(阻塞时先走可行性门闩:说明前提+请确认;强制则标 quality=unreadable),**禁止改换为无关步骤冒充完成**
未记录导入表(或合法等价锚点 / IAT 失败旁路)Evidence 前:MUST NOT 声称「基础侦察完成」,MUST NOT 进入工作流 2+ 的深挖结论。 未记录导入表(或合法等价锚点 / IAT 失败旁路)Evidence 前:MUST NOT 声称「基础侦察完成」,MUST NOT 进入工作流 2+ 的深挖结论。
@@ -1,7 +1,7 @@
# RE Agent 工作流门闩(静态↔动态) # RE Agent 工作流门闩(静态↔动态)
> 来源启发:binary-re 阶段划分、社区 RE skill(Frida/r2/Ghidra/IDA 循环)、Cerberus 三头环(静/动/插桩) > 来源启发:binary-re 阶段划分、社区 RE skill(Frida/r2/Ghidra/IDA 循环)、Cerberus 三头环(静/动/插桩)
> Issue #65 增量:IAT 修复铁律、恶意样本六阶段映射、.NET/DLL·SYS 等价路径(2026-08-12) > Issue #65 增量:IAT 修复铁律、六阶段映射、.NET/DLL·SYS 等价路径;用户指令可行性门闩;旁路补丁 6–10(2026-08-12)
> 适用:`reverse-engineering/`、`ida-reverse/`、`radare2/`、`malware-analysis/`、与 cre 角色交接 > 适用:`reverse-engineering/`、`ida-reverse/`、`radare2/`、`malware-analysis/`、与 cre 角色交接
## 0. 启动 ## 0. 启动
@@ -12,6 +12,21 @@
□ 角色:cre(ops/role-map) □ 角色:cre(ops/role-map)
``` ```
## 0.5 用户指令可行性门闩(Issue #65)
**原则**:服从用户**目标**,不盲从用户**步骤顺序**。跳步前必须说明前提并请确认;确认后的强制步骤必须做,且诚实标注 Evidence 质量。
| 情况 | Agent MUST |
|------|------------|
| 用户要做 X,且当前状态可得到**有效** Evidence | 执行 X,更新 Evidence |
| 用户要做 X,但存在**已知阻塞前提**(例:已判定加壳且静态 IAT 不可读) | **禁止**假装完成有意义的 IAT;① 一句话说清阻塞;② 给出推荐顺序(先脱壳/修 IAT,或直接动态抓 API);③ **请用户确认**是「仍强制看当前花表」还是「按推荐顺序」 |
| 用户明确**强制**当前步骤(如未脱壳也要看 IAT) | 执行并记 Evidence,MUST 标注 `quality=unreadable` / `packed`(或等价);**禁止**据此下「无网络能力」等结论 |
| 用户接受推荐顺序 | 先做前提步骤;完成后自动或再应要求做 X;**禁止**用前提步骤(如脱壳)**冒充**「已完成导入表检查」 |
**与「重做 X」的关系**:重做 X 仍 = 重做被点名步骤(或其经确认的合法前提协商结果),禁止偷换成无关步骤。脱壳是导入表的**前提**,不是导入表的**替代品**。
典型冲突:用户在加壳样本上说「先不要脱壳,先看导入表」→ 壳常篡改导入目录/加密描述符,静态表花且无意义 → 走本表「阻塞前提」行,不得默默脱壳冒充,也不得默默交出花表当完成。
## 1. Triage(5–15 分钟 · 强制起点) ## 1. Triage(5–15 分钟 · 强制起点)
```text ```text
@@ -21,11 +36,11 @@
□ 架构:x86 / x64 / ARM;编译语言线索(VC++ / Delphi / .NET / Go / Rust) □ 架构:x86 / x64 / ARM;编译语言线索(VC++ / Delphi / .NET / Go / Rust)
□ 加壳类型线索:UPX / ASPack / VMProtect / Themida / 未知混淆 □ 加壳类型线索:UPX / ASPack / VMProtect / Themida / 未知混淆
□ strings / rabin2 -z 捡漏 □ strings / rabin2 -z 捡漏
□ MUST 导入/导出锚点(见下方「导入表硬门与等价路径」) □ MUST 导入/导出锚点(见下方「导入表硬门与等价路径」);若用户抢跑且有壳 → 先走 §0.5
□ 产出:E-triage(MUST 含 imports 或等价锚点分类摘要)+ 假设清单(勿过早下结论) □ 产出:E-triage(MUST 含 imports 或等价锚点分类摘要,含 quality 标注如适用)+ 假设清单
``` ```
**阶段门闩(Triage → Static/Dynamic)**:E-triage 中未记录 imports **或** 合法等价锚点摘要前,MUST NOT 进入 Dynamic(除非已记录 IAT 修复失败并选择动态旁路,见 §1.2),也 MUST NOT 声称「基础分诊完成」。解析失败时仍 MUST 把失败输出写入 Evidence,不得跳过。用户要求「重做导入表检查」时 MUST 重做 imports/等价步骤本身,禁止改换其他分析步骤。 **阶段门闩(Triage → Static/Dynamic)**:E-triage 中未记录 imports **或** 合法等价锚点摘要前,MUST NOT 进入 Dynamic(除非已记录 IAT 修复失败并选择动态旁路,见 §1.2),也 MUST NOT 声称「基础分诊完成」。解析失败时仍 MUST 把失败输出写入 Evidence,不得跳过。用户要求「重做导入表检查」时 MUST 重做 imports/等价步骤本身(或先完成 §0.5 协商后的前提),禁止改换其他分析步骤冒充。
### 1.1 导入表硬门与等价路径 ### 1.1 导入表硬门与等价路径
@@ -34,10 +49,17 @@
| 原生 PE/ELF/Mach-O(IAT 可读) | `E-imports` / `E-triage-imports`:导入分类摘要 | `rabin2 -i` / IDA imports / 等价 | | 原生 PE/ELF/Mach-O(IAT 可读) | `E-imports` / `E-triage-imports`:导入分类摘要 | `rabin2 -i` / IDA imports / 等价 |
| DLL / SYS / 共享库 | **并列** `E-imports` + `E-exports`(`rabin2 -i` + `rabin2 -E`) | 导出表优先级等同导入表(对外入口) | | DLL / SYS / 共享库 | **并列** `E-imports` + `E-exports`(`rabin2 -i` + `rabin2 -E`) | 导出表优先级等同导入表(对外入口) |
| .NET 托管(无传统 IAT) | **等价路径**:dnSpy/IL/元数据/程序集引用与敏感 API 摘要 → 仍写入 `E-imports` 或 `E-triage-imports` 语义槽 | **禁止** 因「没有 IAT」而空过硬门;dnSpy 查看 = 原生「查导入表」 | | .NET 托管(无传统 IAT) | **等价路径**:dnSpy/IL/元数据/程序集引用与敏感 API 摘要 → 仍写入 `E-imports` 或 `E-triage-imports` 语义槽 | **禁止** 因「没有 IAT」而空过硬门;dnSpy 查看 = 原生「查导入表」 |
| 导入表解析失败 / 为空 | 仍记失败输出为 Evidence | 不得静默跳过 | | 导入表解析失败 / 为空 / 加壳花表 | 仍记失败或花表输出为 Evidence,并标 `quality` | 不得静默跳过;花表不得支撑能力否定结论 |
**干净导入表警告(MUST 提醒)**:若导入表「过干净」(仅 kernel32/ntdll 等基础 DLL、几乎无业务 API),高度怀疑 `LoadLibrary` + `GetProcAddress` 动态加载 → 在 Evidence 注明嫌疑,并 **SHOULD** 转入 Dynamic 抓取内存 API;不得仅凭静态 IAT 宣称「无网络/无文件能力」。 **干净导入表警告(MUST 提醒)**:若导入表「过干净」(仅 kernel32/ntdll 等基础 DLL、几乎无业务 API),高度怀疑 `LoadLibrary` + `GetProcAddress` 动态加载 → 在 Evidence 注明嫌疑,并 **SHOULD** 转入 Dynamic 抓取内存 API;不得仅凭静态 IAT 宣称「无网络/无文件能力」。
**高危 API 组合(补丁 8 · SHOULD)**:导入表过长时,优先输出**恶意组合聚类**,过滤纯系统基础调用。示例(非穷尽):
- 高危簇:`FindWindowA/W` + `WriteProcessMemory` + `CreateRemoteThread`(注入)
- 高危簇:`CryptEncrypt` / `CryptAcquireContext` + 大量 `FindFirstFile` / `DeleteFile`(勒索倾向)
- 高危簇:`InternetOpen` / `WinHttp` / `URLDownloadToFile` + 持久化 API(`RegSetValue` / `CreateService`)
- 单独 `CreateFile` / `ReadFile` 等多为良性噪声,除非与上簇共现
### 1.2 脱壳与 IAT 处理(高风险分岔 · Issue #65) ### 1.2 脱壳与 IAT 处理(高风险分岔 · Issue #65)
```text ```text
@@ -52,8 +74,11 @@
情况 B2:ImportREC/Scylla 报错、修复后无法运行、或 IAT 全乱码(VMP/加密壳) 情况 B2:ImportREC/Scylla 报错、修复后无法运行、或 IAT 全乱码(VMP/加密壳)
→ 【IAT 修复铁律】立即终止继续静态 IAT 修复 → 【IAT 修复铁律】立即终止继续静态 IAT 修复
→ MUST 记录 E-iat-repair-fail(命令、工具、失败现象、决定转动态) → MUST 记录 E-iat-repair-fail(命令、工具、失败现象、决定转动态)
→ ⏩ 直接进入 §3 Dynamic:API 断点 / 硬件执行断点 / 内存搜索抓取导入 → 直接进入 §3 Dynamic:API 断点 / 硬件执行断点 / 内存搜索抓取导入
→ 这不算「跳过导入表」:导入表路径已尝试并记 Evidence → 这不算「跳过导入表」:导入表路径已尝试并记 Evidence
情况 B3(补丁 6):脱壳并修 IAT 后双击闪退 / 蓝屏(疑文件 CRC/大小自校验)
→ 放弃继续静态修文件;记 E-self-check-crash 或并入 E-iat-repair-fail
→ 转入 §3 Dynamic:对 CreateFile / GetFileSize / 哈希相关 API 下断,定位校验绕过点
``` ```
**IAT 修复铁律(MUST)**:优先尝试自动/半自动修复;一旦修复工具报错或修复后程序无法运行,**立即停止**在静态导入表上死磕,切换动态调试,用 API 断点(如 `bp CreateFile` / 关键网络 API)在运行时捕获导入函数。 **IAT 修复铁律(MUST)**:优先尝试自动/半自动修复;一旦修复工具报错或修复后程序无法运行,**立即停止**在静态导入表上死磕,切换动态调试,用 API 断点(如 `bp CreateFile` / 关键网络 API)在运行时捕获导入函数。
@@ -70,10 +95,11 @@
```text ```text
□ 确认 E-imports / E-triage 已含导入表或等价锚点 Evidence(缺失则先补,禁止后置) □ 确认 E-imports / E-triage 已含导入表或等价锚点 Evidence(缺失则先补,禁止后置)
□ 若 DLL/SYS:确认 E-exports 已记录 □ 若 DLL/SYS:确认 E-exports 已记录
□ 敏感 API 分组:网络/WinHTTP、文件/CreateFile、进程/远程线程、注册表/服务 □ 敏感 API 分组 + 高危组合聚类(补丁 8)
□ 硬编码域名/IP/URL 字符串;资源节是否藏 Payload □ 硬编码域名/IP/URL 字符串;资源节是否藏 Payload
□ 定位关键函数(加密/校验/网络/授权)→ 地址/符号写入 Evidence □ 定位关键函数(加密/校验/网络/授权)→ 地址/符号写入 Evidence
□ 一条路不通 → 换工具(IDA↔r2↔Ghidra) □ 一条路不通 → 换工具(IDA↔r2↔Ghidra)
□ 时间盒(补丁 9 · SHOULD 默认):静态深挖约 15 分钟仍无关键路径 → 强制转入 §3 Dynamic(用户/任务可覆盖时长)
``` ```
**无 MCP 时**:可用导出反编译文本再分析(对照 P4nda0s reverse-skills / IDA-NO-MCP 思路),仍写 Evidence 路径。 **无 MCP 时**:可用导出反编译文本再分析(对照 P4nda0s reverse-skills / IDA-NO-MCP 思路),仍写 Evidence 路径。
@@ -82,14 +108,24 @@
核心理念:**静态提供线索 → 动态验证 → 验证卡壳 → 回静态重审**(无固定唯一顺序)。 核心理念:**静态提供线索 → 动态验证 → 验证卡壳 → 回静态重审**(无固定唯一顺序)。
### 3.0 断点起手式(补丁 7 + 10 · MUST 顺序)
在用户态调试器(x64dbg 等)启动样本前,按「四级火箭」预置断点(可因架构/工具略名不同,顺序不变):
1. **TLS 回调**断点(调试器 EP 之前可能已跑)
2. **入口点 EP** 断点
3. **敏感 API** 断点(如 `CreateRemoteThread` / 网络 / 文件写)
4. **保底**:`ExitProcess` / 进程退出路径断点(补丁 10)— 一旦因反调试直接退出,**不急着重启**;立即 dump memory,将崩溃前镜像路径写入 Evidence,供字符串/数据恢复
```text ```text
□ Frida / x64dbg / gdb / emulator:验证静态假设 □ Frida / x64dbg / gdb / emulator:验证静态假设
□ 敏感 API 断点、单步跟踪栈/寄存器(白盒) □ 按 §3.0 预置断点后再跑;单步跟踪栈/寄存器(白盒)
□ 行为监控:沙箱 / Procmon / RegShot(黑盒) □ 行为监控:沙箱 / Procmon / RegShot(黑盒)
□ IAT 修复失败样本:硬件执行断点或内存搜索强行捕捉 API □ IAT 修复失败 / 自校验闪退样本:硬件执行断点或内存搜索强行捕捉 API;CreateFile/GetFileSize 查 CRC
□ 反调试/反 Frida → reverse-engineering/anti-analysis □ 反调试/反 Frida → reverse-engineering/anti-analysis
□ Android:root 检测 / SSL pinning 绕过脚本按需生成,**须在授权设备** □ Android:root 检测 / SSL pinning 绕过脚本按需生成,**须在授权设备**
□ 崩溃日志驱动下一轮 hook(自适应循环) □ 崩溃日志驱动下一轮 hook(自适应循环)
□ 时间盒(补丁 9 · SHOULD 默认):单步跟踪约 200 条指令仍无恶意行为线索 → 强制回静态搜字符串/换锚点(可覆盖)
``` ```
### 3.1 沙箱 / 动态无行为应急分支(MUST) ### 3.1 沙箱 / 动态无行为应急分支(MUST)
@@ -101,6 +137,14 @@
→ 将「无行为 + 疑似 anti-VM」写入 Evidence,禁止写成「样本无害」而不加条件 → 将「无行为 + 疑似 anti-VM」写入 Evidence,禁止写成「样本无害」而不加条件
``` ```
### 3.2 时间盒策略(补丁 9 · SHOULD)
| 阶段 | 默认阈值(可被用户/任务覆盖) | 动作 |
|------|------------------------------|------|
| Static 深挖无关键路径 | ~15 分钟 | 转入 Dynamic |
| Dynamic 单步无进展 | ~200 条指令 | 回 Static 字符串/交叉引用重锚 |
| 任一路径重复失败 | 记 Evidence 后换工具或旁路 | 禁止同一失败手法空转 |
## 4. Synthesis(IOC / 攻击链 / 报告) ## 4. Synthesis(IOC / 攻击链 / 报告)
```text ```text
@@ -116,10 +160,10 @@
| 实战阶段 | 本文件章节 | 硬门 / 铁律 | | 实战阶段 | 本文件章节 | 硬门 / 铁律 |
|----------|------------|-------------| |----------|------------|-------------|
| 1 初步快速研判 | §0–§1 Triage | Hash、架构、文件类型、查壳;imports/等价锚点 | | 1 初步快速研判 | §0–§1 Triage | Hash、架构、文件类型、查壳;imports/等价锚点;§0.5 指令门闩 |
| 2 脱壳与 IAT | §1.2 | IAT 修复铁律;失败 → E-iat-repair-fail → Dynamic | | 2 脱壳与 IAT | §1.2 | IAT 铁律;失败/自校验闪退 → Evidence → Dynamic |
| 3 基础静态锚点 | §2 Static | 仅 IAT 正常或等价锚点已记录后深挖 | | 3 基础静态锚点 | §2 Static | 高危 API 组合;时间盒 SHOULD |
| 4 深度交叉验证 | §3 Dynamic | 静↔动循环;无行为应急分支 | | 4 深度交叉验证 | §3 Dynamic | 断点四级火箭;无行为应急;时间盒 SHOULD |
| 5 提取 IoC 与攻击链 | §4 Synthesis | IOC + Kill Chain / Path | | 5 提取 IoC 与攻击链 | §4 Synthesis | IOC + Kill Chain / Path |
| 6 归档与规则化 | §4 + docs-generator / YARA | 结构化报告;规则可选 | | 6 归档与规则化 | §4 + docs-generator / YARA | 结构化报告;规则可选 |
@@ -128,3 +172,4 @@
- 本包用 **阶段门闩 + tool-index**,不默认启用 Hex-Rays「unsafe 全自动执行」类插件 - 本包用 **阶段门闩 + tool-index**,不默认启用 Hex-Rays「unsafe 全自动执行」类插件
- 动态插桩默认 **offline/lab** network_profile - 动态插桩默认 **offline/lab** network_profile
- IAT/导入表:**尝试 + 记录** 优先于「无限静态死磕」或「静默跳过」 - IAT/导入表:**尝试 + 记录** 优先于「无限静态死磕」或「静默跳过」
- 用户指令:**目标优先 + 前提协商**,禁止用无关步骤冒充被点名步骤
+2 -2
View File
@@ -178,7 +178,7 @@ Assert-Fields (Join-Path $skillsRoot 'ops/timeline-workitem.md') @('timeline.md'
Assert-Fields (Join-Path $skillsRoot 'ops/role-map.md') @('lead', 'cie', 'cpe', 'cre', 'Handoff') Assert-Fields (Join-Path $skillsRoot 'ops/role-map.md') @('lead', 'cie', 'cpe', 'cre', 'Handoff')
Assert-Fields (Join-Path $skillsRoot 'ops/skill-supply-chain.md') @('AST10', 'MCP', 'bootstrap', 'MUST') Assert-Fields (Join-Path $skillsRoot 'ops/skill-supply-chain.md') @('AST10', 'MCP', 'bootstrap', 'MUST')
Assert-Fields (Join-Path $skillsRoot 'references/community-security-skills.md') @('trailofbits', 'agentskills.io', 'MUST', '2026-07') Assert-Fields (Join-Path $skillsRoot 'references/community-security-skills.md') @('trailofbits', 'agentskills.io', 'MUST', '2026-07')
Assert-Fields (Join-Path $skillsRoot 'reverse-engineering/references\re-agent-workflow.md') @('Triage', 'Static', 'Dynamic', 'Synthesis', 'IAT 修复铁律', 'E-iat-repair-fail', 'E-exports', 'dnSpy') Assert-Fields (Join-Path $skillsRoot 'reverse-engineering/references\re-agent-workflow.md') @('Triage', 'Static', 'Dynamic', 'Synthesis', 'IAT 修复铁律', 'E-iat-repair-fail', 'E-exports', 'dnSpy', '可行性门闩', 'E-self-check-crash', 'ExitProcess', '时间盒')
Assert-Fields (Join-Path $skillsRoot 'pentest-tools/references\recon-pipeline.md') @('auth.status', 'network_profile', 'Evidence', 'nuclei') Assert-Fields (Join-Path $skillsRoot 'pentest-tools/references\recon-pipeline.md') @('auth.status', 'network_profile', 'Evidence', 'nuclei')
Assert-Fields (Join-Path $skillsRoot 'docs-generator/references\security-report-templates.md') @('Evidence Chain', 'Findings', 'Path') Assert-Fields (Join-Path $skillsRoot 'docs-generator/references\security-report-templates.md') @('Evidence Chain', 'Findings', 'Path')
Assert-Fields (Join-Path $skillsRoot 'field-journal/_template.md') @('Scope', 'Evidence', 'Finding') Assert-Fields (Join-Path $skillsRoot 'field-journal/_template.md') @('Scope', 'Evidence', 'Finding')
@@ -203,7 +203,7 @@ if ($vendorRulesText -match '(?m)JS/Web 签名逆向报告\s*\|[^\r\n]*malware')
Ok 'vendor rules keep JS signature reports flavor-neutral' Ok 'vendor rules keep JS signature reports flavor-neutral'
} }
Assert-Fields $vendorRulesPath @('skills/ops/evidence-finding-path.md', '来源证据', 'securelist.com/updated-mata', 'www.huorong.cn', 'thin overlay', 'vuln') Assert-Fields $vendorRulesPath @('skills/ops/evidence-finding-path.md', '来源证据', 'securelist.com/updated-mata', 'www.huorong.cn', 'thin overlay', 'vuln')
Assert-Fields (Join-Path $skillsRoot 'malware-analysis/SKILL.md') @('IAT 修复铁律', 'E-iat-repair-fail', 'E-exports') Assert-Fields (Join-Path $skillsRoot 'malware-analysis/SKILL.md') @('IAT 修复铁律', 'E-iat-repair-fail', 'E-exports', 'E-self-check-crash', 'ExitProcess', '时间盒', '可行性')
Assert-Fields (Join-Path $skillsRoot 'docs-generator/references\security-report-templates.md') @('thin `vuln`', '1c. 漏洞技术分析') Assert-Fields (Join-Path $skillsRoot 'docs-generator/references\security-report-templates.md') @('thin `vuln`', '1c. 漏洞技术分析')
if ($vendorRulesText -match '(?m)vuln.*默认全文' -or $vendorRulesText -match '第 3 个默认全文 flavor') { if ($vendorRulesText -match '(?m)vuln.*默认全文' -or $vendorRulesText -match '第 3 个默认全文 flavor') {
# presence of explicit "not third default" language is OK; flag only if it claims vuln IS a third default full flavor # presence of explicit "not third default" language is OK; flag only if it claims vuln IS a third default full flavor