ARTICLE · 1184689
AI 逆向工程实战手册:REA 拆解闭源软件的完整流程、能力边界与合规红线
发布时间:2026-10-15 10:05:48 最近访问:2026-10-15 10:05:50
AI 逆向工程实战手册:REA 拆解闭源软件的完整流程、能力边界与合规红线
本文由 莫潇羽@无忆研习社(www.wuyi.wiki)撰写,转载请注明出处。REA(Reverse Engineer Anything)不是一个"一键抄软件"的破解器,它本质上是把 Ghidra、IDA、Hopper、JADX 这类专业逆向工具,通过 MCP 协议打包成 AI Agent 能直接调用的工作台。 一条 npx rea-agents setup 就能接进 Claude Code、Codex、Cursor 等客户端;之后你对着一个闭源程序说"这个搜索功能怎么实现的",Agent 会自己去反编译、翻字符串、追调用链,然后把结论连同证据和局限一起交回来。但请务必记住三件事:第一,它拆的是"跑在你机器上的那一半",服务端逻辑、云端算法、风控模型永远拆不到;第二,加壳、混淆、虚拟化保护依然能把它挡在门外,VMP 级别的高强度保护目前基本啃不动;第三,也是最容易被忽略的——"研究"和"照着做一个"在法律上是两件事,逆向研究的豁免拿不到"重建"头上。这篇文章我会从原理讲到实操:REA 的三阶段工作模型、能拆的目标清单、完整安装配置、两个可复现的实操案例(桌面客户端和 Android 端)、逆向攻防的技术底牌,以及我自己整理的一套"目标分级 + 净室隔离"合规工作流。全程不吹"扒光商业软件"这种话,我只讲能落地、且不会给自己找麻烦的做法。1.1 从 MCP 讲起:给 AI 装一个"万能插排"MCP 是 "Model Context Protocol"(模型上下文协议)的缩写。它是一套开源标准,解决的问题很朴素:让 AI 应用能统一地连接外部系统——本地文件、数据库、搜索引擎、专业软件,都可以。打个比方你就懂了。以前每个家电(电视、空调、音响)都有自己的专属遥控器和接口,AI 想控制它们,就得为每一个单独写一套对接代码。MCP 就像给 AI 配了一个万能插排:不管后面插的是什么设备,前面的接口长得都一样。AI 客户端拿到一份"这个插排上有哪些按钮"的清单,就能按需去按。角色 | 干的事 | 类比 |
MCP Host | 运行客户端的那个 AI 应用,比如 Claude Code、Cursor | 拿着遥控器的人 |
MCP Client | Host 内部的中介,负责发请求、接结果 | 遥控器的红外发射头 |
MCP Server | 真正提供能力的服务端,响应调用、协调外部工具 | 电视里的接收电路板 |
- Tools(工具):能执行的动作,比如"反编译这个函数"、"读取这份文件的字符串"。模型根据上下文自己判断该调哪个。
- Resources(资源):能读取的数据,比如文件内容、数据库记录。
- Prompts(提示模板):预先写好的工作流模板。
REA 就是一个 MCP Server。它把你的 Agent 和一堆逆向工具连了起来。1.2 REA 真正的定位:它是"调度员",不是"反编译器"REA 自己不做反编译。 它是一个编排层(orchestration layer),坐在你的 Agent 和真正的分析工具之间。它对外提供统一的分析工具箱,对内去调用:- 深度分析提供方:Hopper、Ghidra(只读模式,需要你自己装)、IDA
- 产物解析提供方:ZIP、APK、IPA、ASAR、MSIX 这类打包文件的清单解析
- 浏览器提供方:通过 Chrome DevTools Protocol 被动观察网页行为
- 原生平台工具:macOS 侧的 Mach-O 解析、代码签名、plist 读取、Swift 符号还原
所以它的技术含量不在"反编译算法"上——那些算法是 Ghidra 和 IDA 二十多年的积累。REA 的创新在工程整合和证据管理上,这一点下面会展开。用一句话概括:REA 不发明工具,它发明的是"让 Agent 会用工具"这件事。REA 是 MIT 协议的开源项目,用 TypeScript 写成,代码托管在 GitHub 的 morluto/rea 仓库里。它对外提供三种使用方式:形态一:CLI(命令行) 在终端直接跑分析,适合脚本化和自动化 命令前缀:rea 或 npx rea-agents形态二:MCP Server Agent(Claude Code / Codex / Cursor / Gemini CLI 等)直接调用 这是它最主流的用法形态三:配套的 Agent 调查技能 setup 时会一并装上,教 Agent"该按什么顺序提问"
# 一条命令完成配置(会检测你装了哪些客户端,逐步确认)npx rea-agents setup# 只想先看看它打算改哪些文件,用 dry-runnpx rea-agents setup --dry-run# 装完检查环境,看有没有缺件或配错rea doctor
安装过程有一点设计我觉得很值得学:它默认是"No"。它会先检测你机器上装了哪些 Agent 客户端,问你要开启哪些能力,把即将修改的文件列给你看,你点头才动手,而且会先备份已有配置。这种"默认保守"的交互,在这类会改配置文件、又会动系统工具的项目里,算是比较少见的克制。REA 把每一次调查都拆成固定的三段,这个框架我建议你记下来,因为它其实就是逆向工程的标准心法:阶段 | 英文 | 做什么 | 产出 |
第一阶段 | Decompile | 打开目标,还原可读代码、字符串、符号名、其他线索 | 伪代码片段、字符串表、符号列表 |
第二阶段 | Understand | 顺着线索从一个模块追到另一个模块,直到能解释清楚功能怎么跑 | 调用关系图、数据流向说明 |
第三阶段 | Recreate | 把学到的东西变成你自己项目里的功能,用你的语言和框架 | 可运行的实现代码 |
REA 自己负责前两阶段,第三阶段交回给你原来的 Agent——因为写代码本来就是 Claude Code、Codex 这些工具擅长的事。这里要划一条清晰的线:REA 明确说了,它不声称能还原原始源码,也不克隆应用。它给的是伪代码、汇编、符号、字符串和它们之间的关系,并且会标注每条结论背后的证据。新手看到"AI 逆向一切"这种标题,很容易脑补出三件事。我把它们提前澄清:- 误解一:装完就能"扒光"任何软件。 实际它受限于目标有没有加壳、混淆强度、以及你本机装了什么分析工具。没装 Ghidra 或 Hopper,原生二进制的深度分析就是空的。
- 误解二:分析结果就是原始源码。 伪代码是"编译器优化后的逻辑的近似转写",变量名大多是 v1、a2、sub_401230,跟人写的源码差得远。
- 误解三:本地分析就等于不外发任何数据。 工具确实在你本机跑,但 Agent 要理解这些结果,就得把反编译片段、调用关系、字符串发给背后的模型服务商。这一条牵扯到很多合规问题,第八章会细讲。
为什么这波和以前不一样:门槛砸到地板,风险抬到天花板业内有一个很犀利的判断:REA 的技术不新,新的是用它的人。让 AI 接上逆向工具,这件事在 REA 走红之前一年就已经有人在做了。IDA Pro MCP、GhidraMCP、Binary Ninja 的 MCP 桥接、JADX 的 MCP 插件、Hex-Rays 官方的 MCP 支持,一个都不缺。REA 走红前几天,还有逆向工具的开发者公开说,他用 IDA 的 MCP 插件,大约一小时就解完了当年 Flare-On 逆向挑战赛的全部题目。Flare-On 是谷歌旗下 FLARE 团队每年举办的逆向挑战赛,题目大多取材自真实的恶意软件样本。能一小时全通,这水平当然很高,但请注意:这类人本来就懂逆向,MCP 只是让他打字更少了。REA 干的事不一样,它把这套东西变成了一行命令。维度 | 传统路径 | 接上 REA 之后的路径 |
前置技能 | 会反汇编、看得懂汇编、熟悉 IDA 的 API | 会用自然语言提问 |
准备时间 | 装 IDA、配插件、找教程,几小时到几天 | npx rea-agents setup,几分钟
|
提问方式 | 自己知道该看哪个函数、哪个字符串 | 描述目标功能,Agent 自己找线索 |
工具切换 | 在反编译器、调试器、抓包工具之间来回倒 | 都在一个 Agent 会话里完成 |
结果形式 | 自己整理笔记 | 结构化的证据记录,可导出、可对比 |
门槛下降这件事,本身不坏。工具平民化一直是技术进步的常态。问题在于:门槛下降的速度,远远快于规则科普的速度。以前你想让 AI 帮你逆向,你得先是个会逆向的人——装好 IDA,配好插件,知道自己该问什么。这一路上无数个坎,其实都在筛掉"只是好奇想看看"的人。现在这些坎没了,直接涌入的是大量没有受过任何合规训练的普通开发者。REA 项目的热度,写稿时看已经属于现象级:从最初几千颗星,不到一周就冲到了六位数,并登上了 GitHub Trending 榜首。不同媒体的统计口径不太一样——有的按"累计星数"算,有的按"新增星数"算,还有的报道成文时项目又已经涨了一大截。所以这里我要提醒一句:任何具体到个位的星数、fork 数、下载量,都只是那一瞬间的快照,参考价值有限。 这类数据变动极快,你要真关心,直接去看仓库首页的实时数字。同样,本文涉及的一切版本号、平台支持范围、定价信息,都以写稿时的公开信息为准,请以官方文档的实时内容为准。热度之外,真正让普通人第一次"看见"AI 逆向的,其实是游戏圈。2026 年 10 月初,一批老游戏突然能在浏览器里直接玩了起来。随后有公开报道提到,一位逆向开发者用十几个 Claude Code 和 Codex 智能体并行作业,把一款射击游戏的绝大多数函数还原成了 C++ 源码,其中相当大比例的编译结果与原程序达到字节级一致。注意:他走的是 Hex-Rays 官方提供的 MCP 通道,不是 REA。 也就是说,REA 只是这波浪潮里名字最响的那一个,真正在动的是一整片水面。2.3 圈内人的分歧:一句"炒作"和一句"挡不住"有意思的是,职业逆向工程师群体对这件事普遍没那么兴奋。一种说法是"炒作"。 持这种看法的人(包括几位写过逆向教材的作者)认为,让模型接工具这件事早就有人做了,REA 只是重新包装了一遍;而且,给模型暴露的工具越多,它不一定表现越好——现在已经有 REA 用户抱怨过,它塞给智能体的工具说明太长,用不了多久就把上下文窗口挤满了。另一种说法是"能拖慢,挡不住"。 支持者认为,混淆和加壳会增加 AI 的分析成本,但并不能从根上阻止它——因为人写混淆规则的速度,赶不上模型试错的次数。这两种说法我觉得都对,只是说的不是同一件事。前者说的是"能力上限",后者说的是"经济性"。而现实里,决定一个技术会不会普及的,往往不是上限,是经济性。还有一个大家讨论得不多、但实操中一定会撞上的东西:模型服务商自己的限制。有博主公开分享过,他用 Agent 去拆某款国产剪辑软件时,Claude 拆到一半会卡住,也会被限制继续。这类拦截不是说服务商在替你判断"这件事合不合法",而是他们在按自己的内容策略处理——反编译产物里可能包含敏感字符串、可能的绕过逻辑、甚至被误判的恶意代码特征。- 不可依赖:别把关键业务流程建立在"某个模型不拦我"这个假设上。
我在自己的实践里,慢慢养成一个习惯:把分析产生的原始产物(伪代码、字符串表)当作敏感数据来对待,而不是随手丢进对话里。这个习惯后面第九节会展开成一套完整做法。先把 REA 官方文档里列出的目标类型汇总成一张表。这张表我建议你打印出来贴在显示器边上,因为它直接决定了"你手上的问题能不能用它解决"。目标类型 | 能拿到什么 | 依赖条件 | 典型场景 |
原生二进制(exe / so / dylib) | 伪代码、汇编、字符串、符号、调用与引用关系 | 本机装 Hopper、Ghidra 或 IDA | 分析无源码的桌面工具、闭源库 |
JavaScript / Electron 应用 | 模块、导入关系、source map、路由、IPC 边界、原生插件 | 只需要 Node.js | 分析 Electron 客户端的行为与接口 |
.NET 程序集 | 元数据、CIL 指令、原生依赖、版本对比 | 纯静态,无需额外引擎 | 分析企业内的小工具、插件 |
网站页面 | 页面结构、脚本、网络观测、截图 | Chrome 系浏览器 | 弄清某个前端交互怎么做的 |
Android APK | Manifest 声明、类结构、方法级反编译、引用关系 | 无头 JADX + JDK | 分析竞品 App 的功能实现 |
Android 设备 | 进程、日志、内存 dump、屏幕捕获 | adb 连接真机 | 观察运行时的实际行为 |
WASM / EVM 字节码 | 校验信息、导入导出、WAT 反汇编、分发选择器 | WABT 或本地解析 | 链上合约与前端 WASM 分析 |
固件镜像 | 区域划分、文件提取、原生分析交接 | Binwalk / Unblob | 物联网设备固件研究 |
网络抓包(HAR) | 请求响应、暴露的载荷、源码位置 | 可选 mitmdump | 分析客户端与后端的通信协议 |
Go 二进制 | 函数、字符串、引用关系 | 内置支持 | 分析 Go 写的服务端工具 |
原生二进制是最硬核的一档。 给一个没有源码的可执行文件或动态库,它能出伪代码、汇编、字符串、符号表、调用和引用关系。反编译引擎用你机器上装的哪一家都行——Hopper、Ghidra、IDA,三选一。我自己的习惯是:先用字符串搜线索,再用引用关系锁定函数,最后才看伪代码。 很多新手一上来就盯着伪代码看,结果被几千行 v1、a2 淹没,半天没有进展。字符串是导航,伪代码是终点,顺序别搞反。Electron 应用是性价比最高的一档。 因为 Electron 把渲染层代码打包成 ASAR 归档,本质上是 JavaScript,静态分析就能梳理出模块、imports、路由、IPC 通道和原生 add-on 的关系,根本不用把应用跑起来。对一个做前端出身的人来说,这一档的学习曲线几乎为零。Android APK 走无头 JADX。 它能把 APK 反编译到方法级,看清 manifest 里声明了什么、类结构长什么样、每个方法里的逻辑是什么。如果接上 adb,还能直接操作真机:看安装包、看进程、拉日志、截屏幕。网站分析走的是被动观测。 通过 Chrome DevTools Protocol 观察页面结构、脚本加载、网络请求,最后还能截图。要注意"被动"这两个字——它记录的是页面本来就在做的事,不是往页面里注入什么。WASM、EVM 字节码、固件、崩溃转储这些属于长尾。 平时用不上,但真遇到的时候,能在同一个 Agent 会话里顺手处理掉,省掉了专门去装一套工具链的功夫。这一段是我认为全文最重要的部分之一,因为它决定了你对这个工具的期望值该定在哪。REA 分析的是跑在你手里的那一半。你装在本机的客户端能拆开,但别人机房里的服务端你碰不到。这就是为什么很多人幻想"拆了国民级 App 就能拿到推荐算法"——做不到。推荐算法、支付风控、账户体系、社交关系链,这些全都跑在云端。抓包能看到请求和响应,但看不到产生这些响应的逻辑。加壳、代码虚拟化、反调试、完整性校验,这些手段本身就是为对抗逆向而生。强壳保护下的函数,反编译出来往往是一片无法识别的字节码。第七章会专门讲这块的技术细节。就算你把某个功能的实现完整还原出来了,你也还原不出它的作者当时为什么这么选。为什么这个缓存策略定成 5 分钟而不是 30 分钟?为什么这里用轮询不用推送?——这些决策背后的业务约束、历史包袱、性能实测数据,都不在二进制里。换句话说:逆向能给你"是什么"和"怎么做",给不了"为什么"。 而真正值钱的产品判断,恰恰在最后一个问题上。REA 的说明里写着,所有分析在本机执行,你的目标文件不会离开你的机器。这句话是真的,但它只说了半句。完整的版本应该是:分析引擎在本机跑,但分析结果的一部分会流向模型服务商。为什么?因为 Agent 要理解分析结果,就必须把这些内容放进模型的上下文:反编译出来的代码片段、函数调用关系、提取到的字符串常量。这些东西要发到云端模型那边才能被"读懂"。你的机器 云端+---------------------+ +------------------+| 目标程序(不动) | | || | | | || v | | || 本机分析引擎 | | || (Ghidra/IDA/Hopper) | | || | | | || v | 外发 | || 分析产物 -----------|--------->| 模型服务商 || (伪代码/字符串/调用图) | | (有独立数据策略) |+---------------------+ +------------------+
如果你拆的是自己买来的、随便研究的软件,这一步问题不大——顶多是你的使用习惯被看到了。但如果你拆的是客户交付给你的软件、或者签过保密协议的东西,这一步就可能已经构成违约了。因为保密协议约束的通常是"你不得向第三方披露",而不是"你不得上传到云端"。这两件事在很多法务眼里是等价的。所以我的第一个实操建议就是:拆之前先问一句,这个目标的代码能不能离开这台机器。 不能的话,就该考虑离线部署的模型方案,或者干脆不做。我见过太多人卡在第一步,其实都是环境问题。把下面这张表过一遍,能省掉你半小时。检查项 | 要求 | 说明 |
Node.js | 建议 20 LTS 或更高 | REA 的 CLI 走 npm 分发,Node 版本太低会直接报错 |
磁盘空间 | 预留几个 GB | 分析产物、证据包、反编译中间文件都会占地方 |
Agent 客户端 | 至少装一个 | Claude Code、Codex、Cursor、Gemini CLI、Windsurf 等都可以 |
深度分析引擎 | 按需 | 要拆原生二进制,才需要装 Hopper / Ghidra / IDA 中的一个 |
JDK | 按需 | 只在你分析 APK 时才需要,无头 JADX 依赖它 |
目标样本 | 必须是你能合法获取的 | 这条是底线,不是建议 |
关于"目标样本必须合法获取"这句,我要再说一遍。 后面第八章会讲清楚法律细节,但这里先把话放前面:来路不正的样本,即使你只是"研究研究",也不会因为你用了 AI 就变得没问题。这是能力和授权的区别,两码事。安装本身设计得挺克制,但第一次用还是建议按顺序来,别跳步。npx rea-agents setup --dry-run
这一步只做一件事:告诉你它打算改哪些文件。 它不会真的动手。我强烈建议第一次一定先跑这个。原因很简单——这类工具会往你的 Agent 配置里写 MCP 连接信息,如果你同时用着好几个客户端,动手之前最好心里有数。注意这里有一个默认行为:所有确认项的默认值都是"No"。 这是好设计,你多按几次回车不会误开一堆能力——虽然有点烦,但比"手一抖开了权限"强多了。如果你已经知道要用哪个客户端,可以直接指定,跳过交互:# 客户端参数用下划线命名,例如 Claude Code 就是 claude_codenpx rea-agents setup --client claude_code
客户端 | --client 取值
|
Claude Code | claude_code
|
Claude Desktop | claude_desktop
|
Codex | codex
|
Cursor | cursor
|
Gemini CLI | gemini_cli
|
Windsurf | windsurf
|
VS Code | vscode
|
GitHub Copilot CLI | copilot_cli
|
OpenCode | opencode
|
Devin | devin
|
这一步特别容易被忽略,而且忽略之后的症状是"装了但好像没生效"。桌面应用(Claude Desktop / Cursor / Windsurf / VS Code) 必须完全退出进程再打开,只关窗口不算 macOS:按 ⌘ + Q Windows:如果有托盘图标,也要从托盘退出终端类工具(Claude Code / Codex / Gemini CLI) 退出当前会话,重新启动一次即可
这个命令会告诉你:有没有缺件、有没有配错、你这台机器上有没有不支持的能力。装完必跑,报错先看它的输出。很多人装完之后完全不知道它动了什么。我建议你自己看一眼生成的配置,心里有个底。MCP 连接信息通常长这样(不同客户端字段名略有差异):{ "mcpServers": { "rea": { "command": "npx", "args": ["-y", "rea-agents@latest", "mcp"], "env": { "REA_WORKSPACE": "/path/to/your/rea-workspace" } } }}
除了 MCP 连接,setup 还会装一份配套的调查技能(agent skill)。这份技能的作用是教 Agent"按什么顺序提问"——先开目标、再看概览、再搜字符串、再追引用、最后才反编译。这个顺序很重要,下一章我会具体解释为什么。REA 会把分析产物落在工作目录里。我自己的习惯是把每个目标单独放一个目录,方便日后对比不同版本:rea-workspace/├── targets/│ ├── notely-desktop-2.3.1/ # 目标名 + 版本号│ │ ├── sample/ # 样本本体(不提交到版本库)│ │ ├── evidence/ # 证据包导出│ │ ├── notes/ # 我自己的分析笔记│ │ └── findings.md # 结论汇总│ └── notely-desktop-2.4.0/├── templates/│ └── feature-spec-template.md # 功能说明书模板└── policies/ └── target-whitelist.md # 允许分析的目标清单
- 目录名带版本号,因为分析产物能跨版本对比,这个能力很有用
- sample/ 目录加进 .gitignore,别把别人的软件提交到你的版本库
- policies/target-whitelist.md 这份文件的意义,到第九章你会明白——它是你日后证明"我只拆了该拆的"的第一手材料
- 每个目标单独一份 findings.md,别混在一起写
症状 | 可能原因 | 处理办法 |
装完 Agent 里看不到 rea 工具 | 客户端没完全重启 | 彻底退出进程再打开,Windows 记得看托盘 |
提示 Node 版本不兼容 | Node 太旧 | 升到 20 LTS 或以上 |
拆原生二进制时没有伪代码 | 没装 Hopper / Ghidra / IDA | rea doctor 会指出来,装一个
|
分析 APK 报 JADX 相关错误 | 缺 JDK | 装 JDK 后重试 |
Agent 聊到一半说上下文满了 | 工具说明太长 | 新开会话;只开本次需要的能力,别全开 |
分析到一半模型不往下走了 | 撞上了服务商的内容限制 | 换思路、缩小范围,或改用离线模型 |
最后一行那个问题值得单独说一下。很多人第一次撞上模型拦截时会以为是工具坏了,其实不是。 那道护栏在服务商那边,你改不了。能做的只有两件事:把问题切小,或者换一条不敏感的分析路径。比如"给我这个软件的完整伪代码"就很容易被拦;而"帮我确认这个方法里数据是怎么流转的"通常能顺利通过。问得越具体、越像正常的工程问题,越不容易撞墙。 这不只是规避风控,它本身也是更好的提问方式——范围小的问题,模型的回答质量也更高。这一节和下一节的案例,都是我为了讲解方便自己编出来的虚构目标,产品名、目录结构、代码片段全部是示意,不对应任何真实软件。我写它们的目的是把"分析流程长什么样"讲清楚,你自己动手时把路径和问题换成你的真实目标就行。先把话说在这里,免得后面读串了:第五、第六两章里的目标、路径、Agent 输出内容,通通是虚构示意;但穿插在案例中间的那些经验型段落(比如该按什么顺序提问、上下文为什么会莫名其妙被塞满)是我自己在真实项目里踩出来的,属于实操总结。下文出现"我试过""我的习惯是""我的做法是"这类表述时,指的都是后者,跟虚构案例无关。不要把这些示例的结论直接拿去套真实产品。 真实产品的实现千差万差,而且分析它们之前,你得先确认自己有那个权利——第八章会讲。假设你手上有一个虚构的桌面笔记应用 NotesLab。让你好奇的地方有好几个:- 离线全文搜索很快,你怀疑它做了本地索引,但不知道用什么结构
- 多个设备同时编辑同一条笔记时,它处理冲突的方式很顺手
- 有个"批量导出"功能,能导出成好几种格式,你好奇它怎么组织的
这一节我们只挑第 2 个走完整个流程,也就是多设备同步冲突的处理策略。原因很实在:全文检索这一类功能的技术路线就那么几条,看多了容易腻;而"冲突处理策略"背后藏着一个更值得学的设计取舍——什么情况下该让用户决定,什么情况下该让系统悄悄合并。你只想搞清楚它是怎么做的,然后在自己项目里实现一个思路不同的版本,一行代码都不抄。这就是一个典型的、合规区间内的研究目标。因为 NotesLab 是 Electron 应用,我们先走 JavaScript 这条最好走的路。Electron 应用一般会把它打包的代码放在 resources 目录下的 app.asar 归档里。# macOS 常见位置/Applications/NotesLab.app/Contents/Resources/app.asar# Windows 常见位置C:\Users\<你的用户名>\AppData\Local\Programs\NotesLab\resources\app.asar# Linux(AppImage 解开后)squashfs-root/resources/app.asar
如果你不确定路径,用 Agent 直接问也行——它可以调用系统工具去定位。这一档的好处是不需要把程序跑起来。用 CLI 直接分析目录或 ASAR 文件:npx -y rea-agents@latest analyze-javascript-application \ "/Applications/NotesLab.app/Contents/Resources/app.asar" \ --json
加 --json 是为了把结果输出成结构化数据,方便你后面做对比。路径里有空格的话一定要加引号,这个坑我踩过,报错信息还挺难懂的。- IPC 通道列表——这是关键,主进程和渲染进程之间的通信接口全在这里
IPC 通道列表为什么关键? 因为它等于一张"功能地图"。功能名往往直接写在通道名里,比如 notes:index:rebuild、sync:merge:resolve 这种。有了这张地图,你就知道该往哪个方向深挖了,而不是在几千个文件里瞎翻。这套提问模板我在无忆研习社的内部工作流里用了挺久,前前后后改了五六版,现在长这样:目标:/Applications/NotesLab.app/Contents/Resources/app.asar问题:这个应用在多个设备同时编辑一条笔记时,是用什么策略解决冲突的?请按这个顺序做:1. 先列出所有和 sync 相关的 IPC 通道和模块2. 找出处理冲突的核心函数3. 说明它用的是哪种策略(时间戳 / 版本向量 / 操作变换 / 其他)4. 给出证据:涉及的文件、函数名、关键代码位置5. 明确说清楚哪些结论是静态推断,哪些有直接代码依据不要给我完整伪代码,我只要策略和证据。
设计 | 为什么这么写 |
明确给出目标路径 | 不给路径它会到处找,浪费上下文 |
限定"一个问题" | 一次问三四个问题,回答质量会明显下降 |
指定分析顺序 | 防止它一上来就钻细节,跳过全局 |
要求给出证据 | 这是防"一本正经地胡说"最有效的办法 |
明确"不要完整伪代码" | 反编译产物极长,全塞进上下文会挤爆窗口 |
要求区分推断和依据 | 逆向场景里,这条能帮你避开很多坑 |
最后两条特别重要。REA 在这一点上的设计我是认可的:它明确区分静态推断和运行时观测,数据不完整就报不完整,不把猜测当事实。 但你自己也得有意识地去追问,别看到一段像模像样的伪代码就信了。你发出上面那个问题之后,Agent 内部大致会走这么一串:1. 打开归档,建立索引 -> open_archive / list_modules2. 搜索字符串线索 -> search_strings("conflict") -> search_strings("merge") -> search_strings("version")3. 搜索过程/函数名 -> search_procedures("sync")4. 列出模块与导出 -> list_names5. 顺着线索追引用关系 -> find_xrefs_to_name("resolveConflict") -> xrefs(...)6. 重建调用关系 -> get_call_graph(...) -> procedure_callers(...)7. 只对关键函数做反编译(范围受控) -> procedure_pseudo_code(<关键函数>)8. 汇总,按你要的格式输出
注意第 7 步是受控的——只反编译关键的那几个函数。这是整个流程里最省钱、也最不容易把上下文撑爆的做法。假设它回来了,结论大概是这个形状(以下是我按常见输出结构示意,非真实结果):结论:目标采用"最后写入优先 + 字段级合并"的混合策略,静态推断。依据: [1] 模块 src/sync/merger.js(文件已从 ASAR 还原) 导出函数 resolveConflict(remote, local) [2] 该函数引用了 compareTimestamps 与 mergeFields [3] IPC 通道 sync:merge:resolve 指向该模块 [4] 字符串常量包含 "field_level_merge"置信度:中局限: - 以上为静态分析结论,未做运行时验证 - 存在一个混淆过的辅助模块,未能解析 - 服务端是否参与冲突判定,本地无法确定
我读这类报告的第一件事,不是看结论,是看"局限"那一栏。如果一份分析报告的局限栏是空的,我基本不信它的结论。因为静态分析一定有盲区——动态加载的模块、运行时生成的代码、服务端的行为,这些都不可能从静态文件里看出来。一份诚实的报告一定会告诉你它哪里不确定。第二件事是自己抽验一条证据。随便挑一条依据,比如 [3] 那个 IPC 通道,自己去搜一遍,看是不是真的存在。抽一条就够了——如果这一条对,说明整个证据链的可信度还行;如果这一条都编的,那整份报告直接作废。技巧一:先问"有哪些功能",再问"某个功能怎么做"。很多人一上来就钻细节。更好的顺序是先要一张功能全景图(模块、IPC 通道、路由),拿着这张图自己挑感兴趣的点,再单独开一轮分析。这样你对整体的理解会扎实得多,也不容易被模型的措辞带着走。这一条跟上面那个虚构案例无关,是我自己真实项目里的经验。我同时把两个目标丢进同一个会话让它对比过,结果上下文很快就被塞满,回答质量断崖式下降——前一个目标的字符串表、调用关系还挂在上下文里,它回答第二个目标时明显在"串味",把两边的函数名混着说。一个会话一个目标,这是硬纪律。 需要对比两个目标的话,分两轮做完,然后把结论放在一张表里自己比,比让它在同一轮里比要靠谱得多。实操二:Android APK 与原生二进制的分析姿势6.1 APK 这一档:无头 JADX 是怎么工作的Android 应用的分析走无头 JADX(headless,即不带图形界面,直接用命令驱动)。所谓"无头",就是没有那个让你点点点的界面,一切靠命令和 API。它能做到方法级反编译,也就是把一个方法里的逻辑还原成可读的 Java 风格代码。配合分析,你能拿到:- AndroidManifest.xml 里的声明:权限、组件、入口 Activity、接收的 Intent
# 分析一个 APK(示意命令,具体参数以官方文档为准)npx -y rea-agents@latest analyze-apk \ "/path/to/target.apk" \ --json
adb devices # 确认设备已连接adb shell pm list packages | grep <关键词> # 看装了哪些包adb shell ps | grep <包名> # 看进程adb logcat -d > runtime.log # 导出运行日志
「真机 + 静态分析」这两条路结合起来用,效果会好很多。静态分析告诉你"代码里写了什么",运行时观测告诉你"实际跑了什么"。有些功能是靠动态下发配置开关的,静态看永远是关着的那一条分支。这里有一个必须提醒的点:APK 里往往包含第三方 SDK、图片素材、字体文件。 你在分析过程中会接触到这些东西。如果你后面要用到其中任何素材(图标、字体、音频),一定要记住:商用需要取得正版授权。 从别人 APK 里扒出来的素材,即使技术上拿到了,也不等于你有权使用。这条界限一定要清楚。原生二进制是"最硬核"的一档,因为它离机器最近。这里的反编译引擎要看你自己装了什么:分析引擎 | 授权模式 | 优势 | 我的使用感受 |
Ghidra | 开源免费 | 反编译器质量高,插件生态活跃 | 免费里最能打的,适合日常 |
IDA | 商业授权(有免费版) | 反汇编视图成熟,脚本能力强 | 老牌,界面和快捷键需要适应 |
Hopper | 商业授权 | macOS 上体验顺滑 | 界面友好,适合新手入门 |
如果你刚开始,我的建议很简单:从 Ghidra 开始。 免费、跨平台、社区资料多,遇到问题容易搜到答案。等到你确实觉得某些场景需要更顺手的工具了,再考虑付费的那两个。不管用哪个引擎,分析的顺序是共通的。这套顺序我用了很多次,基本没变过:顺序 | 做什么 | 为什么放在这个位置 |
1 | 看文件基本信息(架构、位数、是否加壳、是否有符号) | 决定后面值不值得投入时间 |
2 | 搜字符串 | 字符串是最高效的导航,界面文案、错误提示、日志前缀都在这里 |
3 | 用字符串反推函数(交叉引用) | 从"用户能看到的话"跳到"产生这句话的代码" |
4 | 看调用图,理清层级 | 避免陷在单个函数里 |
5 | 只对关键函数看伪代码 | 伪代码是成本最高的资源,最后才用 |
6 | 做动态验证 | 用调试器或运行时观测确认静态推断 |
第 1 步为什么重要? 因为如果目标是高强度加壳的,后面几步基本都可以省了——你会在"搜字符串"这一步就卡住,因为字符串被加密了。第七章细讲这个。这是新手最容易误判的一环。我举一个示意性的对比。假设某个函数在源码里是这样:intclamp_value(int v, int lo, int hi) { if (v < lo) return lo; if (v > hi) return hi; return v;}
经过编译器优化、再被反编译出来,你看到的可能长这样:// 伪代码示意,非真实输出int __fastcall sub_401230(int a1, int a2, int a3){ int v3; v3 = a2; if (a1 >= a2) { v3 = a3; if (a1 <= a3) v3 = a1; } return v3;}
这两段在逻辑上等价,但你如果直接照抄下面这段去重构,会写出很难维护的代码。 因为编译器已经把原来的两个 if 合并成了一个嵌套分支,变量名也没了。所以用伪代码的正确姿势是:把它当作"逻辑等价物"来理解,而不是当作"源码"来搬运。 你要从里面看出的是意图(这是个范围钳制),而不是它的具体写法。还有一层坑:内联和优化会"骗"你。 一个函数在源码里只有三行,编译后可能被内联到十几个调用点,你看到的就是十几段重复代码。反过来,一个被编译器合并的大函数,在伪代码里长得像个巨型循环。看到这类反常结构,第一反应应该是"这可能是编译器优化的产物",而不是"原作者写得很烂"。把上面两节合起来,我总结了三条通用结论,你可以直接当作工作原则:- 字符串先行,伪代码压轴。 搜索成本低的东西先做,反编译成本高的东西后做。这条能帮你节省大量时间。
- 静态和动态必须交叉。 只有静态,你会漏掉运行时行为;只有动态,你会看不懂协议的来龙去脉。两条腿走路。
- 结论必须带证据和局限。 这条既是 REA 的设计原则,也应该是你自己的写作纪律。你交给同事的分析报告,如果局限栏是空的,那就是一份不合格的报告。
很多人把"加壳""混淆""加密"当成一回事,其实它们是不同层级的对抗手段,成本和效果差得很远。我把常见的手段整理成一张表:保护手段 | 原理 | 对抗静态分析 | 对抗 AI Agent | 对性能的影响 |
符号剥离 | 编译时去掉函数名、变量名 | 弱 | 弱 | 无 |
名称混淆 | 把类名、方法名改成 a、b、c | 中 | 弱到中 | 无 |
控制流混淆 | 打乱分支结构、插入无效跳转 | 中 | 中 | 小到中 |
字符串加密 | 字符串常量加密,运行时才解密 | 中到强 | 中到强 | 小 |
加壳(压缩/加密) | 整个程序被包一层,运行时解压到内存 | 强 | 强 | 小到中 |
代码虚拟化(VMP) | 把关键代码翻译成自定义字节码,在自带虚拟机上执行 | 很强 | 很强 | 中到大 |
反调试 | 检测调试器存在,发现就改变行为或退出 | 只对抗动态 | 中 | 小 |
完整性校验 | 校验自身代码有没有被改过 | 中 | 中 | 小 |
关键结论在最后两行之外的那一行:代码虚拟化是目前公开技术里性价比最高的强保护。 它也是你判断"这个目标值不值得投入时间"的最重要信号。正常编译是这样的:你的 C 代码 → 机器指令 → CPU 直接执行。代码虚拟化插了一刀:你的关键代码 → 被翻译成一套只有它自己认识的字节码 → 由程序里自带的一个"虚拟机"来解释执行这些字节码。这套自带的虚拟机和字节码指令集,是保护方案自己设计的,跟标准 CPU 架构没有关系。于是逆向者面对的情况变成:- 你看到的不是 mov eax, ecx,而是一段段循环,每段循环在处理一个字节
- 每个"字节"的含义,取决于虚拟机自己的操作码表,而你手上没有这张表
公开的技术资料里描述过这个机制的细节:虚拟机会为进程创建新的节区来存放虚拟机代码和虚拟字节码,关键代码的入口被替换成跳转指令,原来的代码位置用垃圾数据填充。虚拟机内部的指令处理程序(handler)还会用大量逻辑门运算来隐藏原本的运算逻辑,再配合对标志寄存器状态的精细控制,让控制流更加难以还原。这就是为什么它对 AI 特别有效。 AI 的优势是"量"——它可以快速试错成千上万次。但虚拟化保护的问题不是量的问题,是"信息缺失"的问题:在拿到操作码表和虚拟机语义之前,你手上的字节码就是一堆没有意义的数字,试再多次也试不出来。 你得先做一件需要人来判断的事:把虚拟机的语义逆向出来。代码虚拟化还有一个副作用:体积会暴涨。下面这组是公开技术博客与安全社区在给 VMProtect 做体积实测时汇总出来的对比数据,我把它整理成表,方便你看比例:测试程序 | 原始体积 | 虚拟化保护后体积 | 膨胀倍数 |
计算器小程序 | 约 27 KB | 约 3.5 MB | 约 130 倍 |
中型测试程序 | 约 192 KB | 约 3.8 MB | 约 20 倍 |
迷宫小程序 | 约 8 KB | 约 3.43 MB | 约 440 倍 |
关于这组数据要说明三点。 第一,它不是厂商发布的官方基准,而是社区与个人博主在多轮实测中汇总出的结果,换一个保护工具的版本、换一组保护选项(比如是否勾选压缩、保护哪些函数),数字都会有出入,所以量级可以参考,具体数值别当标准答案。第二,它和你熟悉的压缩壳方向正好相反——UPX 那类壳是把体积压小,虚拟化壳是把体积撑大,因为虚拟机本体和虚拟字节码都要一起打包进你的程序里。第三,唯一稳定的规律是"至少涨一个数量级":上面三条里涨得最少的也有二十倍,你完全可以拿这一点当信号用。这条数据对你的实际意义是:体积异常膨胀本身就是一个信号。 一个功能明明很简单的小工具,装完之后体积大得离谱,那大概率是上了虚拟化保护。你可以据此快速判断"要不要继续投入"。这里要纠正一个常见误解:不是"用了某某加壳工具"就等于安全。公开的技术文章里总结过,如果只是简单套一层壳、不做虚拟化处理、核心逻辑还是明文,那依然有可能被绕过。真正提高门槛的是组合用法:- 加上反调试检测:API Hook 检查、硬件断点扫描、调试器特征识别
五个都做齐,破解成本才会真正抬高。 只做其中一个,尤其是只做前两个,基本上就是"防君子不防小人"。还有一个现实情况:网上确实能找到一些自动化的脱壳脚本,但它们大多只对早期版本有效。对于启用了完整虚拟化加授权模块的较新版本,还是得结合动态调试、内存分析、语义重构、函数伪代码还原一步步来,几乎没法"通杀"。我看到的公开讨论里,圈内人的说法其实比较一致,我把它概括成一句:"能拆"和"拆得动"之间,差的是成本曲线,不是能力开关。无保护 / 仅符号剥离 -> AI 基本能拿下来,速度很快轻度混淆 -> 能拿下来,需要多几轮引导中度混淆 + 字符串加密 -> 拿得下来,但要人工介入拆解关键点加壳(常见壳) -> 困难的开始,AI 容易卡在壳的处理上完整代码虚拟化(强壳) -> 目前基本啃不动,需要人类专家深度参与服务端逻辑 -> 无论什么工具都拿不到
注意最后两行。 一行是技术边界,一行是物理边界。很多文章把这两行混在一起讲,导致读者对能力产生了严重误判。加壳(常见壳) 那一行也值得说一句。有做逆向产品的公司在公开渠道提到过,碰到加壳样本,模型分析照样会卡住。这说明当前的能力状态是"能处理容易的那一头",公开的成功案例也大多落在这一侧。我们通常会以为"给 AI 更多工具,它就更强"。但一位调试器与逆向工具的开发者公开表示过相反的看法:他不认为给模型暴露更多工具能让它表现更好。为什么?因为每个工具的描述、参数说明都要占用上下文。工具越多,光是把工具说明读完就消耗掉大量空间,留给真正分析任务的余量就少了。现在也确实有用户抱怨,工具说明太长,聊不了多久上下文就满了。只分析 Electron 应用?那就别开原生二进制那一堆。只拆 APK?那也不需要 Hopper 相关的工具。每次新开会话、只开这一轮需要的,比"全开然后抱怨它变笨"要有效得多。- 护城河正在从"藏"转向"贵"。 以前大家相信只要不给源码就安全。现在的事实是:只要程序跑在用户手里,就能被拆开。所以软件公司的应对方向在变化——不是把代码藏得更深,而是让"拆了也没用"。比如把关键逻辑放服务端、用云端签名、把数据和算法绑在一起。一位写过逆向教材的作者给出的建议就很直接:只要程序跑在用户手里,就能被拆开,唯一稳妥的办法是把关键逻辑放到服务器上。 有意思的是,推荐算法的护城河从来就不在客户端代码里。
- 不要为了防御去做"反人类设计"。 网上有一种说法很流行:既然代码藏不住,那就把代码写成一团乱麻,让 AI 看了都放弃。我不同意这个方向。过度混淆的代价是团队自己也没法维护、没法排查线上问题。防御的重点应该放在"关键的那 5%",而不是把整个代码库都搞成一坨。
- 对开发者来说,最有价值的动作是"提前想清楚哪些东西不该装进客户端"。 这比事后加壳便宜得多,也可靠得多。
"拆一个软件"和"照着做一个"是两件法律上完全不同的事。前者在许多情形下有明确的空间,后者几乎没有。而 REA 的宣传语恰恰把这两件事并排放在一起:它一边说帮你理解功能,一边说"为你的项目实现类似功能"。中间那道法律上的隔离墙,在同一个 Agent 会话里是自动消失的。所以这一章,我把"拆软件"这件事拆成四个必须过关的层面来讲。最高人民法院 2020 年关于商业秘密案件的司法解释有一个清楚的表述:对从公开渠道取得的产品进行拆卸、测绘、分析,从而获得技术信息,不属于侵犯商业秘密。 这个原则在更早的司法解释里就已经确立,反向工程长期被定义为"通过技术手段对从公开渠道取得的产品进行拆卸、测绘、分析而获得该产品的有关技术信息"。如果先用不正当手段拿到了秘密,然后再拿"我在做逆向"当说法,法院不认。这句话的实操含义是:- 你从官方渠道下载的、合法购买的软件 → 拆卸分析,商业秘密这条基本没问题
- 你从内部渠道搞来的、客户交付的、或者别人违规泄露给你的 → 无论你做什么,风险都在
所以"样本来路"是你动手之前第一个要确认的事。 不是技术问题,是纪律问题。我国的《计算机软件保护条例》第十七条允许为了学习和研究软件内含的设计思想和原理而使用软件。更明确的是,2020 年修正的《著作权法》第五十条,把"进行加密研究或者计算机软件反向工程研究"列为可以避开技术措施的法定例外情形之一。这里要说清一个法律上的细节:反编译本身会构成一次"从一种形式到另一种形式的复制",但这种附随的复制,学界和实务界普遍认为并非法律需要管制的典型复制行为。反编译的最终目的是获取软件中不受著作权保护的成分,这个目标本身是正当的。这一条对想做产品的人是好消息。《计算机软件保护条例》第六条写得很清楚:保护不延及开发软件所用的思想、处理过程和操作方法。翻译成白话:别人有个好用的搜索功能,你自己写一个效果相似的,单从版权角度看,本身不违法。因为"搜索"这个功能、这个思路,不受版权保护;受保护的是表达,也就是具体那一串代码怎么写的。8.4 第三层:合同(这一层最容易被忽略,也最危险)软件行业应对"别人拆我的软件"这件事,有一套老办法,叫净室开发(clean room)。- 一组人负责去拆对方的软件,只写出一份功能说明书——描述这个功能做什么、输入输出是什么、行为表现如何,不写实现细节
- 另一组人从没看过对方代码,只拿着这份说明书,从头写自己的实现
- 两组人之间隔着一道墙,这道墙本身就是日后打官司时的证据,用来证明新代码是独立写出来的
这个流程的核心不是"技术上的隔离",是"证据上的隔离"。而 REA 这类工具,恰好把这道墙拆了。为什么?读反编译结果的是这个 Agent,写新代码的还是这个 Agent,中间没有任何隔断。 它先看了别人的实现,再"自己写",这个顺序本身就很难证明"独立开发"。国外技术社区有人给这种做法起了个很形象的说法,叫"洗知识产权"——看起来是新代码,但来源链条不干净。外部报道里还提到一个很能说明问题的细节:一个复刻某款图形软件的开源项目,开发者明确禁止团队成员使用逆向工具和这类 AI 逆向工具,理由很简单——怕被起诉。再说合同层面本身。大多数商业软件的用户协议里,都有一条禁止反编译的条款。 这类条款在不同地区的效力差别很大:地区 | 禁止逆向的合同条款效力 | 参考依据 |
美国 | 经常被认定有效、可执行 | 2003 年联邦巡回上诉法院在 Bowers v. Baystate Technologies(320 F.3d 1317)中认定:软件许可里的禁止逆向条款不因联邦版权法而失效,逆向之后做出竞品的一方按违约赔了钱。要注意它判的是"合同违约"成立,不等于"逆向本身违法" |
欧盟 | 为实现互操作性而反编译时,合同里禁止这类反编译的条款无效 | 欧盟软件指令(91/250/EEC,后由 2009/24/EC 编纂承接)第 6 条给了互操作性反编译的例外,第 9 条第 1 款明确写"任何与第 6 条相冲突的合同条款一律无效" |
中国 | 研究性使用有法定空间,但合同约定仍需重视 | 著作权法的技术措施例外条款 + 合同法一般规则 |
关于欧盟那一栏,还要再补一个限定,不然容易被误读成"在欧盟反编译随便做":那个"合同条款无效"的结论是有前提的——你的反编译得确实是为实现互操作性所必需。 第 6 条给出的例外,范围本身就限定在"为一个独立创作的程序实现互操作性"这一个目的上,第 9 条第 1 款之所以敢说合同条款无效,是因为例外的边界已经画得很窄了。换句话说,如果你的目的不是互操作——比如就是想照着做一个功能一样的同类产品——那把"合同条款无效"的保护伞对你撑不起来。补一个细节:欧盟法院在 2021 年的 Top System 案(C-13/20)里澄清过,第 6 条并不是欧盟法下唯一允许反编译的通道,第 5 条第 1 款下为纠正错误等目的所必需的反编译,可以不受第 6 条那套条件的约束。但无论走哪一条,目的都必须落在欧盟法认可的那几个名单里,"做一个竞品"从来不在名单上。同一件事,换个地方答案就不一样。 这就是为什么"我在国外看到有人这么干没事"不能作为你的判断依据。而且还有一个更细的问题:一个人在自己电脑上做研究,和把这种能力打包成一行命令分发给十几万人,是不是同一件事?法律条文没有直接给答案。但值得注意的一点是,《著作权法》第五十条在列出豁免情形之后,紧跟了一句限制:不得向他人提供避开技术措施的技术、装置或者部件。这句话的含义是:豁免的是"你自己研究",不包括"你造一把钥匙发给所有人"。这也是为什么我认为使用这类工具时,个人研究和批量分发的边界需要特别小心。前面第三章讲过:分析引擎在本机跑,但分析产物会流向模型服务商。来源一:你的保密义务。 如果你拆的是客户交付的软件,或者签了保密协议的东西,把反编译结果发到云端模型,这一步本身就可能构成违约。因为保密协议约束的通常是"不得向第三方披露",而模型服务商在你和客户看来,就是第三方。来源二:模型服务商自己的策略。 前面提到过,有博主拆某款国产剪辑软件时,Claude 拆到一半会卡住、会被限制。那道栏杆拦在哪里,由服务商说了算,不透明、不稳定、不可依赖。来源三:跨境数据的问题。 这一条我要说得直白一点,因为它最容易被"反正工具是在我本地跑的"这个错觉盖过去。只要你用的是境外模型服务,那被你分析出来的代码片段、字符串、调用关系,实际上会随请求一起传输到境外服务器上。 拆一个开源项目或者自己买来的桌面小工具,这个动作多数时候没什么分量;但如果你拆的是企业内部系统的客户端、涉及客户信息或个人信息的产品,那"把这段代码发到境外"这件事本身就可能落进数据出境合规的管辖范围,而且它跟被分析对象有没有商业秘密、有没有创新性都没关系——落在管的是"数据出境"这个动作。再叠一层:境外模型服务的使用,本身也需要遵守国内网络与内容管理相关规定。 这两件事不要混在一起看,一个是数据出境,一个是服务使用的合规性,任何一条踩了都麻烦。所以我给自己的规矩很硬:分析目标只要带上"客户""个人信息""内部系统"这三个标签里的任意一个,就一律不上境外模型服务,换本地部署的方案。 拿不准的时候就别做——这一层是四层里唯一完全由你说了算的,没有理由在这上面赌运气。落到操作上就一句话:拆之前先判断"这个目标的代码能不能离开这台机器",不能就换离线部署方案,或者干脆不做。REA 的免责声明里,有一句话的措辞很值得琢磨。它说自己为"合法的逆向工程研究、分析和重建"提供工具。"研究"和"分析"这两个词,上面那些法条都给留了门。但"重建"(reconstruction)这个词,找不到对应的豁免。也就是说,项目方自己把"重建"写进了合法用途,同时又把"取得授权、遵守法律"的责任完整地交给了你。这个结构很常见,也很合理——工具提供方不承担责任,使用者承担责任。项目方 → 说:责任在你模型服务商 → 会拦你,但标准不透明被拆的公司 → 手里握着用户协议和律师真正站在风险正中间的,只有发出那句指令的用户
所以我的态度是:把免责声明当技术文档读,不是当法律意见读。 它告诉你工具想干什么,不告诉你你能干什么。我把上面四层压缩成一份可以照着做的清单。每次动手前过一遍,大概花两分钟。 | 检查项 | 通过标准 |
1 | 样本来路 | 来自官方渠道或合法购买,有获取记录 |
2 | 使用目的 | 我能说清楚是"研究原理"还是"做竞品",前者可做,后者别做 |
3 | 用户协议 | 我读过目标软件的服务条款,知道里面有没有禁止逆向的约定 |
4 | 分析范围 | 我只需要弄清一个具体问题,不是"把整个软件拆一遍" |
5 | 数据外发 | 目标代码可以离开这台机器(或者我用的是离线模型) |
6 | 读取与编写是否隔离 | 看反编译结果的和写代码的,不是同一个流程 |
7 | 证据留存 | 我留下了分析记录,能说明我做了什么、没做什么 |
8 | 产出边界 | 我的产出是"思路"和"自己的实现",不是"照着还原的代码" |
第 6 和第 8 项是净室开发的核心,下一章会展开成完整流程。第 3 项我特别想强调。很多人的误区是"法律允许研究,所以我可以随便研究"。 但你和软件厂商之间还有一层合同关系——你点过"同意"的那份协议。法律给的例外和合同给的约束是两个体系,合同里的约定只要不违反法律的强制性规定,通常就有约束力。最后补几个容易被忽略的点,都是国内环境下的实操注意事项:- 涉及 AI 生成内容的发布:如果你把分析结果整理成文章、视频发到国内平台,注意平台对 AI 生成内容的标注要求。涉及音视频、配音、图像这类生成内容,该标注就标注,别省这一步。
- 涉及素材、字体、音乐、图片的商用:分析过程中拿到的任何素材,商用都要取得正版授权。技术上拿得到,不等于法律上能用。
- 不要宣传"破解""脱壳服务"这类内容:这属于灰色地带,不在本文讨论范围,也建议你不要碰。
- 不要用"能扒光商业软件"这种话做宣传:既不符合事实,也容易给自己带来不必要的麻烦。
说到底,这一章想传达的其实只有一句话:工具的边界在技术里,你的边界在规则里。这两件事不重叠。净室开发的精神是"读的人和写的人分开"。用 AI 之后,物理上很难做到隔断——毕竟都是同一个 Agent。但流程上完全可以补回来,关键是在中间加一个"人工翻译"的环节。我的做法是把整个流程切成三段,段与段之间用书面产出物连接:- 阶段一和阶段三必须是不同的会话,最好不同的模型账号。 不要在一个会话里先说"帮我拆它"再说"顺便帮我写一个"。
- 阶段二必须有人工参与。 这一步是整条链的核心。你要把"它怎么写的"翻译成"它要做什么"。翻译的过程中,具体的实现细节会被自然丢掉,留下的只有行为特征。
- 产出物要留痕。 分析结论和功能说明书都存档。日后如果真有人问起"你这代码怎么来的",这两份文件就是你的解释。
这套流程不是为了应付谁,是为了让你自己能说清楚。 说实话,很多争议到最后不是法律判出来的,是"你能不能解释清楚"决定的。我给自己定了一张三档分级表,贴在 policies/target-whitelist.md 里。每次想拆一个新东西,先来这里对一下。档位 | 特征 | 我的处理方式 |
白名单 | 自己写的 / 公司自己的产品 / 明示允许研究的开源项目 / 有书面授权的 | 正常分析,走完整流程 |
灰名单 | 自己合法购买的商业软件、公开下载的免费软件,仅为了解原理 | 可以做,但严格控制范围:一个问题一轮,不做全面还原,不外发到云端模型 |
黑名单 | 客户交付物 / 签过保密协议的 / 明令禁止逆向的 / 来路不明的 / 涉支付与安全的第三方客户端 | 不碰。有需要就走正式授权申请 |
"灰名单只做单点问题"这条规则,我觉得最实用。 很多人出问题不是因为拆了不该拆的东西,而是因为对合法获取的东西做了"全面还原"——那性质就变了。再补一条我自己总结的经验:涉及资金、账号、身份认证的客户端,别碰。 这类软件的保护措施最严,法律风险最高,而且你拆出来的东西也基本没什么产品价值——它们的护城河全在服务端和风控体系上。这几年我(莫潇羽@无忆研习社)接触过不少人来问"我想拆个 App 看看它怎么做",十个里面有八个,问完之后发现其实自己想解决的是另一个问题:不是"它怎么做",而是"我该不该做这个功能"。如果是后者,那你要的其实是产品判断,不是逆向技术。 先把自己的问题想清楚,能省掉很多无用功,也能避掉很多风险。如果是团队场景,很多时候拿一份准用文件并不难,只是没人去要。写邮件的时候把范围讲清楚,通过率会高很多。主题:关于 <产品名> 功能实现原理的研究授权申请尊敬的 <对方>:我方正在开发 <你的产品>,其中 <某功能> 的实现方式需要参考行业通用实践。为避免任何歧义,特此申请如下范围的授权:1. 分析目标:<产品名> <版本号>,来源为 <官方渠道/已购买授权>2. 分析目的:了解 <某功能> 的技术实现思路,用于 <自研产品的技术选型>3. 分析范围:仅限 <某功能> 相关模块,不涉及其他功能4. 分析环境:离线环境,分析过程不接入任何云端服务5. 产出形式:内部技术文档,不含任何反编译代码6. 承诺事项:不复制、不传播源代码;不用于降低互操作性之外的任何目的盼复。
这份模板的思路是:把"我只要理解原理"这个意图,用可核查的条款写清楚。 范围越具体,对方越容易答应;范围写成"想研究一下你们的产品",谁都不敢签。这不是法律程序,只是"自我说明"的准备。我自己的做法是每个目标留三样东西:留存项 | 内容 | 存放位置 |
来源记录 | 从哪下载的、什么时候、订单号或链接 | notes/source.md
|
分析台账 | 每轮问了什么问题、得出什么结论、什么时候 | notes/log.md
|
产出物 | 分析报告、功能说明书(不含反编译原文) | findings.md + spec/
|
明确一点:不要留存反编译出来的完整源码。 反编译产物本身是衍生自他人作品的表达,留着它既没有实际必要,又在形式上不好解释。你要留的是你写的结论,不是别人的代码。我一般会在分析完成后清理掉原始伪代码和字符串导出,只在笔记里保留必要的函数名和逻辑描述。- 换账号:分析和写代码用不同的模型账号,避免上下文串在一起
- 新会话:做实现阶段时一定新开会话,不要把分析历史带过去
- 关工具:实现阶段把 REA 这类分析工具关掉,只留写代码和测试的能力
- 离线模型:目标敏感时,用本地部署的模型做分析,产物不出机器
- 物理隔离:如果条件允许,专门一台机器做分析,不接公司内网
最后一条听起来夸张,但在一些对合规要求严格的团队里是常规做法。能不能做,取决于你手上的目标有多敏感。某开发者看到一个 App 的动效很顺滑,就让它拆了一下,Agent 交回来一份详细的实现说明,还附了一段伪代码。他觉得挺好,就把伪代码直接贴进自己项目里改了改变量名,代码提交了,功能上线了。- 拆解本身,如果样本是合法获取的,且他只为了解原理 → 到这一步问题不大
- 但从"贴进项目"那一刻开始,性质就变了。 他把衍生的表达直接搬了过来,且中间没有任何独立重写的环节
- 更糟的是,他保留了"读"和"写"在同一个会话里的记录
反过来,如果他把这份说明放进抽屉,隔一天新开一个会话,对着说明书写自己的一套实现——结果可能功能一样,但来源链条是干净的。同一个技术动作,两个不同的流程,法律上的分量完全不同。 这就是流程的价值。净室开发里最关键的一份产出,就是功能说明书。它的写法有讲究:只描述行为,不描述实现。应该写的 | 不应该写的 |
这个功能做什么、解决什么问题 | 用到了哪个类、哪个函数 |
输入是什么、输出是什么 | 关键的算法结构长什么样 |
在各种边界情况下表现如何 | 用了什么数据结构、什么库 |
性能特征(大概什么量级) | 具体的参数取值 |
用户能观察到的行为 | 代码的组织方式 |
这份文档的检验标准很简单:一个完全没看过原软件的人,只看这份文档,能不能写出一套自己的实现? 能,说明这份文档合格。如果他看完之后说"这不就是照着人家抄吗",说明你写得太细了。# 功能说明书:离线全文搜索## 1. 目标用户在多设备场景下编辑笔记,需要在断网时也能秒级搜索到历史内容。## 2. 行为描述- 输入:搜索关键词(中英文混合)- 输出:按相关度排序的结果列表,包含标题与高亮片段- 响应时间:本地数据量在数万条量级时,首屏结果应在百毫秒级返回- 断网时可正常使用;联网后新内容应在短时间窗口内被索引## 3. 边界情况- 空关键词:返回最近编辑的内容,而非空列表- 特殊字符:不作为通配符处理- 数据量增长:索引体积应与原始数据呈近似线性关系## 4. 非目标(明确不做)- 不做云端的语义搜索- 不做跨账号的全局检索## 5. 性能量级(观察结论)- 匹配阶段应为内存级操作,不依赖磁盘随机读
注意第 4 节"非目标"。写明"不做什么",比写"做什么"更能帮你避开模仿。 因为一旦你连"不做什么"都跟原产品一致,那就说明你已经贴着它走了。- 换语言、换框架、换数据结构。 原产品用 A 方案,你就用 B 方案。即使性能差一点也没关系,重要的是独立。
- 不要做"字节级匹配"。 把结论先放在最前面:追求"编译后和原程序逐字节一致",是本文里法律风险最高的一个动作,绝大多数场景下不要碰。 有些人把它当成"还原得准不准"的证明,但它的性质得看清楚——它要求你的实现精确复现对方的表达形式,等于用技术手段自证"我不是独立写的",这跟独立实现的方向正好相反。唯一还能接受的用法,是纯为了学习编译器行为,在隔离环境里做编译输出对比;只要你开始为了让自己的产品"跑起来一模一样"而回头改代码,性质立刻就变了。
- 不要复用第三方素材。 图片、字体、音效、图标,一律自己找或买。商用需取得正版授权,这条没有例外。
- 检查开源许可证。 你在实现过程中如果引入了开源库,注意许可证的传染性。有些许可证(比如 GPL 系)要求衍生作品也开源,如果你不想开源,就得避开这些,或者只通过独立进程调用的方式使用。这一步千万别省,等到要发布的时候才发现许可证冲突,返工成本很高。
功能实现了,怎么确认它真的达到了预期?我的做法是做一张行为对照表,逐项对比,但对比的是行为,不是代码:对比项 | 原产品表现 | 我的实现 | 是否达标 |
首次搜索响应时间 | 百毫秒量级 | 百毫秒量级 | 达标 |
空关键词行为 | 返回近期内容 | 返回近期内容 | 达标 |
特殊字符处理 | 原样匹配 | 原样匹配 | 达标 |
索引体积增长 | 近似线性 | 近似线性 | 达标 |
断网可用性 | 可用 | 可用 | 达标 |
这张表的意义不只是验证功能,它也是你的"独立开发"证据。 因为它记录的是"我达到什么效果",而不是"我照抄了什么代码"。我自己做这类分析,收获最大的其实不是"抄到了一个功能",而是推翻了自己原来的技术假设。举个例子:我原本以为某类应用的检索一定是靠数据库的全文索引实现的,结果分析下来发现,人家是先在内存里维护一份精简索引结构,数据库只做持久化。这个取舍背后的原因很清楚——用户对"边打字边出结果"这件事的容忍度极低,而在内存里操作才能做到那个响应速度。这种"哦,原来可以这么权衡"的瞬间,是逆向分析真正的价值所在。 它给你的是设计判断力,不是代码片段。而设计判断力,是你抄不走的,因为它在你自己脑子里。所以我的建议是:每次分析完之后,花十分钟写一段"我从中学到了什么"的总结。 这段总结迟早会成为你自己的技术积累,比任何一段伪代码都值钱。前十章该讲的都讲过一遍了。这一章我换个处理方式,不再逐条复述:前面五个都属于"操作型"坑,压成一张速查表,每条只留症状和一句话对策,细节回对应章节看就够了;后面两个属于"判断型"坑,单独展开写透,因为在正文里没充分讲过,而真正让人栽跟头的往往正是这两个。坑 | 症状 | 一句话对策 | 细节回看 |
把伪代码当源码用 | 代码能跑但极难维护,分支诡异,变量叫 v3、v4 | 从伪代码里拿走"意图",实现自己重新组织 | 6.4 |
一个会话里既让 AI 拆、又让 AI 写 | 效率高得可疑,一轮对话就把功能做出来了 | 读和写分两个会话,中间插一份人工功能说明书 | 9.1 |
一上来就要"完整伪代码" | 模型聊到一半停下,或者干脆拒绝回答 | 先要功能地图,再要单个模块,最后才看关键函数 | 5.5 |
以为装了工具就能拆一切 | 拿加壳目标硬啃,跑半天没结果,然后怪工具不行 | 动手前做五分钟体检:体积、壳特征、字符串能不能搜出来 | 3.3 |
工具全开、目标堆一起 | 刚开始挺好,聊一阵之后回答越来越离谱 | 按需开能力,一个会话一个目标 | 7.6 |
这五条只给一行,是因为它们本质上是操作习惯问题——顺手改掉就行,展开写反而占地方。下面两个不一样。11.2 坑六:把目标交给云端模型之前,没做任何判断这个坑的症状很有欺骗性:分析做完了、报告也写好了,然后你才在某个瞬间想起来——"这东西好像签过保密协议"。更麻烦的是,它不像坑一、坑二那样会立刻让你感觉到痛。代码能跑、结论有用,技术指标全是绿的,出问题的地方在你当时看不见的位置。等客户或者法务问起来,你手上甚至连一份"我当时是怎么判断的"记录都没有。老有人踩它,我觉得根子在一个默认假设:"工具在我本机跑,那数据就在我本机。" 这个假设放在别的本地工具上大多成立,放在这类 Agent 工具上不成立——分析引擎本地跑,理解结果的那部分在云端跑。第三章、第四章都讲过原理,这里只说怎么办。我的做法是把"能不能离开这台机器"这个问题提到最前面,而不是留到最后。具体就三个动作,加起来两分钟:- 动手前先问来源:目标是怎么来的?有没有签过保密条款?答案是"客户给的""签过 NDA"的,直接进下一问。
- 再问内容:里面有没有个人信息、客户数据、内部系统信息?只要有一样,一律不用境外模型服务。
- 最后才定工具组合:普通研究目标走云端模型没问题;敏感目标换成本地部署的模型,或者把分析范围缩到只剩自己手写的一小段脱敏样本。
顺序是关键。 很多人是反着来的:先用最顺手的工具跑完,跑完再想合不合规。那时候成本已经发生了,反编译产物已经在别处了,想撤也撤不回来。补一个小习惯:把这三问的结论记进 notes/,一句话就行。 第九章的证据留存是给"我做过什么研究"留痕,这里的记录是给"我判断过什么风险"留痕,两件事都值得做,成本都很低。这是七个坑里最根本的一个,也最不容易自察——因为它不在技术层面出错,出错的地方是你的判断。我见过不少人是因为"顺手"栽跟头的:本来只是想看看某个交互怎么实现的,结果工具太顺手,一轮下来把一个完整模块都还原完了;再顺手一点,就把实现搬进了自己的项目里。中间没有任何一步让他觉得"我越界了",因为每一步单独看都只是"再看一眼"。技术能力和行为正当性,是两套独立的评分标准。 一个目标能不能拆,取决于你的工具和技能;一个目标该不该拆,取决于样本来源、你的目的、你和对方之间的合同关系、以及数据会不会外流。这两者之间没有推导关系——技术再强,也推不出"所以我可以做"。关于"该不该",第九章给过一张三档分级表,这里只强调我自己的执行方式:把它做成一个动手前必须先过的闸,而不是靠临场自觉。 每次想拆新东西,先打开 policies/target-whitelist.md 把目标对进去,落在哪一档就按哪一档的规矩走:- 落在灰名单:只做单点问题,一轮一个,不做全面还原,不上云端模型
- 落在黑名单:不碰。真有需要,就用 9.3 那份授权申请模板把范围写清楚,去要一份书面文件
这张表的意义不在于"别人看了会觉得我很规范",而在于它能拦住你自己那一瞬间的"顺手"。规则写下来之前,边界是弹性的;写下来之后,它才变成可执行的。最后一句实在话:真正让你长期难受的,通常不是某一次分析做得好不好,而是你在某个说不清的边界上多走了一步。第十章讲净室工作流、这里讲三档分闸,本质上是同一件事——把模糊的边界,提前换成一个明确的"不做"。不能。它自己也明确说了,不声称能恢复原始源码,也不克隆应用。它给的是伪代码、汇编、符号、字符串和它们之间的关系,并且标注每条结论的证据。反编译和"还原源码"之间隔着一整个优化流程,这件事不会因为加了 AI 就变简单。分两层。分析引擎本身可以在本机跑,不需要联网。但如果你用的是云端模型驱动的 Agent,那反编译结果就会被送进模型的上下文。想完全离线,需要用本地部署的模型方案。Q3:它能不能拆 iOS 应用或者系统级的闭源组件?从公开信息看,它的能力清单里没有 iOS 这一档。而且这类系统级目标往往有完整的代码签名和完整性校验体系,分析难度和保护强度都远高于普通商业软件。看到"AI 能完整逆向整个闭源系统"这类说法,建议直接当宣传语看,别当事实。不是"没办法",是"成本陡然上升"。常见的壳有对应的处理思路,但需要人的经验判断。真正麻烦的是完整代码虚拟化的场景,那基本要靠专业逆向人员深度参与,AI 目前在这场对抗里不占优势。相比做产品,风险确实低很多。我国的法律对"为学习和研究软件内含的设计思想和原理"使用软件、以及"计算机软件反向工程研究",都留了明确的空间。但要注意两点:一是样本必须来路正当;二是目标软件的用户协议里如果有禁止逆向的条款,那是合同层面的约束,法律给的例外不必然覆盖它。Q6:为什么我用它拆东西,模型有时候会莫名其妙停下来?一般是撞上了模型服务商的内容策略。这类拦截不透明也不稳定,你没法预知边界。能做的就是把问题切小、问得更具体,或者换本地模型。但请注意,绕开内容策略这件事本身就不该做——换成离线模型的目的应该是数据合规,不是规避审核。我的观察是两类人收益最大:一类是做过一些逆向、但被工具链的繁琐卡住的工程师,REA 能明显提升他们的效率;另一类是前端或全栈出身、想看懂 Electron 和 Web 应用实现的开发者,这一档的学习曲线几乎为零。完全零基础的小白,我不建议一上手就碰原生二进制,从 JavaScript 这一档起步更实际。这类项目迭代很快,能力清单和接口都在变。所以别把某个具体命令、某个客户端参数当成长期稳定的东西,隔一段时间去官方文档确认一次。本文涉及的工具名称、参数、平台支持范围都是写稿时的情况,请以官方文档的实时内容为准。本文是我(莫潇羽@无忆研习社)基于个人对 AI 逆向工程与软件开发实践的学习与整理而成的方法论总结。文中观点、案例、产品名、目录结构、代码片段均为通用化、虚构化处理,用于学习交流,不构成任何投资、经营或法律建议。文中涉及的法律条文、司法解释、判例、平台规则、监管要求等会动态变化,本文反映的是写稿时的公开情况,请务必以官方发布的最新文本、平台官方后台与当地主管部门的实时口径为准。涉及工具版本号、支持范围、价格与性能数据变动很快,上文均为示意,请以官方文档与官方定价页面的实时数据为准。涉及境外模型与服务的部分,仅作技术科普,实际使用需遵守国内网络与内容管理相关规定。涉及素材、字体、音乐、图片的商业使用时,请务必取得正版授权。技术可以打开黑盒,但打开之后怎么用,是每个人自己的选择。 我希望这篇文章帮你建立的不只是操作能力,还有一条清晰的边界感。本文由 莫潇羽@无忆研习社(www.wuyi.wiki)撰写,原「源码七号站」(