首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
逆向工程
发新帖
12
12
[原创]Agentic IDA Pro - LLM 驱动的逆向分析专家
发表于: 2026-3-6 13:57
5587
[原创]Agentic IDA Pro - LLM 驱动的逆向分析专家
xxxxxxx_798269
2026-3-6 13:57
5587
> 项目地址:<a href="elink@8ceK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6E0j5h3N6A6j5$3I4X3i4K6u0V1j5h3W2Q4x3V1k6S2k6$3g2F1N6r3W2U0i4K6u0V1K9h3c8S2i4K6u0V1M7s2u0G2">github.com/magiclf-ai/agentic-ida-pro</a> > 版本:IDA Pro 9.3 > 核心理念:LLM 主导策略决策,工具执行具体动作,全流程可追溯、可验证、可审计 --- `Agentic IDA Pro` 核心思想是: - LLM 主导策略 - 工具执行动作 - 任务板跟踪状态 - 证据链驱动结论 - 前后快照做验收 --- ## 二、为什么是 Agent,而不是更多脚本 逆向分析的典型路径是: ``` 入口定位 -> 调用链展开 -> 函数语义分析 -> 数据结构恢复 -> 类型传播 -> 验证 ``` 这个路径的关键难点是:**它不是固定流程图,而是"观察-决策-执行-再观察"的循环过程**。 脚本擅长执行固定步骤,但不擅长在证据变化时动态改计划。而 LLM 正好擅长"弱结构决策"——也就是在不完全信息下做下一步规划。 所以我们把角色拆开: | 层级 | 负责方 | 职责 | |------|--------|------| | **决策层** | LLM | 观察证据、规划下一步、选择工具 | | **执行层** | Tool | 做确定性动作(搜索、反编译、创建结构体) | | **状态层** | Task Board / Knowledge | 沉淀结论、管理进度 | | **审计层** | Observability / Acceptance | 记录日志、验收结果 | 这就是 Agentic 化真正的价值:**不是"替代分析师",而是把分析师的方法论做成能复盘、能审计、能扩展的系统**。 --- ## 三、总体架构:主控 Agent + 子 Agent + IDA 服务 先看主路径: ``` 用户请求 ↓ ReverseExpertAgentCore(主策略循环) ↓ Tool Layer(search/xref/decompile/create_structure/...) ↓ IDAClient(HTTP 通信层) ↓ ida_service.daemon(IDA 进程内串行执行) ↓ IDB 变更 + 反编译结果 ``` 再看横向能力: | 组件 | 作用 | |------|------| | **任务与知识** | TaskBoard + WorkingKnowledge,管理进度与沉淀认知 | | **子任务并行** | spawn_subagent 异步派生,结果自动回流 | | **上下文压缩** | prune_context_messages + compress_context_8block | | **运行验收** | 备份、快照、结构体 diff、失败判定 | | **可观测性** | 会话、turn、tool、事件入库 SQLite,可视化回放 | 从工程角度看,这个架构有两个关键取舍: 1. Python 代码保持"薄控制层",避免把业务逻辑硬编码进 if/else 2. 把策略约束写进 prompt + tool docstring,让 Agent 行为可进化 --- ## 四、多 Agent 分工:不是"多模型炫技",而是角色隔离 很多多 Agent 系统失败,原因是"每个 Agent 都在做所有事"。我们反过来做:**每个 Agent 只做自己最擅长、最可验证的一段**。 ### 1)主 Agent:ReverseExpertAgentCore **职责:** - 维护主循环(观察 -> 规划 -> 调工具 -> 更新状态) - 管理任务板和知识库 - 决定是否派生子 Agent - 最终调用 `submit_output` 完成收敛 **约束:** - 关键任务未关闭,禁止 `submit_output` - 有运行中 subagent,禁止 `submit_output` - 每轮结论必须引用工具证据 ### 2)DocumentAgent 检索本地 artifacts 中的可复用模板与历史片段,为主 Agent 提供"路径 + 片段 + 使用建议"。 ### 3)Evidence Reviewer 审核证据链是否闭环,识别"字段命名看起来对了但证据不足"的风险点,给出最小补证动作。 ### 4)Reverse Planner 给主 Agent 输出"下一轮唯一关键动作",把动作描述成可执行、可验证、可回退的形式。 ### 5)Context Pruner 对历史消息做高密度压缩,保留可执行记忆,删除噪音上下文。 ### 6)IDAPython Coder / Executor - Coder 负责写出最小修改脚本 - Executor 负责"执行-报错-修复-再执行"的闭环 这两者共同构成了我们最有特色的一段:**CodeAct 式执行环**。 --- ## 五、实战演示:一次完整的结构体恢复流程 下面是一个真实的结构体恢复任务执行日志。我们将逐轮剖析 Agent 的决策过程、工具调用和验证闭环。 ### 任务目标 > 分析关键函数并恢复结构体定义,给出证据链 这是一个典型的逆向分析需求:不仅要找出程序的核心逻辑,还要把散落在代码中的数据结构还原出来,并且每个结论都要有迹可循。 --- ### 第一轮:任务规划与入口定位 Agent 首先创建任务列表,把大目标拆成可追踪的子任务: ``` [Tool Calls] - create_task: { "tasks": [ {"title": "定位关键函数入口/热点函数", "priority": "high"}, {"title": "采集关键函数伪代码与符号使用证据", "priority": "high"}, {"title": "创建/迭代结构体定义并应用类型验证", "priority": "high"}, {"title": "形成证据链报告", "priority": "normal"} ] } ``` **为什么要先创建任务板?** 在长时间的分析过程中,LLM 容易"迷失方向"——忘记自己已经做了什么、还需要做什么。任务板把这些状态外化,每完成一个子任务就标记为 done,形成清晰的可审计路径。 任务创建成功后,Agent 开始执行第一个任务:定位入口函数。 ``` [Tool Calls] - search: { "pattern": "(?i)\\b(main|wmain|winmain|dllmain|start|entry)\\b", "target_type": "symbol" } ``` **Tool 返回:** ``` # Search Results - total_count: 2 ## Items 1. [symbol/function] main @ 0x1140 2. [symbol/function] start @ 0x14c0 ``` 找到了两个关键符号:`main` 和 `start`。接下来需要确认它们的调用关系。 ``` [Tool Calls] - xref: {"target": "main", "target_type": "symbol", "direction": "to"} ``` **Tool 返回:** ``` # Xref Results - total_count: 5 ## Items 1. ea=0x3fd8 -> target=0x4060 [__libc_start_main] 2. start+0x1f -> target=0x4060 [__libc_start_main] 3. start+0x18 -> target=0x1140 [main] ← 关键证据 4. start+0x1f -> target=0x3fd8 [__libc_start_main_ptr] 5. ea=0x420 -> target=0x56e [aLibcStartMain] ``` **证据解读:** `xref` 的结果清晰地展示了调用链:`start` 函数在偏移 `+0x18` 处调用了 `main`(地址 `0x1140`)。这是标准的 C 程序启动流程:`start` 作为真正的程序入口,通过 `__libc_start_main` 最终调用用户定义的 `main`。 Agent 立即更新任务状态,记录这一关键证据: ``` [Tool Calls] - set_task_status: { "task_ref": "t001", "status": "in_progress", "note": "已定位入口符号: main@0x1140, start@0x14C0;xref 证据: start+0x18 -> main" } ``` --- ### 第二轮:关键函数反编译与证据采集 入口定位完成,接下来深入分析 `main` 函数。 ``` [Tool Calls] - decompile_function: {"function_name": "main"} ``` **Tool 返回的伪代码(节选):** ```c __int64 __fastcall main(int a1, char **a2, char **a3) { __int64 ptr; // [rsp+8h] [rbp-50h] ptr = (__int64)calloc(1u, 0x28u); // 分配 0x28 字节 if ( ptr ) { *(_DWORD *)(ptr + 8) = 256; // offset +8 写入 256 *(_QWORD *)ptr = 0x5244485F544E4F43LL; // offset +0 写入 magic *(_QWORD *)(ptr + 32) = sub_15B0; // offset +32 写入函数指针 // ... v6 = calloc(1u, 0x38u); // 分配 0x38 字节 // ... v10 = calloc(v7, 0x38u); // 分配数组,元素大小 0x38 } } ``` **关键发现:** 1. `ptr = calloc(1, 0x28)` —— 分配 40 字节,很可能是某个结构体 2. `*(ptr + 8) = 256` —— offset 8 可能是版本号字段 3. `*ptr = 0x5244485F544E4F43` —— offset 0 写入一个 8 字节常量,可能是 magic 4. `*(ptr + 32) = sub_15B0` —— offset 32 写入函数指针 5. 后续还有 `calloc(1, 0x38)` 和 `calloc(v7, 0x38)` —— 说明还有另外两种大小为 56 字节的结构体 但仅凭 `main` 的代码还不够,Agent 决定同时反编译 `main` 中调用的子函数,获取更完整的字段使用证据: ``` [Tool Calls] - decompile_function: {"function_name": "sub_1780"} - decompile_function: {"function_name": "sub_15B0"} - decompile_function: {"function_name": "sub_15F0"} - decompile_function: {"function_name": "sub_16C0"} ``` **sub_1780 的反编译结果(应用类型前):** ```c __int64 __fastcall sub_1780(__int64 a1, int a2) { __int64 v2; if ( !a1 ) return v13 - __readfsqword(0x28u); v2 = *(_QWORD *)(a1 + 16); // offset +16 作为链表头 if ( !v2 ) goto LABEL_13; while ( *(_DWORD *)v2 != a2 ) // 比较 offset 0 { v2 = *(_QWORD *)(v2 + 32); // offset +32 作为 next 指针 if ( !v2 ) goto LABEL_13; } v4 = (*(__int64 (**)(void))(a1 + 32))(v2, 16, 0); // ... 更多字段访问 ... } ``` **证据解读:** - `a1 + 16` 被解引用作为链表头,说明 offset 16 是 `head` 指针 - `v2 + 32` 是 next 指针,说明 node 结构体的 offset 32 是 `next` - `a1 + 32` 被当作函数指针调用,验证了 `main` 中 `*(ptr + 32) = sub_15B0` 的推测 **sub_15F0 的反编译结果(应用类型前):** ```c unsigned __int64 __fastcall sub_15F0(__int64 a1) { __int64 v1; v1 = *(_QWORD *)(a1 + 16); // offset +16 作为某个指针 if ( v1 ) { v4 = *(unsigned int *)(a1 + 24); // offset +24 是计数 if ( (_DWORD)v4 ) { v5 = *(_QWORD *)(a1 + 8) & 0xFFFLL; // offset +8 被读取 v6 = v1 + 56 * v4; do { *(_DWORD *)(v1 + 52) |= 1u; // offset +52 被置位 *(_QWORD *)(v1 + 40) += v5; // offset +40 被累加 v1 += 56; // 步长 56,说明是数组 } while ( v1 != v6 ); } } } ``` **证据解读:** - `a1 + 16` 指向的内存以 56 字节为步长遍历,且每个元素有 offset 52 和 40 的访问 - 这与 `main` 中 `calloc(v7, 0x38)`(0x38 = 56)对应,说明 `v1` 指向的是 `field_desc` 数组 Agent 更新任务状态,记录已采集的证据: ``` [Tool Calls] - set_task_status: { "task_ref": "t002", "status": "in_progress", "note": "已反编译 main@0x1140 获得容器与节点构建逻辑;已提取符号使用:calloc(0x28) 容器、calloc(0x38) 节点、calloc(v7,0x38) 字段数组" } ``` --- ### 第三轮:结构体建模与创建 基于前面收集的证据,Agent 开始构建结构体定义。 **container 结构体推导:** | 偏移 | 大小 | 证据来源 | 语义推断 | |------|------|----------|----------| | +0x00 | 8 | `*ptr = 0x5244485F544E4F43` | magic 字段 | | +0x08 | 4 | `*(ptr + 8) = 256` | version | | +0x0C | 4 | `++*(ptr + 12)` | node_count | | +0x10 | 8 | `*(ptr + 16)` 作为链表头 | head 指针 | | +0x18 | 8 | `*(ptr + 24)` 指向尾节点 | tail 指针 | | +0x20 | 8 | `*(ptr + 32) = sub_15B0` | hash 函数指针 | 总大小:0x28(40 字节),与 `calloc(1, 0x28)` 吻合。 **node 结构体推导:** | 偏移 | 大小 | 证据来源 | 语义推断 | |------|------|----------|----------| | +0x00 | 4 | `*v6 = v33` | id | | +0x04 | 4 | `v6[1] = v4` | flags | | +0x08 | 8 | `*(v8 + 8) = time(0)` | ts(时间戳)| | +0x10 | 8 | `*(v8 + 16) = v11` | fields 指针 | | +0x18 | 4 | `v8[6] = v7` | field_count | | +0x1C | 4 | 未观察到访问 | unk1C(占位)| | +0x20 | 8 | 遍历 `v2 + 32` | next 指针 | | +0x28 | 8 | 双向链表逻辑 | prev 指针 | | +0x30 | 8 | `*(v8 + 48) = v20` | process 函数指针 | 总大小:0x38(56 字节),与 `calloc(1, 0x38)` 吻合。 **field_desc 结构体推导:** | 偏移 | 大小 | 证据来源 | 语义推断 | |------|------|----------|----------| | +0x00 | 32 | `snprintf(..., 32, ...)` 写入 name | name[32] | | +0x20 | 4 | `*(v14 - 6) = v12 & 3` | kind | | +0x24 | 4 | 未观察到访问 | unk24 | | +0x28 | 8 | `*(v14 - 2) = 8 * v12` | value | | +0x30 | 4 | `*(v14 - 1) = 4 << (v12 % 3)` | size | | +0x34 | 4 | `sub_15F0` 中置位操作 | flags | Agent 使用 `create_structure` 创建这三个结构体: ``` [Tool Calls] - create_structure: {"name": "field_desc", "c_decl": "struct field_desc { char name[32]; unsigned int kind; unsigned int unk24; unsigned __int64 value; unsigned int size; unsigned int flags; };"} - create_structure: {"name": "node", "c_decl": "struct node { unsigned int id; unsigned int flags; unsigned __int64 ts; struct field_desc *fields; unsigned int field_count; struct node *next; struct node *prev; void (*process)(struct node*); };"} - create_structure: {"name": "container", "c_decl": "struct container { unsigned __int64 magic; unsigned int version; unsigned int node_count; struct node *head; struct node *tail; __int64 (*hash)(void *buf, __int64 len, __int64 unused); };"} ``` **Tool 返回(确认结构体已落地):** ``` struct field_desc { ... }; // size=0x38 (56), mutation_effective=true struct node { ... }; // size=0x38 (56), mutation_effective=true struct container { ... }; // size=0x28 (40), mutation_effective=true ``` `mutation_effective=true` 表示结构体已成功写入 IDA 数据库。这是关键一步:**结构体不再是"纸面分析",而是真正落地到了 IDB 中**。 --- ### 第四轮:类型应用与验证闭环 结构体创建完成,但这只是开始。接下来必须验证:应用这些类型后,反编译代码是否真的变得更易读了? Agent 在 `main` 函数中应用类型: ``` [Tool Calls] - set_identifier_type: { "function_name": "main", "operations": [ {"kind": "local", "name": "ptr", "c_type": "struct container *"}, {"kind": "local", "name": "v8", "c_type": "struct node *"} ], "redecompile": true } ``` **Tool 返回(重反编译后的 main 函数):** ```c __int64 __fastcall main(int a1, char **a2, char **a3) { struct container *ptr; ptr = (struct container *)calloc(1u, 0x28u); if ( ptr ) { ptr->version = 256; ptr->magic = 0x5244485F544E4F43LL; ptr->hash = (__int64 (*)(void *, __int64, __int64))sub_15B0; // ... v8->fields = v11; v8->process = v20; if ( ptr->head ) { tail = ptr->tail; ptr->tail = v8; v8->prev = tail; tail->next = v8; } // ... head = ptr->head; for ( i = head; i; i = i->next ) { process = i->process; if ( process ) process(i); } } } ``` **验证效果:** - `ptr->version = 256` 替代了 `*(_DWORD *)(ptr + 8) = 256` - `ptr->magic` 替代了直接赋值常量 - `v8->fields`、`v8->process`、`v8->prev`、`v8->next` 全部变成了有意义的字段名 - 链表遍历 `i = i->next` 清晰可读 - 函数调用 `process(i)` 不再是一堆强制类型转换 同样的验证在子函数中进行: **重反编译后的 sub_1780:** ```c __int64 __fastcall sub_1780(struct container *a1, unsigned int a2) { struct node *head; head = a1->head; while ( head->id != a2 ) { head = head->next; if ( !head ) goto LABEL_13; } v4 = a1->hash(head, 16, 0); field_count = head->field_count; if ( (_DWORD)field_count ) { fields = head->fields; while ( 1 ) { field_count = fields->size + field_count; if ( fields->value > 0x10000 || (fields->flags & 4) != 0 ) break; if ( ++fields == v8 ) return; } } } ``` **重反编译后的 sub_15F0:** ```c unsigned __int64 __fastcall sub_15F0(struct node *a1) { struct field_desc *fields; fields = a1->fields; if ( fields ) { field_count = a1->field_count; if ( (_DWORD)field_count ) { v5 = a1->ts & 0xFFF; v6 = &fields[field_count]; do { fields->flags |= 1u; fields->value += v5; ++fields; } while ( fields != v6 ); } } } ``` **重反编译后的 sub_16C0:** ```c unsigned __int64 __fastcall sub_16C0(struct node *a1) { struct field_desc *fields; fields = a1->fields; if ( fields ) { field_count = a1->field_count; if ( (_DWORD)field_count ) { v5 = &fields[field_count]; do { fields->flags |= 2u; if ( fields->kind == 1 ) fields->size *= 2; ++fields; } while ( v5 != fields ); } } } ``` **闭环验证总结:** | 函数 | 应用前 | 应用后 | 改进 | |------|--------|--------|------| | main | `*(_DWORD *)(ptr + 8) = 256` | `ptr->version = 256` | 字段语义清晰 | | main | `v2 = *(_QWORD *)(a1 + 16)` | `head = a1->head` | 链表操作可读 | | sub_1780 | `*(_QWORD *)(a1 + 32))(v2, 16, 0)` | `a1->hash(head, 16, 0)` | 函数指针调用明确 | | sub_15F0 | `*(_DWORD *)(v1 + 52) |= 1` | `fields->flags |= 1` | 位操作语义清晰 | | sub_16C0 | `v1[8] == 1` | `fields->kind == 1` | 条件判断可读 | Agent 更新任务状态,标记结构体恢复任务完成: ``` [Tool Calls] - set_task_status: { "task_ref": "t003", "status": "done", "note": "结构体已创建并通过类型应用验证闭环:create_structure 确认大小;set_identifier_type 后伪代码字段访问全部替换为有名字段" } ``` --- ### 第五轮:知识沉淀与任务闭环 所有子任务完成后,Agent 将关键发现沉淀到知识区: ``` [Tool Calls] - knowledge_write: { "confirmed_facts": "main 使用 calloc(1,0x28) 分配容器对象...", "evidence": "search: main@0x1140; xref: start+0x18 -> main; decompile main...", "hypotheses": "container::hash 的第三参数目前固定为 0,可能是保留参数", "open_questions": "field_desc::unk24 未见读写证据,需在其它函数中找交叉引用", "do_not_repeat": "不在无偏移访问证据时猜测字段含义" } ``` 这种知识沉淀机制使得分析过程可持续:如果后续发现新的证据,可以回到知识区更新假设;如果另一个子 Agent 在别处发现了 `unk24` 的访问,可以补充到这里。 最终的任务板状态: ``` ## Task Status (Current) - summary: total=4, active=0, done=4, blocked=0 - [x] t001 (high) 定位关键函数入口/热点函数 [status=done] - [x] t002 (high) 采集关键函数伪代码与符号使用证据 [status=done] - [x] t003 (high) 创建/迭代结构体定义并应用类型验证 [status=done] - [x] t004 (normal) 形成证据链报告 [status=done] ``` 所有任务都已闭环,Agent 提交最终输出: ``` [Tool Calls] - submit_output: { "summary": "已完成关键函数分析并恢复 3 个核心结构体(container/node/field_desc)", "key_findings": "入口: main@0x1140; container 大小 0x28; node 大小 0x38; field_desc 大小 0x38", "artifacts": "IDA Structures: container/node/field_desc; 类型应用验证: main/sub_1780/sub_15F0/sub_16C0" } ``` --- ## 六、Tool Call 逻辑:为什么强调 docstring 而不是 JSON Schema 堆叠 项目里 tool 调用遵循几条硬规则: 1. **`bind_tools` + docstring 是参数语义基线** 2. **参数要显式且最小,避免盲调** 3. **Tool 返回 `ERROR:` 时先做最小修复再重试** 4. **有依赖关系的工具必须分轮调用** 5. **每轮结论必须引用工具证据文本** 从实现上看,我们采用了"动态绑定工具集": - 主循环动态注入运行时工具(任务板、知识库、上下文压缩、submit) - 子循环使用子 Agent 对应工具集 - 工具执行支持受控并发(有并发上限和错误收集) 这套设计的优势是:**策略灵活,但工具边界清晰**。 --- ## 七、IDAPython Agent 的 CodeAct 设计:核心差异化 很多系统把"执行 IDAPython"当成一个黑盒工具:脚本失败了就失败了。我们做的是"脚本失败也能自修复"的可循环执行器。 ### 1)入口:先执行,再决定是否进入修复环 `execute_idapython` 的路径大致是: - 先跑一次脚本 - 如果成功,直接返回 - 如果失败,进入 IDAPython repair 子循环 ### 2)修复环:观察错误 -> 最小修改 -> 提交执行 -> 再观察 系统会自动生成子任务板,例如: - 已执行初始脚本并收集错误 - 待最小修改并提交 - 若知识不足则检索 KB(`search/read_file`) - 成功后退出 这正是 CodeAct 思路在工程里的落地: - 行动是"可执行代码" - 观察是"运行输出和报错" - 下一步动作由上一轮执行结果驱动 ### 3)安全与边界:防破坏优先 我们明确阻断了破坏性结构操作,例如 `idc.del_struc`。理由很简单:一旦删错结构体,证据链和验收基线都会被污染。 ### 4)IDA 9.3 兼容策略 我们在提示词和执行器里都写了"高风险 API 规避策略": - 避免盲用兼容性差的接口 - 优先 `idc/idautils/ida_hexrays` 等稳定模块 - 每次修复只改报错相关行,拒绝大改 这套机制让"会写脚本"升级成"可控地修脚本并完成任务"。 --- ## 八、任务板与知识库:让 Agent 不是"边跑边忘" 我们把任务管理做成了第一等公民,而不是日志附属品。 **任务板支持:** - `create_task`(单条/批量) - `set_task_status`(todo/in_progress/blocked/done/cancelled) - `edit_task` - `get_task_board` **知识库支持:** - `confirmed_facts` —— 已验证的事实 - `hypotheses` —— 待验证的假设 - `open_questions` —— 尚未解答的问题 - `evidence` —— 证据来源 - `next_actions` —— 下一步建议 - `do_not_repeat` —— 避免重复踩坑 为什么这很关键?因为它把"模型短期上下文"转换成"可持续记忆"。尤其在长链路逆向任务里,没有这层结构化记忆,系统几乎一定会重复劳动。 --- ## 九、上下文压缩:长任务场景里必须有"记忆管理" 长周期分析常见问题是上下文污染:历史消息越多,模型越容易掉焦点。我们设计了两层机制: 1. **`prune_context_messages`**:按 Message ID 定点折叠 2. **`compress_context_8block`**:触发 8-block 蒸馏快照 蒸馏不是"摘要文学",而是保留可执行记忆: - 当前目标 - 关键证据 - 任务状态 - 禁止重复动作 - 下一步建议 这让系统可以在长会话中保持"方向稳定 + 成本可控"。 --- ## 十、可观测性与验收 ### 1)可观测性 所有会话进入 SQLite,包含: - `sessions` —— 会话级别元数据 - `turns` —— 轮次级别信息 - `messages` —— 完整消息链 - `turn_tools` —— 工具调用记录 - `session_events` —— 事件日志 并配有前端时间线,可回看"某一轮为什么调用了这个工具、失败点是什么、后续如何修复"。 ### 2)验收 `run_reverse_expert_agent.py` 在执行期自动完成: - IDB 备份 - before/after 结构体快照 - struct diff - acceptance summary(md/json) 而且定义了明确失败条件: - 无 tool call - 无有效 mutation - before/after 无差异 - 运行异常中断 这意味着:**系统不是"跑完就算成功",而是"满足质量门槛才算成功"**。 --- ## 十一、关键设计解析 ### 1. 为什么坚持"类型应用后必须重反编译验证" 很多自动化工具止步于"输出结构体定义",但 Agentic IDA Pro 强制要求验证闭环。这是因为: - **模型可能猜错**:LLM 根据偏移推断的字段语义,可能与实际不符。只有看到 `ptr->version = 256` 这样的代码,才能确认 offset 8 真的是版本号。 - **结构体定义可能不完整**:如果漏掉了某个字段,后续访问会出现错位。重反编译能立即暴露这种问题。 - **可读性是硬指标**:结构体恢复的目标是让代码更易读。如果应用类型后代码仍然满屏强制类型转换,说明恢复工作还没到位。 ### 2. 为什么用"任务板"管理状态 长链任务中,LLM 容易"遗忘"之前做过什么。任务板的价值在于: - **外化记忆**:不依赖 LLM 的上下文记忆,而是把状态写在持久化的任务板里 - **可审计**:每个任务的完成都有明确的证据引用 - **阻断提交**:如果还有未完成的任务,`submit_output` 会被拒绝,防止"半成品"输出 ### 3. 为什么需要"知识区" 与任务板不同,知识区沉淀的是**跨任务的长期认知**。这使得多个子 Agent 可以协作分析:一个 Agent 发现了线索,写入知识区;另一个 Agent 在别处找到了答案,回来补充。 --- ## 十二、与学术/行业思路的关系:借鉴与工程化 从研究脉络看,我们受到两类工作启发: 1. **ReAct**:交错的推理与行动 2. **CodeAct**:把可执行代码作为统一行动空间 但项目不是直接照搬论文,而是做了工程化改造: - 将"动作空间"映射为可控工具集(含逆向专用工具) - 用任务板和知识区约束长链路决策 - 用子 Agent 做角色隔离,降低上下文污染 - 用验收机制保证"可交付"的底线 简单说:**论文解决"能不能做",工程系统解决"能不能长期稳定地做"**。 --- ## 十三、风险控制与局限 ### 风险控制 | 风险 | 对策 | |------|------| | 模型幻觉 | 每步操作必须有工具证据,不能只凭"我觉得" | | 破坏性操作 | 显式阻断删除结构体等高危 API | | 失败不可追溯 | 所有操作写入 SQLite,支持轮级回放 | | 伪成功 | 必须有实际变更(结构体 diff)才算完成 | | 无限循环 | 最大迭代次数 + 子任务超时机制 | ### 当前局限 - 仅支持 IDA Pro 9.3 - 当前优化重点是结构体恢复,不代表覆盖所有逆向场景 - 字段命名质量取决于证据密度 ### 路线图 1. 增加结构体恢复质量的自动化评测 2. 扩展更多逆向技能(字符串解密、协议字段恢复、语义级的代码分析) 3. 更细粒度的变更审计(字段变更原因链) 4. RAG 增强逆向workflow, 和 IDAPython 脚本开发 --- ## 十四、如何快速上手 ### 1)环境要求 - IDA Pro 9.3 - Python 3.10+ - OpenAI API Key(或其他兼容 OpenAI 格式的端点) ### 2)配置模型环境 ```bash export OPENAI_API_KEY='your-api-key' export OPENAI_BASE_URL='http://your-llm-endpoint/v1' export OPENAI_MODEL='gpt-5.2' ``` ### 3)启动 IDA Service(Windows) ```bat .\src\scripts\run_windows_bridge.bat ``` ### 4)启动 Agent(WSL/Linux) ```bash PYTHONPATH=src python src/scripts/run_reverse_expert_agent.py \ --ida-url http://127.0.0.1:5000 \ --request "分析关键函数并恢复结构体定义,给出证据链" \ --max-iterations 40 ``` ### 5)运行前检查清单 - [ ] LLM 端点可达 - [ ] IDA 服务健康检查通过(`/health`、`/db/info`) - [ ] IDB 文件路径正确 - [ ] 日志目录可写 --- ## 十五、最后:我们更关心"可信工作流" 在逆向工程这类高复杂任务里,最危险的不是模型答错,而是模型"看起来答对了",但你没有验证手段。 `Agentic IDA Pro` 的方向很明确: - 把每一步变成可追溯动作 - 把每个结论绑定到证据 - 把每次运行纳入验收体系 这样做的结果,不是让分析师消失,而是让分析师从"手工重复劳动"转向"高价值判断与决策"。 如果你也在做 Agent 化逆向平台,欢迎一起讨论:如何把"模型能力"真正沉淀成"工程能力"。 抛砖引玉,在这个 AI 时代,希望找些同路人一起探索 !  --- ## 参考资料 1. ReAct: Synergistic Reasoning and Acting in Language Models <mark class="encrypted">e5cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6S2M7Y4S2A6N6W2)9J5k6h3!0J5k6#2)9J5c8X3q4T1M7#2)9J5c8U0t1J5x3e0m8Q4x3X3f1H3x3K6j5J5z5b7`.`.</mark> 2. Executable Code Actions Elicit Better LLM Agents (CodeAct, ICML 2024) <mark class="encrypted">ff2K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6S2M7Y4S2A6N6W2)9J5k6h3!0J5k6#2)9J5c8X3q4T1M7#2)9J5c8U0t1@1x3o6u0Q4x3X3f1H3x3e0l9K6x3l9`.`.</mark> 3. CodeAct 官方实现 <mark class="encrypted">ef7K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6^5K9h3&6Y4P5h3q4G2N6%4N6Q4x3V1k6U0L8$3c8W2i4K6u0V1j5h3y4@1</mark> 4. Hex-Rays IDA 9.3 Release Notes <mark class="encrypted">80cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1L8$3y4K6i4K6u0W2K9r3g2^5i4K6u0V1M7X3q4&6M7#2)9J5k6h3y4G2L8g2)9J5c8Y4u0W2L8r3g2S2M7$3g2Q4x3X3c8F1L8%4c8W2M7#2)9J5c8U0W2Q4y4h3j5K6</mark> 5. Hex-Rays IDAPython Developer Guide <mark class="encrypted">e81K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1L8$3y4K6i4K6u0W2K9r3g2^5i4K6u0V1M7X3q4&6M7#2)9J5k6h3y4G2L8g2)9J5c8X3c8W2N6X3g2D9L8%4m8W2M7W2)9J5k6r3N6#2K9h3c8W2i4K6u0r3K9h3c8S2M7s2W2@1K9r3!0F1</mark> 6. LangChain tool calling / bind_tools <mark class="encrypted">9b5K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1L8$3y4K6i4K6u0W2L8r3q4F1k6$3y4Z5j5h3W2F1i4K6u0W2j5$3!0E0i4K6u0r3L8%4y4K6i4K6u0r3M7s2W2@1K9r3!0F1i4K6u0r3L8r3q4F1k6$3y4Z5j5h3W2F1i4K6u0r3N6r3!0G2L8s2x3`.</mark> 7. OWASP Top 10 for LLM Applications <mark class="encrypted">838K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6G2N6$3q4K6M7q4)9J5k6h3!0J5k6#2)9J5c8Y4N6%4N6#2)9J5k6s2m8J5L8$3A6W2j5%4c8Q4x3X3c8@1L8%4m8Q4x3X3b7I4x3q4)9J5k6r3k6G2M7W2)9J5k6r3I4S2M7X3N6W2i4K6u0V1L8r3q4F1k6%4g2S2k6$3g2Q4x3X3c8E0L8$3c8W2L8q4)9J5k6r3q4H3M7r3I4A6j5$3q4@1K9h3!0F1M7#2)9J5c8R3`.`.</mark>
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
最后于
2026-3-6 16:34 被xxxxxxx_798269编辑 ,原因:
#调试逆向
#系统底层
#问题讨论
#其他内容
收藏
・
12
点赞
・
12
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
git_31587fengye102
非常支持你的观点!
2026-8-11 23:30
git_69042ahyun1101
非常支持你的观点!
2026-7-28 15:08
chenzhouch
感谢你分享这么好的资源!
2026-6-6 18:05
mb_mdcvvlsr
期待更多优质内容的分享,论坛有你更精彩!
2026-4-15 11:27
deallyxyz
非常支持你的观点!
2026-3-12 17:01
x_req
期待更多优质内容的分享,论坛有你更精彩!
2026-3-10 13:23
冰雪浣
感谢你的贡献,论坛因你而更加精彩!
2026-3-9 16:54
cr_lgdx
为你点赞!
2026-3-8 22:16
nuoen
你的帖子非常有用,感谢分享!
2026-3-8 15:59
暗香沉浮
+1
感谢你的积极参与,期待更多精彩内容!
2026-3-7 11:31
东方玻璃
这个讨论对我很有帮助,谢谢!
2026-3-6 22:27
马来
为你点赞!
2026-3-6 14:06
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
10
)
xxxxxxx_798269
雪 币:
1014
活跃值:
(192)
能力值:
( LV2,RANK:10 )
在线值:
发帖
3
回帖
17
粉丝
6
关注
私信
xxxxxxx_798269
2
楼
运行前检查清单 后面的内容好像被截断了
2026-3-6 16:35
0
zhangtheo
雪 币:
257
活跃值:
(1754)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
12
粉丝
0
关注
私信
zhangtheo
3
楼
很厉害啊,晚上回去试一下
2026-3-6 16:46
0
RRRRoma
雪 币:
4
活跃值:
(80)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
8
粉丝
0
关注
私信
RRRRoma
4
楼
能分享下配置文件吗
2026-3-6 21:57
0
xxxxxxx_798269
雪 币:
1014
活跃值:
(192)
能力值:
( LV2,RANK:10 )
在线值:
发帖
3
回帖
17
粉丝
6
关注
私信
xxxxxxx_798269
5
楼
RRRRoma
能分享下配置文件吗
请问下什么配置文件
2026-3-7 08:05
0
huangjw
雪 币:
6688
活跃值:
(11872)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
511
粉丝
2
关注
私信
huangjw
6
楼
你是真牛逼
2026-3-7 10:14
0
暗香沉浮
雪 币:
379
活跃值:
(2672)
能力值:
( LV8,RANK:140 )
在线值:
发帖
19
回帖
90
粉丝
26
关注
私信
暗香沉浮
2
7
楼
挺好
2026-3-7 11:31
0
fessxfeaf
雪 币:
33
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
4
粉丝
0
关注
私信
fessxfeaf
8
楼
厉害
2026-3-8 10:44
0
RRRRoma
雪 币:
4
活跃值:
(80)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
8
粉丝
0
关注
私信
RRRRoma
9
楼
xxxxxxx_798269
请问下什么配置文件
就是工作流啊或者skill啊
2026-3-11 21:11
0
海带
雪 币:
427
活跃值:
(2115)
能力值:
( LV2,RANK:10 )
在线值:
发帖
1
回帖
83
粉丝
11
关注
私信
海带
10
楼
吊!
2026-5-27 16:15
0
syc
雪 币:
197
活跃值:
(993)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
10
粉丝
0
关注
私信
syc
11
楼
学习了
2026-7-15 19:03
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
xxxxxxx_798269
3
发帖
17
回帖
10
RANK
关注
私信
他的文章
[原创]Agentic IDA Pro - LLM 驱动的逆向分析专家
5587
[原创] IVAgent - Multi-Agent 驱动的漏洞挖掘 Agent
6672
[讨
1226
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部