本节摘要:角色预设是人推一下、模型走一步;ReAct 自动模式让模型自己走:思考(当前该干什么)、行动(调用某个工具,通常是发一条 r2 命令)、观测(读命令输出),循环往复直到给出答案。本节先讲清这个循环为什么在逆向里成立——因为 r2 命令的输入输出都是文本,恰好是模型的世界;然后实操自动模式会话,让它在 demo_stripped 上自主完成「找校验函数、认出去混淆、给出密钥」的全过程,全程留痕。第三部分讲 r2ai 内置的本地 RAG 向量库:把第 2.2 节那种函数级 JSON 建成可检索库,模型先查再读,解决「全部函数塞不进上下文」。第四部分给本地 Ollama 与云端模型的取舍表。最后是刹车:预算上限与人工检查点。命令与输出为写法示意,以 r2ai 官方 README 为准。
ReAct 的意思是推理与行动交替:模型不一次性给答案,而是边做边想。
┌─────────────── 思考(Thought)───────────────┐ │ 「我需要先知道有哪些函数,才能找校验逻辑」 │ └───────────────────────┬──────────────────────┘ ▼ ┌─────────────── 行动(Action)───────────────┐ │ 调用工具:aflj(列函数,JSON) │ └───────────────────────┬──────────────────────┘ ▼ ┌─────────────── 观测(Observation)──────────┐ │ 读到 14 个函数的清单,其中 fcn.00401160 可疑 │ └───────────────────────┬──────────────────────┘ ▼ 回到思考:下一步发 pdf 还是 axt? (循环,直到模型给出最终答案)
这个循环在逆向里成立的根本原因与第 4.1 节同源:r2 的命令与输出都是文本。EnIGMA 的结论(第 0.1 节)说的正是这件事——给模型交互式工具,能力大幅提升;ReAct 是把「交互」程序化的标准形状。
自动挡的代价是失控风险:模型可能发十几次无意义的命令烧 token,也可能在幻觉里打转。所以本节结尾的刹车不是可选项。
(文字流程图)单轮问答(4.1 节):人问 ──▶ 模型答 ──▶ 人再问。ReAct(本节):人给目标 ──▶ 模型思考 ──▶ 发命令 ──▶ 读观测 ──▶ 循环 ──▶ 出答案 ──▶ 人重放证据链。
# bash —— r2ai 自动模式会话(写法示意,输出有删节,以官方 README 为准) r2 -A bin/demo_stripped [0x00401090]> r2ai -m ollama/qwen2.5-coder [0x00401090]> r2ai 找出这个程序的许可校验逻辑与正确密钥,给出证据链 (模型自动循环) 行动: aflj -> 观测: 14 个函数 行动: izz -> 观测: [FAIL] invalid license key 等字符串 行动: axt @ str._FAIL_... -> 观测: 引用落在 fcn.00401139 行动: pdf @ fcn.00401160 -> 观测: strcmp 与对 fcn.00401189 的调用 行动: pdf @ fcn.00401189 -> 观测: 逐字节异或 0x5a 的循环 行动: px 16 @ 0x00402008 -> 观测: 36 33 39 3f 34 29 3f ... 答案: fcn.00401160 为校验函数;期望密钥为字节序列逐个异或 0x5a 的结果 license;证据链如上五步。
会话后的人工动作只有一样:把证据链五步在 r2 里重放一遍(每条行动都是合法 r2 命令,这正是设计出来的可复核性)。哪一步的观测与模型转述不符,就在哪一步喊停。
自动会话还有一个观测细节要盯:观测截断。函数太大或字符串太多时,工具返回给模型的观测会被截断,模型可能基于半截观测下结论而不自知。两个对策:走查前对超长函数先手工分段(或用第 2.2 节的截断标记思路);要求模型在答案里注明「依据的观测是否完整」。截断是自动模式里最隐蔽的翻车点,比幻觉更难发现。
自动模式有个隐含瓶颈:上下文装不下全部函数。中型样本几百个函数、几万行伪代码,逐个 pdf 会把会话撑爆。r2ai 的解法是内置本地 RAG 向量库:把函数文本(伪代码或反汇编)向量化存本地,查询时检索最相关的若干函数拼进提示词。
第 2.2 节的 JSON ──▶ 入库(向量化,本地存储)──▶ 查询「许可校验」 │ ▼ 命中 check 类函数(top-k 个) │ ▼ 只有命中者进提示词,模型再细读
与源码侧的对照:《语义代码检索》第 3 章《代码切分》讨论 AST 级切块、第 6 章《repo-map 与 agentic 检索》讨论「把检索交给智能体」——r2ai 的函数级 RAG 是同一思想在二进制侧的落地:切分粒度换成函数边界(第 2.2 节讨论过原因),检索器交给模型按需调用。实操上入库与查询命令随版本演进较快,以官方 README 为准;会话形态示意:
# bash —— RAG 查询会话(写法示意,命令以 r2ai 官方 README 为准) [0x00401090]> r2ai -e rag=1 # 启用本地向量库(开关形态示意) [0x00401090]> r2ai 哪些函数像是在做许可或校验? 模型(检索后回答):命中 3 个函数—— fcn.00401160(strcmp 分支,相关度高) fcn.00401139(打印失败信息) fcn.00401189(字节变换循环) 建议从 fcn.00401160 开始 pdf 细读。
RAG 结果的质量三问,问完再信:命中的函数真是主题相关,还是只是文本形似(异或循环和 Base64 解码在向量空间里是近邻)?top-k 之外的函数是不是被截断丢了(入库时的 truncated 标记见第 2.2 节)?检索词换一种说法,结果稳不稳?三问过不了,就退回枚举模式让模型自己列函数。
工程要点稳定:入库原料就是第 2.2 节的 JSON,切分粒度与截断策略在那里已经定好。入库时机建议放进批处理链路——导出 JSON 的同一步顺手入库,样本与索引同批次落盘,避免「索引是旧的」这类时序问题。
| 维度 | 本地(Ollama 等) | 云端(OpenAI / Anthropic 等) |
|---|---|---|
| 隐私 | 样本不出本机 | 样本内容进提示词与日志 |
| 质量 | 受本地模型档位限制 | 通常更强 |
| 成本 | 电费与硬件折旧 | 按 token 计费 |
| 可用性 | 无网也能跑 | 依赖网络与额度 |
决策规则一句话:样本敏感(未知来源、客户交付、内部代码)一律本地;公开 CTF 与自编译样本按质量与预算自由选。 ReAct 循环里模型会多次调用、上下文反复增长,云端成本按循环次数放大——上自动挡之前先看下一节的预算。另外记住本地不等于慢:解释、命名这类任务本地中档模型完全够用(第 4.1 节的档位建议),真正需要云端强模型的场景比想象中少。
两道刹车,缺一不可:
(文字流程图)自动模式 ──▶ 预算内?──否──▶ 停止并汇报 └──是──▶ 行动与观测 ──▶ 声称有答案? │否:继续循环 │是:人工重放证据链 └──写操作?──是──▶ 人工确认再执行
打转的识别标准值得单独记:同一命令(或等价命令)连续出现三次以上、观测内容没有新增信息、模型开始「复述」而不是「推进」。命中任意一条就手动打断,把任务拆小再放它跑——打转烧的不只是 token,还有你对自动化的信任。
自动模式已经能跑了,但过程与结论仍散落在会话里。下一节用 r2mcp 把 r2 变成 MCP 服务器,搭一条「假设清单、逐条验证、结论回填」的流水线,让结果可复现、可落盘。