
做 JS 逆向的朋友大概率都经历过这样的场景定位到一个加密函数信心满满地把代码复制到 Node 里一运行第一行就报window is not defined。补一行再跑又报document is not defined。再补又告诉你navigator上没有userAgent。就这样一整个下午耗在跟undefined搏斗上加密逻辑一行都没来得及看。这不是你技术不行而是“补环境”这件事本身就足够劝退新手。过去主流的做法是手动开一个浏览器环境挨个补对象或者加载一份动辄几千行的通用环境脚本出了问题还得自己在报错栈里慢慢抠。效率低心智负担大而且极其容易在补完环境之后发现真正要分析的算法还没开始。这篇文章想聊的是怎么把“补环境”从手动体力活变成 AI 辅助的快速迭代过程。主角是近期社区讨论度很高的终端 AI 编码工具 OpenCode。我的判断是AI 不会替你理解加密算法但它能把“报错→搜答案→手动补→再报错”的低效循环压缩成“报错→让 AI 读→自动生成补环境→验证”这是小白从劝退到入门的关键一步。特别说明网上不少教程喜欢拿瑞幸小程序、某某点单小程序当案例。本文不会这么做。实战部分我会使用自定义 demo 演示通用原理真实小程序的分析请务必在合法授权范围内进行。下面进入正题。1. AI 逆向为什么突然火了先解决“补环境”这个磨人问题1.1 什么是补环境为什么逆向离不开它前端逆向里有一个非常常见的需求网页或小程序里的加密函数原本运行在浏览器里依赖window、document、navigator、localStorage这些浏览器对象。但我们要在 Node.js 里单独运行这段函数方便调试、分析算法、验证结果。Node.js 没有这些浏览器对象一运行就会报错。“补环境”就是在 Node.js 里模拟出这些浏览器对象让依赖浏览器环境的脚本能跑起来。听起来简单做起来却非常琐碎。手动补环境的典型循环是这样的运行脚本看到第一行报错比如navigator is not defined。去搜索navigator应该长什么样复制一段代码补上。再运行报下一个错这次可能是navigator.userAgent是undefined。继续补继续跑直到脚本不再报错。这个循环看起来有推进实际上每一步都在消耗你宝贵的分析时间。更麻烦的是有些浏览器对象存在原型链关系不是简单补一个全局变量就能糊弄过去。后面我会专门讲原型链补环境。1.2 手动补环境的痛点第一个痛点是“无底洞”。你永远不知道下一个报错在哪个角落。有时候一个加密函数依赖十几个浏览器 API手动补完要花一两个小时而且补出来的代码自己都没底不确定是不是和真实浏览器行为一致。第二个痛点是“不可复用”。每个脚本依赖的环境都不一样你在这段代码上补的window换一个脚本可能就不适用。更别提有些代码会检测环境真实性比如检查navigator.webdriver是否存在这时候简单的全局变量赋值就会露馅。第三个痛点是“知识断层”。对新手来说看到报错往往不知道应该补成什么样只能到处搜索。AI 出现之前这个学习曲线是很陡的。1.3 AI 如何改变这个流程AI 辅助补环境的思路和手动补环境完全不同。手动补是“面向报错编程”AI 辅助是“面向意图编程”。你只需要告诉 AI这段代码依赖哪些浏览器 API请生成补环境脚本。AI 会直接读代码分析依赖生成一份最小可运行的补环境文件。更关键的是AI 能处理“为什么这么补”的问题。你可以追问它为什么window要指向global为什么这里要用Object.defineProperty而不是直接赋值这种交互方式等于身边随时坐了一个有经验的逆向老手。这才是 AI 逆向真正有价值的点它不是替你颠覆逆向而是把环境搭建这种高重复、高琐碎、低认知增益的部分接管过去让你把精力集中在算法分析本身。2. OpenCode 是什么和 Codex / Cursor 有哪些区别2.1 先认识 OpenCodeOpenCode 是一个开源的、运行在终端里的 AI 编码代理AI Coding Agent。它和 Codex、Cursor 这类工具属于同一个赛道但因为交互形态和使用方式不同在开发者社区里吸引了一批忠实用户。简单理解OpenCode 就是一个命令行版本的 AI 结对程序员。你在终端里启动它它会读取你当前项目的代码结构理解你的项目规则然后根据你的自然语言指令去读写代码、执行命令、运行测试、修复报错。它最吸引人的一个特点是“Agent 感”很强。不是简单地帮你补全一行代码而是像一个真正坐在你旁边工作的工程师自己规划步骤、执行命令、观察结果、调整方案直到完成任务。常见的热搜词里和 OpenCode 同时出现的往往还有opencode 安装、opencode 使用教程、opencode skill、opencode 如何切换模型说明大家最关心的是怎么用起来、怎么配置成适合自己的形态。2.2 OpenCode 的核心能力从使用体验和官方文档来看OpenCode 的核心能力可以归纳为以下几点。第一多模型支持。OpenCode 不绑定单一模型可以接入 Anthropic、OpenAI、Google Gemini、DeepSeek 等多家大模型也支持本地模型。这意味着你可以根据任务难度切换模型简单任务用便宜模型复杂逆向分析用强模型。第二项目规则文件 AGENTS.md。你可以在项目根目录放一个AGENTS.md告诉 OpenCode 这个项目的技术栈、代码规范、特别注意事项。它启动后会自动读取相当于给 AI 设定项目上下文。第三Skills 技能机制。你可以为 OpenCode 定义自己的“技能包”。比如针对逆向补环境可以写一个 Skill让 AI 在遇到 JS 报错时自动按固定流程生成补环境代码而不是每次从头解释一遍。第四MCP 支持。OpenCode 可以接入 MCPModel Context Protocol服务器扩展它获取外部信息的能力。第五多形态客户端。除了终端 TUI还有桌面版、VSCode 插件等形态可以覆盖不同用户的操作习惯。2.3 OpenCode 与 Codex、Cursor 的定位差异对比维度OpenCodeCodex CLICursor运行形态终端 TUI / 桌面版终端 CLI桌面 IDE开源情况开源社区活跃闭源为主闭源模型支持多家模型自由切换主要绑定自家模型多家模型项目规则AGENTS.mdAGENTS.md.cursor/rulesSkills支持支持有类似机制适合场景终端党、脚本任务终端党、轻量任务日常开发、重度 IDE 用户从表格能看出OpenCode 更贴近“终端里的自动化工程师”而 Cursor 更贴近“带 AI 能力的完整 IDE”。如果你平时就习惯终端操作或者做的事情是脚本分析、接口调试、环境搭建这类轻 IDE 任务OpenCode 会更顺手。2.4 为什么 OpenCode 适合逆向场景做逆向分析有一个特点工作流长且碎。解包、找文件、看代码、补环境、跑脚本、验证签名每一步都在终端和文件系统之间切换。OpenCode 的终端形态和文件读写能力天然适合这个场景。它可以帮你浏览解包后的文件目录、定位可疑函数、分析代码依赖、生成补环境脚本、执行 Node 命令、根据报错继续迭代。整个流程不离开终端上下文也不容易丢。还有一点很关键OpenCode 是开源的配置和数据都在本地对于处理敏感代码来说比把代码贴到在线网页里更让人放心。3. 补环境与原型链两个必须先搞清楚的概念3.1 补环境的本质是“按需模拟”很多人拿到一份网上流传的“通用补环境大礼包”动辄几千行以为补环境就是要把所有浏览器对象全补一遍。这是最大的误解。补环境的本质是让正在分析的这段代码在 Node.js 里能跑起来。它只需要覆盖这段代码真正用到的 API 就够了。补多了反而容易出问题一方面代码臃肿另一方面你补的“假环境”可能和真实浏览器行为不一致导致结果偏差。正确做法是“按需补”。先运行看第一行报错再针对报错去补。或者用 AI 直接分析依赖一次性生成最小补环境。下面是一个最基础的补环境示例// 文件路径env/basic.js // 目标让一段依赖浏览器环境的代码在 Node.js 中运行 // 1. 模拟 windowNode 的 global 对象充当全局作用域 global.window global; // 2. 模拟 navigator很多加密函数会读取 UA 和平台信息 global.navigator { userAgent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.50, platform: iPhone, language: zh-CN, }; // 3. 模拟 document只补代码真正用到的部分 global.document { cookie: , createElement() { return { style: {}, setAttribute() {}, appendChild() {}, }; }, getElementById() { return null; }, }; // 4. 模拟 localStorage global.localStorage { getItem() { return null; }, setItem() {}, removeItem() {}, }; module.exports { window: global, navigator, document, localStorage };这段代码的逻辑很直接把window指向global使得业务代码里写window.navigator等价于global.navigator。navigator提供了 UA 和平台信息document只实现了createElement和getElementById两个方法。这就是“够用就好”。3.2 原型链补环境为什么不能只补全局变量再深入一层你会遇到“原型链补环境”。小程序的加密代码里经常出现类似这样的写法const img new Image(); img.src https://example.com/1.png;如果只看表面你可能觉得补一个global.Image function() {}就够了。但真实代码里可能还会做img instanceof HTMLImageElement这时如果你只是把Image补成一个普通函数instanceof检查就会失败。因为instanceof检查的不是函数名而是原型链上有没有对应的 prototype。这就是“原型链补环境”要做的事不仅要补构造函数还要补它和原型对象、实例之间的关系。看一个简单示例// 文件路径env/proto.js // 核心模拟构造函数 原型链关系 class FakeHTMLImageElement {} class FakeImage extends FakeHTMLImageElement { constructor() { super(); this.src ; this.width 0; this.height 0; this.onload null; this.onerror null; } setAttribute(key, value) { this[key] value; } } // 让全局的 Image 指向 FakeImage global.Image FakeImage; // 让 HTMLImageElement 指向同一个原型父类 global.HTMLImageElement FakeHTMLImageElement; // 验证原型链 const img new Image(); console.log(img instanceof HTMLImageElement); // true这里的关键是HTMLImageElement和Image不是各自独立的存在它们在浏览器里有明确的继承关系。补环境的时候要把这层关系一起补上业务代码里的instanceof检查才不会出错。实际逆向中原型链补环境比这个复杂得多。你可能要面对EventTarget、Node、Element、HTMLElement这一整条链。好在 AI 可以承担大部分推导工作你要做的是理解它的补法然后验证结果。3.3 补环境不是破解它是调试手段这里必须澄清一个概念。补环境本身不是“破解”也不是“绕过风控”。它只是把一个需要浏览器环境的脚本搬到 Node.js 里运行和调试是安全研究和前端开发中非常常见的手段。真正需要警惕的是补环境之后的用途如果你用补环境伪造签名、爬取商业接口、领取不属于你的权益那就越过了合规边界。本文只讨论技术原理和正当用法。4. OpenCode 安装与配置4.1 安装 OpenCodeOpenCode 支持多种安装方式官方推荐的通常是安装脚本macOS 用户可以用 HomebrewNode.js 用户也可以用 npm。以下命令以官方文档为准如果版本或命令有变化以你实际使用的版本为准。# 方式一官方安装脚本Linux / macOS curl -fsSL https://opencode.ai/install | bash # 方式二HomebrewmacOS brew install sst/tap/opencode # 方式三npm需要 Node.js 18 npm install -g opencode-ai # 安装后验证 opencode --version如果你是 Windows 用户建议优先使用 WSL2或者直接使用 OpenCode 桌面版体验更稳定。安装完成后在终端输入opencode即可启动。4.2 配置模型提供商OpenCode 本身是“模型无关”的你需要为它配置可用的模型提供商。常见做法是通过环境变量设置 API Key然后在opencode.json里指定默认模型。在项目根目录新建opencode.json{ $schema: https://opencode.ai/config.json, model: anthropic/claude-sonnet-4, provider: { deepseek: { npm: ai-sdk/deepseek, options: { apiKey: {env:DEEPSEEK_API_KEY} } } } }这是一个示例配置model指定默认模型provider里声明了一个新的模型提供商。具体的字段名称和可用配置不同版本可能有差异建议以官方文档为准。配置好之后启动 OpenCode在交互界面里输入/models可以快速切换模型也可以启动时通过命令行参数指定opencode --model anthropic/claude-sonnet-4不同版本的参数名可能不同启动后输入opencode --help查看即可。4.3 配置 Skill做一个“补环境助手”Skill 是 OpenCode 里非常实用的机制。它相当于给 AI 预置了一套“工作手册”。每次触发某个主题时AI 会按照 Skill 里的规则来执行不需要你重复解释需求。给“AI 逆向补环境”场景设计一个 Skill目录结构可以这样.opencode/ └── skills/ └── env-patcher/ └── SKILL.mdSKILL.md内容如下--- name: env-patcher description: 分析 JavaScript 报错并自动生成补环境代码适合在 Node.js 中运行依赖浏览器 API 的脚本。 --- # Env Patcher ## 职责 当用户粘贴一个 JS 报错、一段依赖浏览器环境的代码或者要求“补环境”时按以下流程执行 1. 分析代码列出所有依赖的浏览器全局对象和 API。 2. 运行代码收集第一行真实报错。 3. 根据报错逐个补齐缺失的 API而不是一次性堆砌所有浏览器对象。 4. 优先使用 Object.defineProperty 补齐只读属性。 5. 输出补环境文件路径并给出验证命令。 ## 约束 - 不要修改被分析代码的业务逻辑。 - 如果代码涉及加密算法只解释算法流程不推导私钥或密钥。 - 涉及真实商业应用的逆向时提醒用户确认授权。这样配置之后当你对 OpenCode 说“分析这个 JS 的依赖并补环境”它会自动按照这个 Skill 的流程来做产出会更稳定也更容易形成自己的逆向工作流。5. 实战用 OpenCode 辅助完成一次小程序加密分析5.1 准备材料与合法边界这个实战示例的目标是跑通一个完整流程拿到一个前端 JS 文件分析它的加密逻辑用 AI 生成补环境代码最后在 Node.js 中成功运行并验证输出。这里有一个非常重要的前提示例中的crypto.js是我自定义的 demo不来自任何真实商业小程序。如果你要分析真实小程序请先确认你拥有目标代码或者已经获得明确授权。不要用这些技术去爬取商业接口、伪造签名、领取不属于你的权益也不要传播任何针对真实应用的破解链路。5.2 一个依赖浏览器环境的“签名函数”假设我们拿到了一份前端代码里面有一个sign函数。它做了三件事把参数排序拼接、读取浏览器 UA 和平台信息、计算一个 HmacSHA256 签名。// 文件路径demo/crypto.js // 注意这是为了演示“补环境”而造的示例函数不属于任何真实小程序。 const CryptoJS require(crypto-js); function sign(params, secret) { const sorted Object.keys(params) .sort() .map((key) ${key}${params[key]}) .join(); const base sorted key secret; const ua window.navigator ? window.navigator.userAgent : ; const platform window.navigator ? window.navigator.platform : ; const payload ${base}ua${ua}platform${platform}; return { sign: CryptoJS.HmacSHA256(payload, secret).toString(), ua: ua, }; } module.exports { sign };这段代码在 Node.js 里直接运行会立即报错window is not defined。原因很清楚window是浏览器对象Node.js 里没有。5.3 把代码交给 OpenCode在项目目录启动 OpenCode给它一个完整的任务描述opencode 读取 demo/crypto.js分析它依赖了哪些浏览器 API然后生成 demo/env.js。要求只补必要的全局对象不修改 crypto.js 的业务逻辑。最后运行 node demo/run.js 验证结果。这里的核心技巧是“把需求说清楚”。你不需要自己先分析依赖AI 会读代码。你只需要告诉它目标文件是哪个、输出文件叫什么、约束是什么、怎么验证。OpenCode 会大致执行这样的过程打开demo/crypto.js扫描代码中引用到的全局对象。发现window、navigator两个浏览器对象。生成demo/env.js只补这两个对象的必要属性。创建demo/run.js作为入口。运行验证如果还有报错继续迭代。5.4 AI 生成的补环境文件AI 生成的补环境代码可能长这样// 文件路径demo/env.js // 根据 crypto.js 的依赖自动生成的最小补环境 global.window global; global.navigator { userAgent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.50, platform: iPhone, language: zh-CN, };注意它没有像很多“通用环境大礼包”那样把所有浏览器对象都补上而是只补了window、navigator和navigator的两个属性。这就是按需补环境。5.5 验证入口文件再创建一个入口文件让补环境先执行再调用签名函数// 文件路径demo/run.js require(./env); const { sign } require(./crypto); const result sign( { orderId: 10086, amount: 9.9, ts: 1750000000 }, demo-secret-key ); console.log(result);5.6 运行与迭代先安装依赖再运行cd demo npm install crypto-js node run.js如果用 AI 补的环境正确你会看到类似下面的输出{ sign: d4f8e2c4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0, ua: Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.50 }如果还缺其他环境OpenCode 会读取报错信息继续往env.js里补。整个过程的核心是你负责判断方向AI 负责执行细节。6. 运行结果与效果验证6.1 怎么判断补环境成功补环境成功有一个最直接的标志目标脚本在 Node.js 里不再因为环境缺失而报错并且输出的结果和预期一致。在上面这个 demo 里判断标准有两个node run.js能正常执行完成不报undefined相关错误。输出的sign是一个 64 位十六进制字符串格式符合 HmacSHA256 的特征。如果签名函数在真实浏览器里也有一个参考值你可以把两边的输出做一次对比。一致说明补环境成功不一致说明补的环境和真实浏览器存在差异需要检查是不是某个属性的值不对。6.2 失败时的第一排查顺序很多朋友补环境失败第一反应是继续加代码结果越补越乱。更稳妥的顺序是看第一行报错报什么错就说明缺什么。确认依赖链条比如navigator.userAgent报错可能是navigator都没补也可能是补了navigator但没补属性。确认是否为只读属性问题有些代码会给属性赋值如果环境里的属性不可写会静默失败或抛错此时要改用Object.defineProperty。确认原型链是否完整如果报instanceof相关错误说明构造函数和原型链没补对。6.3 一个值得养成的习惯先跑通再优化不要一上来就让 AI 生成一个“完美”的补环境文件。更实际的做法是先用最小补环境跑通记录输出再逐步补充缺失部分。OpenCode 的迭代模型正好适合这个节奏跑一遍看报错让它改再跑一遍。通常几轮之后脚本就能稳定运行。7. 常见问题与排查思路以下是我在补环境和 OpenCode 使用中遇到的高频问题整理成表格方便收藏查阅。问题现象可能原因排查方式解决方案OpenCode 启动失败提示命令不存在安装未成功或 PATH 未生效执行opencode --version确认重新安装或重启终端让 PATH 生效配置模型后无法对话API Key 未设置或模型名错误检查环境变量和opencode.json按官方文档重新配置使用/models查看可用模型补环境后仍然报xxx is not defined补环境文件未在入口文件之前加载检查require(./env)是否在业务代码之前调整文件加载顺序报xxx is undefined但不是 not defined对象存在但属性缺失用console.log(global.navigator)查看实际内容按需补齐属性优先使用Object.definePropertyinstanceof判断失败构造函数与原型链关系未补全复现浏览器中的继承关系补原型链如FakeImage extends FakeHTMLImageElementAI 生成的补环境过于臃肿提示词里没有限定“按需补”检查提示词是否明确写出只补必要对象在 Skill 中约束“不一次性堆砌所有浏览器对象”输出结果和浏览器不一致UA、时间戳等环境参数有差异对比两边运行时的 UA 和参数统一环境参数后重新验证微信小程序抓包不成功证书未安装或代理未配置检查代理设置和证书信任在合法调试环境中配置 Charles/Fiddler重装证书这里特别提醒一句涉及微信小程序抓包时请只在合法调试环境下进行例如自己开发的小程序、已授权测试的应用程序。不要对他人服务进行未授权探测。8. 最佳实践与工程建议8.1 合规边界一定要先想清楚这部分我放在最佳实践第一位因为它比任何技术技巧都重要。AI 补环境降低了逆向的技术门槛也意味着滥用门槛降低了。在开始任何分析之前先问自己三个问题这段代码是不是我自己的如果不是我是否获得了授权我的分析结果会不会被用于爬取数据、伪造请求、薅羊毛等违规行为只要有一个问题答案是否定的就不要继续。做技术分享时也应该像本文一样用 demo 或公开示例代替真实商业应用。8.2 把提示词模板沉淀成 Skill第一次用 OpenCode 补环境你可能需要写一大段提示词。第二次、第三次就可以把这些提示词沉淀成 Skill。我在第 4 章写的env-patcherSkill 就是一个模板。你可以根据自己的习惯继续补充比如默认输出文件命名、默认的验证命令、加密货币时保留哪些上下文、不要修改哪些文件。Skill 越贴合你的工作流AI 的产出越稳定。8.3 模型选择复杂任务用强模型简单任务用便宜模型OpenCode 支持多模型这个特性对成本控制很有帮助。简单任务比如“分析这个函数的依赖”“把这段代码转成可运行版本”可以用便宜模型速度也快。复杂任务比如“解释一段混淆代码的算法流程”“分析一个反调试逻辑”建议切换到推理能力更强的模型。切换模型不是“越贵越好”而是按任务复杂度匹配。8.4 保留人工判断不要全自动AI 补环境很快但 AI 也可能会“一本正经地胡说”。比如它可能补了一个结构完整但行为错误的navigator导致签名结果和浏览器不一致。所以流程上一定要保留验证环节。每次 AI 生成补环境之后都要跑一次真实的验证脚本对比输出。你可以信任 AI 的执行效率但不要盲目信任它的每一步判断。8.5 环境文件要独立业务代码要只读工程上补环境文件应该独立成一个模块比如env.js并且在入口文件最前面加载。业务代码保持只读不要为了让 AI 更快理解而改动业务代码。这样做的原因有两个一是保持被分析代码和原始代码一致避免引入偏差二是当业务代码更新时你可以快速比对判断补环境是否需要调整。8.6 日志和快照在补环境脚本里加一些关键位置的日志会极大提升排查效率。比如console.log([env] navigator.userAgent , navigator.userAgent);当你发现签名结果和浏览器不一致时这些日志能帮你快速定位是哪个环境变量出了问题。更进阶的做法是把环境快照保存成 JSON 文件方便前后对比。9. 总结与后续学习方向这篇文章的核心判断是OpenCode 这类 AI 编码工具不会替代你去理解加密算法但它把“补环境”这个最磨人、最重复、最劝退新手的环节变成了可以快速迭代的自动化过程。对小白来说这是从“看不懂报错”到“能跑通脚本”的关键转折点。我们完成了三件事理清了补环境和原型链补环境的原理完成了 OpenCode 的安装、模型配置和 Skill 配置并且用一个自定义 demo 跑通了“分析依赖 → AI 生成补环境 → 运行验证”的完整链路。这套流程完全可以迁移到你自己的合法分析任务中。如果你打算继续深入有几个方向值得关注AST 与代码混淆很多小程序代码经过混淆读懂混淆逻辑是下一步的必修课。算法逆向基础哈希、HMAC、非对称加密的特征识别和验证方法。微信小程序安全机制包括包结构、代码保护、平台规则但始终要在合规框架内研究。Agent 工作流把 OpenCode 的 Skill、AGENTS.md、MCP 组合起来形成更完整的自动化分析流水线。最后提醒一句AI 工具会越来越强但逆向的核心竞争力永远是“对代码的理解”和“对边界的敬畏”。建议把本文的 demo 项目跑通一遍收藏备用然后在自己拥有或已获授权的小程序上实践一次。你会发现有了 AI 辅助补环境真的不用再手动硬啃了。