ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

6 条命令的 Electron 逆向分析实操:把 asar 的 IPC 链路从静态一路还原到运行时

6 条命令的 Electron 逆向分析实操:把 asar 的 IPC 链路从静态一路还原到运行时

6 条命令的 Electron 逆向分析实操:把 asar 的 IPC 链路从静态一路还原到运行时

【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea

周三 15:04,你拿到同事发来的一份app.asar:8.9 MB,目标应用装在他机器上,你跑不起来。你要回答的只有一句话——「粘贴到应用」按钮走了哪条 IPC 通道,主进程侧谁在接收。做这次 Electron 逆向分析,rea 不让你解压着祈祷。

能跑什么,几步能跑起来

rea(Reverse Engineer Anything)把逆向能力通过 CLI 和 MCP 同时暴露给你的终端与 AI 助手。对 Electron/JavaScript 目标,静态路径只依赖 Node.js 22.19+ 与 npm,不需要任何反汇编引擎。最小可运行路径两条命令:setup把你的 Agent(Claude Code、Gemini CLI 等)注册为 MCP 客户端并安装工作流指令;analyze-javascript-application把一份 asar(Electron 的归档格式)直接送入静态重构:

npx rea-agents setup npx -y rea-agents@latest analyze-javascript-application /path/to/app.asar --json

输出是 Evidence 记录——带身份、来源定位、置信度的结果对象,不是裸数据。先盯两处:Electron 边界摘要(contextBridge.exposeInMainWorld的 API key 与字面量成员路径、IPC 字面量通道),以及normalized_result.statistics(节点数、覆盖率、解析失败数)。

不执行一行应用代码,怎么还原模块边界

结论:静态路径是"解析,不执行"——eval、Function、vm.runInContext、DOM、bundle 引导代码永不使用,目标字节全程不运行。

取舍记录在 docs/javascript-artifact-reconstruction.md:JS/TS 源码按惰性文本解析,Webpack/Rspack 的 chunk 注册与模块工厂以 AST 字面量形式恢复;测试套件里有一个专门 fixture,执行它会篡改全局并抛异常,而重构恢复了它的四个模块工厂,两个副作用都没触发。图里每个节点与边都带 authority(artifact bytes / AST analysis / static inference)与认知状态(observed / inferred / unknown / unavailable),unknown是一等公民,不是缺字段。

这意味着你可以把 asar 直接喂给自动化流水线,不用先问"这个目标能不能跑"。代价是硬边界:import 与调用关系只是静态推断,invoke只与唯一一个同字面量通道的ipcMain.handle配对,动态通道永不配对,多个候选只报ambiguous而不画边。

运行时怎么绑回静态图,而不是互相冒充

结论:静态与运行时各持独立 authority,调和只新增observed_as推断边,从不覆盖任何一边的既有观察。

两条观察通道互补。被动:list-electron-targets/inspect-electron-page附加到已运行的 Electron CDP(Chrome DevTools 协议)回环端点,不执行 renderer 代码、不注入、不点击。主动:capture-electron-scenario用 Playwright 官方_electron.launch启动应用并由 rea 拥有其生命周期——60 秒启动截止,SIGINT/SIGTERM 请求取消并等待清理——记录 IPC 通道与参数形状元数据,payload 值永不保留(实现见 src/browser/PlaywrightElectronActiveProvider.ts)。

匹配规则按证据强度排序,内容寻址——同一字节内容永远映射到同一 ID,比对的是字节摘要而非文件名:捕获源 SHA-256 + 映射位置 > 唯一内容摘要 > 唯一映射路径(中等置信度);多候选是ambiguous,摘要不符是显式mismatch,路径永远不能覆盖摘要分歧。规则全文见 docs/javascript-runtime-reconciliation.md。

这意味着"磁盘上哪个文件真的在跑"有了字节级答案,且证据可回溯到两层各自的 Evidence。边界:not-observed-in-capture绝不意味着"全局未加载",source map 原始源永不作为运行时字节匹配的主证据。

追踪读出来的是什么,边界在哪里

结论:trace 返回的是可达子图、终端路径与 authority 汇总,不是反编译出的源码。

trace-application-feature的 seed 是字面量:node ID、route、string、API、IPC channel、module、native export——只接受精确或子串匹配,不接受正则,不接受可执行谓词。trace-javascript-semantics再深一层,覆盖词法定义与读取、闭包捕获、唯一解析的本地调用、参数/返回值流、Promise 链、EventEmitter 注册与派发、node:child_process创建与所有权。函数指纹忽略局部变量名,保留语法、字面量、运算符与对象键,所以压缩改名不影响跨版本比对;compare-application-versions按五级配对(内容摘要 > 模块源摘要 > 节点身份 > source-map 身份 > 结构指纹)把版本间模块归为 unchanged / added / removed / changed / unknown,见 docs/javascript-application-workflows.md。

这意味着厂商升级后你能复现同样的结论,因为结论不依赖变量名。边界:resolved表示"静态分析中唯一",不是该路径被执行过的证明;.nodeadd-on 只恢复 JavaScript 语法请求的导出成员,原生符号验证留给 Hopper/Ghidra 这一层。

一条最短可行链路,照着敲

前面讲为什么这样设计,这里只讲现在敲什么。六条命令,每条按"输入 → 关键输出字段 → 下一步判断"走。

  1. 注册 Agent(只走 CLI 可跳过):
npx rea-agents setup

无输入;输出里看各客户端的注册状态,有失败项按提示处理,然后进入下一条。

  1. 静态重构并落盘——真实应用的 Evidence 可达数百 MB,不要直接对着终端读:
rea analyze-javascript-application /path/to/app.asar --json > app-evidence.json

输入是 asar 绝对路径;关键输出字段:Electron 边界(contextBridge 的api_key、字面量 IPC 通道)与normalized_result.statistics;判断:从证据里挑一条字面量通道或字符串,作为下一条的 seed。

  1. 枚举运行中实例的页面(应用需带 CDP 调试端口启动):
rea list-electron-targets http://127.0.0.1:9223 --json

输出是本地file://页面数组;关键输出字段:target ID 与 canonical 本地路径;判断:选出承载待查功能的那个页面 ID。

  1. 检查该页面并取脚本源:
rea inspect-electron-page http://127.0.0.1:9223 TARGET_ID --include-script-sources --json

关键输出字段:每个脚本的身份与内容寻址摘要;判断:拿着这批摘要去对静态证据,看磁盘上哪个文件真的在跑。

  1. 把两份 Evidence 调和:
rea reconcile-javascript-runtime reconciliation-input.json --json

输入 JSON 含static_layers与runtime_observations(完整 Evidence 对象,不是 ID);关键输出字段:observed_as边,以及各静态资产的加载态(loaded / resident-in-loaded-asset / not-observed-in-capture / unknown);判断:ambiguous与mismatch条目转人工复核,不要猜。

  1. 追踪目标功能:
rea trace-application-feature ./trace-input.json --json

输入是完整 Evidence 加字面量 seed(如{"kind":"string","value":"notion:clipboard:write"});关键输出字段:可达子图规模、终端路径、native handoff;判断:终端路径若止于.node请求,原生部分移交 Hopper/Ghidra,静态层到此为止。

边界与诚实声明

  • capture-electron-scenario保有完整宿主机权限,不是沙箱;应用以你的用户权限运行,选一台丢得起的机器。
  • 静态分析不证明运行时:not-observed-in-capture绝不等于"全局未加载",缺边不等于缺功能。
  • 动态 IPC 通道永不配对,ambiguous 候选永不连边;图里没有的,rea 不会替你补一条。
  • 无法确定精确遗漏数时,omitted_count输出null而不是猜测值。
  • 大型应用的完整 Evidence 可达数百 MB(文档以 334 MB 的 Obsidian 为例),用inspect-analysis-view投出 summary 或单模块页,不要整读。

rea 把 Electron 逆向分析从一次性考古变成了可复现的工程动作:每条结论都带着哪些字节、哪些推断、哪些 unknown——边界不再是"我猜",而是可重跑、可交叉验证。

【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进