REA Hopper provider 深度解析:一次请求在串行反汇编桥上的完整生命周期
【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea
本文用一条请求的完整旅程讲清 REA 的 Hopper provider 内部机制:后台静默拉起 Hopper、令牌握手的 NDJSON 通道、FIFO 串行队列上的心跳与取消,以及带失效策略的反编译缓存如何复用昂贵计算。
全景图
REA 的架构是"一个分析平台 + 可插拔 provider",Hopper provider 负责把查函数、取伪代码、搜字符串等操作翻译成 Hopper 的调用。下面这张截图是它工作的瞬间:Hopper 打开了true.hop,底部状态栏正显示Executing Python script "/tmp/rea-.../bootstrap.py"——REA 注入的桥接脚本已经在 Hopper 进程内跑起来了。
整条链路由 src/hopper/ 目录的 TypeScript 侧和 bridge/hopper_bridge.py 的 Python 侧组成。
冷启动:怎么无声地唤醒一个 GUI 反汇编器 🐢
Hopper 是 GUI 应用,直接拉起会抢占焦点;重复拉起还会开第二个窗口。
启动逻辑在 BridgeLauncher.ts 的prepareHopperApplication:先用ps -ax探测Contents/MacOS/Hopper Disassembler是否已在运行(processIsRunning),已运行直接跳过;冷启动则执行open --hide --background -a <Hopper.app>,随后固定等待常量HOPPER_BACKGROUND_STARTUP_MS = 5_000(L43)。
一个诚实的细节:类注释(L131-L144)明确写道,上游 Hopper 的hopper助手内部会发 AppleScriptactivate,因此窗口仍可能被拉到前台——callers must treat possible foreground UI as an upstream Hopper constraint, not as evidence that analysis failed。这是上游约束,不是 REA 分析失败。
握手就绪:私有目录、随机令牌与 120 秒截止
桥接脚本跑在 Hopper 进程内部的 Python 线程里,一条谁都能连的 socket 是危险的。
HopperClient 的做法:在/tmp下创建rea-前缀的私有目录(L409-L415),用randomBytes(32)生成 64 位十六进制令牌(L420),以0o600权限写入带令牌的bootstrap.py(BridgeLauncher.ts#L393-L417),并把进程组归属写进同目录的ownership.json(L450-L467)。随后轮询 Unix socket、发一个health请求完成认证握手(L476-L491),全程受DEFAULT_HOPPER_STARTUP_TIMEOUT_MS = 120_000的绝对截止约束(providerStartupTimeout.ts#L7)。
桥接侧同样不留后门:hopper_bridge.py 要求请求字段恰好是{id, token, method, params},令牌用hmac.compare_digest比对,不匹配直接抛PermissionError("Invalid bridge capability")。它头部注释还点破了整个设计的根基:Keep all Hopper API access on this thread: moving dispatch to a worker can deadlock Hopper(L1-L6)——单线程不只是限制,是硬约束。
macOS 上另有一层目标租约:HopperLease.ts 注释直言Keep two REA processes from opening duplicate Hopper documents for one target/profile,两个会话不能同时打开同一个二进制。
进入队列:让线上任何时刻只有一个请求
Hopper 的 Python API 是单线程串行的。如果上层并发写 socket,响应乱序,超时和取消都会变成竞态泥潭。
REA 的答案是 HopperRequestQueue,类注释一句话:FIFO that keeps the wire serialized until Hopper actually replies。
- 每个请求带自增数字 id,写线上时形如
{ id, token, method, params }一行 JSON(HopperClient.ts#L198-L199),响应按 id 精确关联; - 后到的请求不抢线,而是上报
queued behind N Hopper request(s)(L137-L141); - 在途请求带 1 秒心跳,持续汇报
still running in Hopper (xxx ms elapsed)(L260-L267); - activity() 输出当前请求 id、操作名、已耗时、排队数,供上层做状态展示。
取消语义也刻意克制:排队中的请求可直接摘出队列;进行中的请求只在调用侧标记cancelled,注释Settle the caller on reply, cancellation, or deadline; retain active wire work(L72)——你无法打断 Hopper 正在执行的操作,但你的调用已经安全落定。
执行与缓存:一次 decompile,多次复用 ⚡
procedure.decompile()是 Hopper 里最贵的操作之一,而同一个函数常被多个有界投影反复查询。
桥接脚本用两张缓存把开销摊平:
- _pseudocode:键为
(id(document), 入口点),注释Reuse one provider decompilation for repeated bounded projections——同一函数无论查多少次,decompile()只跑一次; - _search_inventory:把函数、字符串、命名表整理成immutable, address-sorted inventory并缓存,重复搜索直接命中。
缓存不是只增不清:重命名、加注释等标注变更会触发按文档粒度失效,例如set_address_name的finally块同时调用两个失效函数(L979-L984);_invalidate_pseudocode 注释Discard cached decompilation after an analysis annotation changes。保证拿到的永远是当前分析状态下的结果——这是"证据可信"的底线。
退出清理:只清理自己
乱杀进程的代价是用户还在用的 GUI 工作区。HopperCleanup.ts 的cleanupHopperSession按阶段收尾:先落定在途请求,再发shutdown握手(30 秒HOPPER_SHUTDOWN_TIMEOUT_MS,HopperSessionValues.ts#L6),验证通过后才移除私有目录。BridgeLauncher 的注释划清了边界:REA owns only the short-lived launcher helper's ... process group. It does not claim ownership of the Hopper GUI process(L141-L143)。甚至失败路径也不留痕:注释要求Remove the token-bearing bootstrap file on every non-success path(L344-L348)。
代价与取舍
这套设计买的是可预测性,付的是吞吐:FIFO 保证任何时刻线路上有且仅有一个在途请求,但并行 Agent 场景下后到的请求只能排队等,心跳只是进度汇报,救不了总耗时。
冷启动的 5 秒是固定 sleep,不做就绪探测;缓存活在 Hopper 进程内存里,文档关闭或进程退出后全部作废,再来一轮要重新付 decompile 的钱。Linux 侧更窄:只能走verified_linux_demo适配器(HopperProvider.ts#L257-L264),且必须先验证钉住的 Hopper 构建的 SHA-256(BridgeLauncher.ts#L517-L519)。平台与目标也有限:仅darwin/linux(HopperProvider.ts#L74-L80),DOS MZ/COM 会直接提示改用 Ghidra 16 位适配器(L153-L160)。
收尾
一句话记忆点:先锁门(私有目录 + 随机令牌)、再排队(FIFO 串行 + 心跳)、别反编译两次(按文档失效的缓存)。
延伸阅读:
- 原生二进制调查总览:docs/native-investigation.md
- 整体架构中 provider 如何被编排:docs/architecture.mermaid
- 客户端与队列实现:src/hopper/(重点看 HopperRequestQueue.ts 与 HopperRequestQueue.test.ts)
- 桥接脚本全量实现:bridge/hopper_bridge.py
【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考