Android 逆向 Multi-Agent 系统设计
作者: 人生导师
日期: 2026 年 6 月 1 日
状态: 设计阶段,画饼中
这篇不是教程,是给自己画的饼。把之前几个月学 Agent、踩坑、想明白的东西落成一个可执行的系统设计。目标很明确:搞一个多 Agent 协作系统,专门干 Android 逆向的活。
核心理念
不搞主从调度那套。五个角色信息平权,像一个小组群聊:
- 各自有独立上下文,不共享对话历史
- 通过消息总线交换结论性信息,不是中间推理过程
- 任何人可以 @任何人,不需要经过"领导"中转
- 我(人)是 leader,但不是瓶颈——大部分时候系统自己跑
架构总览
┌─────────────────────────────────────────────────────┐
│ 消息总线(群聊) │
│ SQLite/Redis + HTTP API + @机制 │
└──────┬────────┬────────┬────────┬────────┬──────────┘
│ │ │ │ │
┌────▼────┐┌───▼────┐┌──▼────┐┌──▼────┐┌──▼──┐
│ 主模型 ││IDA+Jadx ││Trace ││Unidbg ││ 我 │
│ 调度+搜索││静态分析 ││算法分析││补环境 ││Leader│
└──────────┘└─────────┘└────────┘└── ─────┘└──────┘
│ │ │ │
┌───▼────┐┌──▼────┐┌─▼───┐┌──▼───┐
│搜索工具 ││IDA MCP ││trace ││unidbg │
│网络判断 ││Jadx CLI││数据 ││Java │
└───── ───┘└────────┘└──────┘└───────┘
五个角色定义
| 角色 |
职责 |
工具 |
模型选择 |
| 主模型 |
任务分发、网络搜索、信息判断、进度总结 |
搜索引擎、文档读取 |
Claude/GPT(需要强推理) |
| IDA+Jadx |
静态分析、函数识别、交叉引用、Java 层分析 |
IDA MCP、Jadx CLI |
Claude(代码理解强) |
| Trace |
执行流分析、算法还原、handler 映射 |
trace 文件读取、模式匹配工具 |
Claude(长上下文+精确推理) |
| Unidbg |
补环境、模拟执行、验证算法 |
unidbg Java API、编译执行 |
DS/Claude(代码生成) |
| 我 |
终审、路径决策、质量把关 |
脑子 |
碳基模型 |
通信机制:群聊模型
为什么不用 A2A
Google 的 A2A 协议太早期了,生态几乎没有。用它等于自己实现大部分东西,协议本身反而成了额外负担。
实际方案:消息总线
本质就是一个"群":
# 消息结构
{
"id": "msg_001",
"from": "trace_agent", # 发送者
"to": "unidbg_agent", # @谁,null=广播
"type": "conclusion", # conclusion/request/question/status
"content": "sub_12A0 的算法是 HMAC-SHA256,salt 拼接规则如下...",
"evidence": ["trace_line_47", "trace_line_128"], # 支撑证据引用
"confidence": "high", # high/medium/low
"timestamp": "2026-06-01T14:30:00Z"
}
@机制
@trace_agent:直接发给 trace agent,它下次被唤醒时看到
@all:广播,所有 agent 下次唤醒时都能看到
@human:上报给我,我来决策
每个 agent 的消息处理流程
1. 被唤醒(定时轮询 or 被@触发)
2. 拉取自己的未读消息
3. 结合自己的上下文处理
4. 输出结论/请求/问题
5. 发到消息总线
6. 回到等待状态
信息流设计:不仅传递结论,也传递可复用知识
最开始设计消息总线时,倾向于只传递结论,避免 Agent 之间互相污染上下文,也避免大量思维链导致上下文爆炸。
但在实际逆向场景中发现:
逆向工程中的很多高价值信息,在形成最终结论之前就已经具备协作价值。
例如:
- IDA agent 发现某函数存在 64 轮循环
- Trace agent 发现某段执行流存在 64 次状态更新
- Unidbg agent 发现某个常量在运行时被频繁访问
这些信息单独看不足以形成结论,但多个 Agent 的观察组合后,可能快速收敛到正确方向。
因此消息总线不应只传递最终结论,而应该支持不同层级的信息流转。
信息层级模型
系统内部将信息分为四层:
Observation(观察)
↓
Fact(事实)
↓
Hypothesis(假设)
↓
Conclusion(已验证结论)
Observation(观察)
Agent 发现的现象。
特点:
示例:
{
"type": "observation",
"agent": "trace_agent",
"content": "sub_5200 存在 64 次重复状态更新"
}
{
"type": "observation",
"agent": "ida_agent",
"content": "sub_5200 存在 64 轮循环结构"
}
Fact(事实)
已经通过工具、代码或证据确认的信息。
特点:
示例:
{
"type": "fact",
"content": "sub_12A0 调用了 sub_5200",
"evidence": [
"xref_001"
]
}
{
"type": "fact",
"content": "trace 第 487 行出现常量 0x6A09E667",
"evidence": [
"trace_487"
]
}
Hypothesis(假设)
基于观察和事实形成的推测。
特点:
示例:
{
"type": "hypothesis",
"content": "sub_5200 可能实现了 SHA256",
"evidence": [
"fact_021",
"fact_037"
],
"confidence": "medium"
}
Conclusion(结论)
已经通过校验机制确认的信息。
特点:
- 已通过验证
- 可进入知识库
- 可作为后续分析的可信前提
示例:
{
"type": "conclusion",
"content": "sub_5200 确认为 SHA256 实现",
"verified": true,
"verification_source": [
"trace_agent",
"unidbg_agent"
]
}
为什么这样设计
传统 Agent 系统更关注任务流:
任务
↓
执行
↓
结果
而逆向工程更接近知识流:
观察
↓
事实
↓
假设
↓
验证
↓
结论
系统的目标不是尽快产出答案,而是持续积累可信知识。
因此:
- Observation 用于发现线索
- Fact 用于沉淀证据
- Hypothesis 用于驱动探索
- Conclusion 用于构建最终知识库
Agent 之间共享的核心不是推理过程,而是这些经过结构化组织的信息。
这样既能避免上下文爆炸,也能最大限度保留逆向过程中最有价值的证据和知识。
三层校验机制
这是系统可靠性的核心。模型会编,但我们有办法拦住。
工作agent输出结论
↓
┌────────────────────────────────────┐
│ 第一层:自校验 │
│ - 硬校验:代码验证具体值/常量/行号│
│ - 软校验:模型自查推理链完整性 │
│ - 过了 → 第二层 │
│ - 没过 → 打回重做(最多3次) │
└───────────────┬────────────────────┘
↓
┌────────────────────────────────────┐
│ 第二层:校验agent(无状态冷启动) │
│ - 每次清空上下文,零先入为主 │
│ - 输入:结论 + 证据 + 原始数据 │
│ - 独立判断有没有矛盾 │
│ - PASS → 结论入库 │
│ - FAIL → 打回重做 │
│ - UNCERTAIN → 上报第三层 │
└───────────────┬────────────────────┘
↓
┌─────────────────────────────────┐
│ 第三层:我 │
│ - 只看 UNCERTAIN 和反复 FAIL 的│
│ - 做路径决策和最终判断 │
└─────────────────────────────────┘
校验 agent 的设计要点
- 无状态:每次任务完成后清空上下文,下次冷启动
- 不知道历史:不知道之前谁说了什么,避免 confirmation bias
- 只看证据:给它原始数据和结论,让它找矛盾
- 输出格式固定:PASS / FAIL / UNCERTAIN + 理由
校验 prompt 模板
你是一个独立的校验员。你不知道之前发生了什么。
以下是一个分析结论和支撑证据。
【结论】
{conclusion}
【原始证据】
{evidence}
请验证:
1. 结论中引用的具体数据(地址、值、行号)是否在证据中存在且一致
2. 结论的推理链是否有跳跃(A→B→C,每一步是否有依据)
3. 是否存在证据中的信息与结论矛盾
4. 结论是否遗漏了证据中的关键信息
输出格式:
- 判定:PASS / FAIL / UNCERTAIN
- 理由:(具体说明哪里有问题或为什么通过)
- 建议:(如果FAIL,建议从哪个方向重新分析)
硬校验示例(代码实现)
def hard_verify(conclusion: dict, trace_data: list) -> bool:
"""验证结论中引用的具体值是否在trace中存在"""
for assertion in conclusion["assertions"]:
if assertion["type"] == "register_value":
line = trace_data[assertion["line_number"]]
if assertion["register"] not in line or \
line[assertion["register"]] != assertion["value"]:
return False
elif assertion["type"] == "constant":
# 在trace中搜索这个常量
found = any(assertion["value"] in line for line in trace_data)
if not found:
return False
return True
工作流示例:分析一个签名算法
用一个典型场景走一遍整个系统怎么协作:
目标:还原 libxxx.so 中的 sign 签名算法
1. 我 @主模型:"分析 libxxx.so 的签名生成逻辑"
2. 主模型:
- 搜索网上有没有现成分析文章
- 判断:没有直接可用的,需要自己分析
- @ida_agent:"定位签名入口函数,从 JNI_OnLoad 开始找"
- @all:"任务启动,目标是 sign 算法还原"
3. IDA+Jadx agent:
- 通过 IDA MCP 找到 JNI 注册表
- 定位到 native 函数 Java_com_xxx_Sign_generate
- 分析调用链,发现核心逻辑在 sub_12A0
- @trace_agent:"入口确认为 sub_12A0,请收集执行 trace"
- @all:"入口函数定位完成:sub_12A0,调用了 sub_3F00 和 sub_5200"
4. Trace agent:
- 读取 sub_12A0 的执行 trace
- 分析数据流和运算模式
- 识别出 HMAC-SHA256 特征(初始值匹配)
- 自校验:在 trace 中确认 SHA256 的 H0-H7 初始值存在 ✓
- 校验agent验证:PASS
- @unidbg_agent:"算法是 HMAC-SHA256,key 来自 sub_3F00 返回值,请补环境验证"
- @all:"算法识别完成:HMAC-SHA256,salt 拼接规则为 timestamp + device_id"
5. Unidbg agent:
- 搭建 unidbg 环境,加载 libxxx.so
- 补 JNI 环境(GetStringUTFChars 等)
- 调用 sub_12A0,输入已知参数
- 对比输出和抓包结果
- 匹配 → @all:"验证通过,算法还原正确"
- 不匹配 → @trace_agent:"验证不通过,输出差异如下..."
6. 主模型:
- 收到所有 agent 的结论
- 整合成最终报告
- @human:"分析完成,结果如下..."
持久化设计
逆向一个目标可能跨好几天,进度不能丢。
项目状态文件
每个逆向项目一个目录,核心状态文件:
project_xxx/
├── status.json # 整体进度和状态
├── conclusions/ # 已确认的结论(通过校验的)
│ ├── func_sub_12A0.json
│ └── func_sub_3F00.json
├── messages/ # 消息历史(消息总线的持久化)
├── traces/ # trace 数据
├── unidbg/ # unidbg 项目代码
└── failed_attempts/ # 失败的尝试(防止重蹈覆辙)
status.json 结构
{
"target": "libxxx.so",
"goal": "还原 sign 签名算法",
"started": "2026-06-01",
"phase": "algorithm_identification",
"progress": {
"entry_located": true,
"call_chain_mapped": true,
"algorithm_identified": false,
"implementation_done": false,
"verified": false
},
"confirmed_facts": [
"入口函数: sub_12A0 (Java_com_xxx_Sign_generate)",
"调用链: sub_12A0 → sub_3F00 (key生成) → sub_5200 (加密核心)"
],
"blocked_paths": [
"sub_7000-sub_8000 是 VMP 保护,静态分析无效"
],
"next_steps": [
"trace agent 分析 sub_5200 的执行流"
]
}
Agent 恢复机制
每个 agent 启动时:
- 读 status.json 了解全局进度
- 读自己相关的 conclusions/ 了解已确认信息
- 拉取未读消息
- 继续工作
不需要记住对话历史,状态全在文件里。
技术选型
语言:Python
理由:
- AI SDK 生态最好(anthropic、openai、litellm)
- FastAPI 做后端接口简单
- 逆向工具链大部分有 Python binding
- 启动快,几百行代码毫秒级
模型调用:litellm
统一接口切模型,想用 Claude 用 Claude,想用 DS 省钱用 DS:
import litellm
# trace agent 用 Claude(需要精确推理)
response = litellm.completion(
model="claude-sonnet-4-20250514",
messages=[...]
)
# unidbg agent 用 DS(代码生成,便宜)
response = litellm.completion(
model="deepseek/deepseek-chat",
messages=[...]
)
消息总线:SQLite + FastAPI
不需要 Redis 那么重,SQLite 够用:
# 消息表
CREATE TABLE messages (
id INTEGER PRIMARY KEY,
from_agent TEXT,
to_agent TEXT, -- NULL = 广播
type TEXT, -- conclusion/request/question/status
content TEXT,
evidence TEXT, -- JSON array
confidence TEXT,
created_at TIMESTAMP,
read_by TEXT -- JSON array,谁已读
);
工具集成:MCP
每个 agent 挂自己的 MCP server:
- IDA agent → ida-pro-mcp
- Unidbg agent → 自己写一个 unidbg MCP(或者直接 subprocess 调用)
- Trace agent → 文件读取 + 自定义分析工具
- 主模型 → 搜索工具
开发路线图
Phase 1:最小可行版本(先跑通通信)
我(CLI输入)+ 1个 trace agent + 消息总线
- 验证消息收发机制
- 验证 agent 能正确处理 @消息
- 验证自校验流程
预计:1-2 周
Phase 2:加入校验机制
在 Phase 1 基础上加入:
- 硬校验(代码验证)
- 校验 agent(无状态冷启动)
- 重试和上报机制
预计:1 周
Phase 3:扩展到完整系统
加入其他 agent:
- 主模型(调度+搜索)
- IDA+Jadx agent
- Unidbg agent
- 持久化机制
预计:2-3 周
Phase 4:实战打磨
拿真实目标跑:
- 先跑一个简单的(非VMP、标准算法)
- 再跑中等难度(魔改算法)
- 最后挑战 VMP 保护的
根据实战调整设计
预计:持续迭代
已知的坑和待解决问题
模型能力边界
- trace 分析在第四五层(跨 handler 状态传递、全局 VM 结构还原)模型会飘
- 提示词工程能扩大可用范围,但天花板还在
- 需要实测 DS 在各层的表现,决定哪些任务可以用便宜模型
上下文管理
- 单个 trace 可能几百万行,不可能全塞给模型
- 需要设计"渐进式喂数据"的策略:先给摘要,模型要细节再给
- 滑动窗口?摘要+按需展开?这个要实验
校验的校验
- 校验 agent 本身也可能犯错
- 硬校验能覆盖的范围有限(只能验证具体值,验不了逻辑)
- 需要设计"校验覆盖率"指标——一个结论有多少比例被硬校验覆盖了
成本控制
- Claude 贵,不能所有 agent 都用顶配
- 需要实测各模型在各任务上的性价比
- 可能的策略:简单任务用 DS,关键判断用 Claude
人的介入点设计
- 现在还没想清楚什么时候该打断我
- 太频繁 → 我成了瓶颈
- 太少 → 系统可能在错误方向上跑很远
- 暂定:UNCERTAIN + 连续 FAIL 3 次 → 上报
跟现有方案的对比
| 维度 |
Claude Code |
Hermes |
我的方案 |
| 模型自由度 |
只能用 Claude |
任意 |
任意,按任务选 |
| 多 agent 协作 |
团队模式(封闭) |
delegate_task |
群聊模型(平权) |
| 逆向工具集成 |
需要自己搞 |
MCP |
MCP |
| 校验机制 |
无 |
无 |
三层校验 |
| 持久化 |
git checkpoint |
memory+session |
项目状态文件 |
| 启动速度 |
快 |
3-5 秒 |
毫秒级 |
| 定制程度 |
低 |
中 |
完全自定义 |
这个饼能不能吃到
说实话,这个系统的核心难点不在代码量——可能总共就几千行 Python。难的是:
- prompt 设计:每个 agent 的系统提示词怎么写,直接决定它能不能干好活
- 任务拆分粒度:给模型的任务太大它搞不定,太小又没效率
- 校验规则设计:什么算"可验证的断言",这个需要逆向经验来定义
- 实战调优:设计再好,跑起来肯定一堆问题,需要反复迭代
但这些都是可以逐步解决的问题,不是原理性障碍。先把 Phase 1 跑通,后面一步步来。
最坏情况:系统跑不起来,但过程中积累的 prompt 模板、校验方法、工具集成经验,单独拿出来也有用。
最好情况:系统能自动完成 70% 的分析工作,我只需要在关键节点做决策。那逆向效率直接翻几倍。
也写了一些些吧,把开源的GitHub链接拿出来给各位看看
https://github.com/djskncxm/DuckAgent