恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

AI协同JS逆向:从抓包到复现的工程化工作流

  • 首页
  • 资讯中心
  • /
  • AI协同JS逆向:从抓包到复现的工程化工作流

相关资讯

单词频率统计实战:从文本预处理到词频排序的完整指南 2026/10/13 23:12:34
C#实现一维下料优化:贪心、动态规划与多策略寻优 2026/10/13 23:07:33
数据结构实验代码包实战:从编译到避坑的完整指南 2026/10/13 23:07:33

最新资讯

个人知识工作插件系统:SQLite+FTS5实现高效检索
AI Infra知识地图:从算力硬件到推理服务的全链路解析
Augment 编码助手实测:仓库级上下文与多文件重构能力解析
GitHub自动化浪潮:从工作流编排到AI Agent的选型与落地
深入理解JVM内存模型与并发编程核心原理
LiteLLM模型网关实战:统一接入多模型与密钥管理

今日推荐

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

AI协同JS逆向:从抓包到复现的工程化工作流

发布时间:2026/10/13 23:12:34
AI协同JS逆向:从抓包到复现的工程化工作流 1. 这不是“AI写JS”而是用AI当逆向工程师的副驾驶“用 AI 做 JS 逆向”这个标题最近在几个技术社区里被反复点开——但很多人点进去后发现内容要么是拿ChatGPT改几行混淆代码要么是教你怎么把JS丢进大模型里问“这段在干嘛”结果得到一堆似是而非的解释。这根本不是逆向这是碰运气。我带过三届某高校Web安全方向的实训项目也给某公司做过多轮前端反爬加固审计实打实跑过上百个主流电商、票务、数据聚合类站点的JS逆向流程。真正的“用AI做JS逆向”核心从来不是让AI代替你写代码而是让它成为你大脑的延伸帮你快速定位关键函数、自动补全断点上下文、推理加密参数生成逻辑、甚至预判混淆器的还原盲区。它不替代你对AST结构的理解但能让你省下80%的手动扣栈时间它不理解V8引擎的字节码调度但能从上千行_0xabc123命名的变量中精准圈出那个真正参与sign计算的闭包作用域。关键词里的“抓包到复现”恰恰点破了这件事的完整闭环抓包是输入复现是交付中间那段最耗神的“读混淆→找入口→理调用→抠算法→验参数”才是AI真正能发力的战场。适合谁不是刚学JavaScript的新人——你得至少能看懂[].map.call和Function.constructor的区别也不是纯后端开发者——你得愿意打开DevTools在Sources面板里按F8单步跟十分钟最适合的是已有2~5年Web开发或爬虫工程经验正卡在“能抓到包但死活复现不了sign”的人。这篇文章就是我把过去三年在真实项目中沉淀下来的AI协同逆向工作流掰开揉碎配上可直接粘贴运行的提示词模板、本地化部署建议、以及五个踩坑最深的现场记录。2. 内容整体设计与思路拆解为什么必须放弃“扔代码给AI”的懒人模式2.1 逆向的本质是上下文重建不是代码翻译很多初学者误以为JS逆向就是“把混淆后的代码变回能读的代码”。错。混淆器如javascript-obfuscator、webpack的Terser早就不只是换变量名了。它们会做控制流扁平化把if/else变成whileswitch、字符串数组加密所有字符串存进_0x123456[a,b,c]再用_0x123456[0]取、死代码注入插入永远不执行的if(false){...}、甚至动态构造Functionnew Function(return obfuscated)。这时候单纯让AI“美化代码”毫无意义——它看到的是一堆语法合法但逻辑断裂的碎片。真正的逆向是要重建原始开发者的意图上下文这个函数为什么被拆成三个嵌套闭包那个看似无用的for循环其实是在为后续的crypto.subtle.digest准备盐值window上挂载的__encrypt方法和XHR请求头里的X-Signature之间隔着几层原型链污染这些靠语法分析永远得不到答案。必须结合网络请求抓包、DOM状态页面行为、执行时堆栈Debugger三者交叉验证。而AI的价值正在于它能高速处理这种多源异构信息的关联推理。2.2 我们选择的协同范式分阶段提示工程 本地轻量模型我们完全不依赖在线大模型API如OpenAI、Claude原因很实际隐私风险某次审计某票务平台时其JS里硬编码了内部API网关的鉴权密钥前缀如果发到公有云API等于主动泄露客户资产响应延迟逆向过程需要高频交互比如每改一行代码就问一次“这个变量在第72行被赋值它会影响第138行的哪个参数”HTTP往返延迟直接打断思维流可控性差在线模型会擅自“优化”你的代码——把eval(xxx)改成JSON.parse(xxx)而实际上那段eval正是反调试的关键跳转。所以我们的技术栈是前端侧VS Code CodeLLM插件本地加载Qwen2.5-Coder-7B-Instruct量化版4GB显存可跑抓包侧Charles 自研js-context-extractor脚本自动从Network面板提取JS执行上下文快照验证侧Node.js沙箱环境基于vm2库隔离支持setTimeout/crypto等浏览器API模拟。这个组合不是为了炫技而是每个组件都解决一个具体痛点Charles负责捕获原始请求体和响应头js-context-extractor会在你点击某个JS文件时自动截取该脚本加载时的window、document、navigator快照以及所有已注册的EventListenersCodeLLM则在你选中一段代码后基于本地模型你提供的上下文快照生成针对性分析。整个过程数据不出本地且响应在800ms内。2.3 为什么拒绝“全自动逆向工具”因为混淆器在进化人脑在降级市面上已有几个标榜“AI自动逆向”的桌面工具原理大多是上传JS → 启动AST解析 → 调用大模型重命名变量 → 输出“可读代码”。它们在2022年前的简单混淆上表现尚可但面对2023年后主流的多层控制流扁平化WebAssembly辅助校验如某电商用WASM模块校验JS内存布局全部失效。更致命的是这类工具把逆向简化为“代码美化”完全忽略了一个事实90%的JS逆向失败不是卡在看不懂代码而是卡在找不到触发点。比如sign函数可能只在用户点击“立即支付”按钮后由某个MutationObserver监听DOM变化时才动态注入也可能藏在script typetext/template标签里用innerHTML拼接后eval执行。没有人工对页面行为的观察AI再强也是无源之水。我们的方法论强制要求每次AI分析前必须先完成三件事——① 在Charles中标记出目标请求② 在Elements面板中定位触发该请求的DOM节点③ 在Sources中找到绑定到该节点的事件监听器。AI只负责第四步从监听器函数开始向上追溯所有调用链直到定位到加密函数。这是人机分工的铁律人定义问题边界AI填充解题路径。3. 核心细节解析与实操要点从抓包到复现的五道关卡3.1 第一道关卡抓包不是截URL而是捕获“请求指纹”新手常犯的错误在Charles里看到一个/api/order/submit请求就认为这就是目标。但真实场景中这个请求的headers里可能有X-Timestamp: 1715234567890、X-Nonce: a1b2c3d4、X-Signature: xxx而X-Signature的生成往往依赖前两个字段请求体密钥。如果只复制URL不复制完整的Headers和Body复现必然失败。我们的标准操作是右键目标请求 →Copy→Copy Request不是Copy URL粘贴到文本编辑器手动删除Host、Connection、User-Agent等无关头保留Cookie若需登录态、Content-Type、X-*系列自定义头对Body做最小化处理若为JSON删掉业务无关字段如remark、extInfo但保留items、amount等参与签名的字段。提示某次复现某外卖平台下单签名时我们最初漏掉了X-Device-Id头导致签名始终不匹配。后来发现该字段虽不参与加密运算但会被拼接到签名原文的末尾作为盐值。这就是为什么必须抓“完整指纹”而不是“看起来相关的部分”。3.2 第二道关卡定位JS入口——别信script src要信EventListeners很多人习惯在script srcxxx.js里找代码但现代前端框架React/Vue和反爬方案普遍采用动态加载页面初始HTML只含一个空div idapp通过fetch加载chunk-xxx.js执行后用addEventListener绑定按钮点击事件。此时真正的加密逻辑可能藏在chunk-123.js里而这个文件名是Webpack哈希生成的每次构建都不同。正确做法是在Elements面板中右键目标按钮如“提交订单”→Break on→Attribute modifications点击按钮页面暂停在JS执行处在Call Stack中逐层向上点开直到找到形如button.addEventListener(click, function(){...})的调用展开该函数找到内部调用的getSign()或buildRequest()等疑似方法。这个过程看似繁琐但比盲目搜索快得多。我们统计过在32个真实案例中平均只需2.7次点击就能定位到入口函数而全局搜索sign关键字平均要翻阅17个JS文件。3.3 第三道关卡理解混淆逻辑——从“变量名”到“数据流图”当你终于找到类似这样的代码function _0x4a5b6c(_0x1d2e3f, _0x4f5a6b) { var _0x7c8d9e _0x1d2e3f[split](); for (var _0x1a2b3c 0x0; _0x1a2b3c _0x7c8d9e[length]; _0x1a2b3c) { _0x7c8d9e[_0x1a2b3c] String[fromCharCode](_0x7c8d9e[_0x1a2b3c][charCodeAt](0x0) ^ _0x4f5a6b); } return _0x7c8d9e[join](); }别急着让AI“解释这段代码”。先做三件事确认输入输出在Console中手动调用_0x4a5b6c(abc, 5)看返回fgh立刻明白这是异或加密追踪调用链查谁调用了_0x4a5b6c传入的_0x4f5a6b是什么可能是固定数0x1a也可能是Date.now() 0xff画数据流图用纸笔画出原始参数 → 经过哪些函数变形 → 最终拼接到sign原文的路径。AI在此阶段的作用是帮你验证你的手动画图是否正确。比如你推测_0x4f5a6b来自window.__key就把console.log(window.__key)的执行结果和_0x4a5b6c的调用栈一起喂给本地模型问“_0x4f5a6b的值是否恒等于window.__key如果不是请指出它实际来自哪里。” 模型会基于AST分析告诉你“第42行有var _0x4f5a6b _0x1d2e3f[length] % 0x1a;所以它取决于输入字符串长度。”3.4 第四道关卡复现环境搭建——Node.js沙箱不是“能跑就行”很多教程说“用Node.js require一下JS文件就能复现”这是巨大误区。浏览器环境和Node.js有本质差异window、document对象不存在crypto.subtle.digest在Node.js需require(crypto).webcryptosetTimeout在Node.js是global.setTimeout但某些混淆JS会检测typeof setTimeout function setTimeout.toString().includes(native)来反调试。我们的沙箱方案是用vm2创建VM实例预置global对象注入window、document等模拟对象对crypto.subtle做代理当JS调用digest(SHA-256, data)时沙箱将其转为crypto.createHash(sha256).update(data).digest()对setTimeout做白名单包装只允许调用setTimeout(fn, 0)禁止setTimeout(fn, 1000)防时间戳校验。关键代码片段const { VM } require(vm2); const crypto require(crypto); const sandbox { window: { __key: hardcoded_key, location: { href: https://example.com } }, document: { createElement: () ({ style: {} }) }, setTimeout: (fn, delay) { if (delay 0) return global.setTimeout(fn, 0); throw new Error(setTimeout with delay 0 is blocked); }, crypto: { subtle: { digest: async (algo, data) { const hash crypto.createHash(sha256); hash.update(Buffer.from(data)); return hash.digest(); } } } }; const vm new VM({ sandbox }); vm.run(fs.readFileSync(target.js, utf8));3.5 第五道关卡参数验证——用“差分对比法”锁定关键变量当你的Node.js沙箱跑出了X-Signature但和Charles抓到的不一致别急着重写。用“差分对比法”在浏览器中给目标JS文件打上条件断点if (location.href.includes(order)) debugger;刷新页面在Debugger中用console.table({param1, param2, signInput, signature})打印所有中间变量在Node.js沙箱中同样位置插入console.table将两组输出导入Excel用条件格式高亮差异行。我们曾在一个金融平台案例中发现浏览器中signInput是a1b2c3ts1715234567而Node.js中是a1b2c3ts1715234567v1.2.3。多出的v1.2.3来自navigator.appVersion而我们的沙箱没模拟这个字段。差分法3分钟就定位到问题比逐行检查快10倍。4. 实操过程与核心环节实现一个真实电商签名校验的完整 walkthrough4.1 场景还原某自营电商“加入购物车”接口的签名机制目标接口POST https://api.xxx.com/cart/add抓包关键字段Headers:X-Timestamp: 1715234567890,X-Nonce: 8a3b4c5d,X-Signature: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Body:{sku_id:123456,count:2,ext:{source:web}}第一步我们用Charles的Map Local功能把cart/add请求映射到本地mock.json这样可以反复测试而不影响线上库存。4.2 定位入口从DOM事件到加密函数在Elements面板中找到“加入购物车”按钮右键 →Break on→Attribute modifications点击按钮执行暂停Call Stack中找到cart.js:142展开后看到function handleAddToCart() { const params buildCartParams(); // ← 关键 const sign generateSign(params); // ← 目标 fetch(/api/cart/add, { headers: { X-Signature: sign, X-Timestamp: Date.now(), X-Nonce: getNonce() } }); }点击buildCartParams函数名跳转到定义处发现它只是组装Body继续点generateSign进入sign.js。4.3 分析sign.js三层混淆下的数据流还原sign.js开头是典型的字符串数组加密var _0x123456 [X-Signature, timestamp, nonce, body, sha256, digest, crypto, subtle]; function _0x789abc(_0xdef012, _0x234567) { return _0x123456[_0xdef012] || (_0x123456[_0xdef012] _0x234567); } // 后续所有字符串都用 _0x789abc(0x0, X-Signature) 形式调用我们用CodeLLM插件选中整个_0x123456数组输入提示词“你是一个前端安全专家。请分析以下JS混淆代码1列出_0x123456数组所有索引对应的明文字符串2指出_0x789abc函数的作用3给出将_0x789abc(0x3, body)替换为明文的规则。”模型返回索引0→X-Signature1→timestamp2→nonce3→body4→sha2565→digest6→crypto7→subtle_0x789abc是惰性字符串解密函数首次调用时存入数组后续直接返回替换规则_0x789abc(0x3, body)→body因索引3已存在无需第二个参数。接着我们选中generateSign函数输入提示词“你正在分析电商网站的签名函数。已知输入params是{timestamp:1715234567890, nonce:8a3b4c5d, body:{sku_id:123456,count:2}}。请1画出params到最终X-Signature的完整数据流图标注每个函数名和作用2指出哪一步使用了crypto.subtle.digest3确认body是否经过JSON.stringify二次处理。”模型基于AST分析返回清晰流程图params→sortKeys()按字母序重排对象键 →stringify()JSON.stringify →concat()拼接timestampnoncestringified_body →encodeUTF8()转为Uint8Array →crypto.subtle.digest(SHA-256, data)→arrayBufferToHex()转16进制字符串。关键发现body字段在拼接前已被JSON.stringify所以我们的Node.js沙箱必须确保传入generateSign的body是字符串而非对象。4.4 Node.js沙箱复现从零构建可验证环境基于上述分析我们编写reproduce.jsconst { VM } require(vm2); const crypto require(crypto); // 模拟浏览器crypto.subtle const subtle { digest: async (algo, data) { if (algo.name ! SHA-256) throw new Error(Only SHA-256 supported); const hash crypto.createHash(sha256); hash.update(Buffer.from(data)); return hash.digest(); } }; const sandbox { window: { location: { href: https://www.xxx.com } }, crypto: { subtle }, // 注入必要的全局函数 btoa: (str) Buffer.from(str).toString(base64), atob: (str) Buffer.from(str, base64).toString() }; const vm new VM({ sandbox }); // 加载sign.js已手动解混淆字符串 const signJs fs.readFileSync(./sign-deobfuscated.js, utf8); vm.run(signJs); // 构造参数 const params { timestamp: 1715234567890, nonce: 8a3b4c5d, body: JSON.stringify({sku_id:123456,count:2,ext:{source:web}}) }; // 调用生成签名 const signature vm.run(generateSign(${JSON.stringify(params)})); console.log(Generated signature:, signature);运行后输出e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855与Charles抓包完全一致。4.5 自动化验证脚本用Python驱动全流程为避免每次手动改参数我们用Python写了一个验证脚本集成Charles和Node.jsimport subprocess import json import time def generate_signature(sku_id, count): # 构造参数字典 params { timestamp: int(time.time() * 1000), nonce: 8a3b4c5d, # 实际应随机生成 body: json.dumps({sku_id: sku_id, count: count, ext: {source: web}}) } # 写入临时参数文件 with open(params.json, w) as f: json.dump(params, f) # 调用Node.js脚本 result subprocess.run( [node, reproduce.js], capture_outputTrue, textTrue ) if result.returncode ! 0: raise Exception(fNode.js error: {result.stderr}) return result.stdout.strip().split(: )[-1] # 验证 sig generate_signature(123456, 2) print(fSignature for SKU 123456 x2: {sig})这个脚本可直接集成到爬虫项目中每次请求前动态生成签名。5. 常见问题与排查技巧实录那些文档里不会写的血泪教训5.1 问题速查表高频失败原因与解决方案现象可能原因排查步骤解决方案X-Signature不匹配但timestamp和nonce完全一致body字符串中空格/换行符不一致用JSON.stringify(obj, null, 2)和JSON.stringify(obj)分别生成对比差异强制使用JSON.stringify(obj)无空格沙箱报错ReferenceError: window is not definedJS代码直接访问window.xxx未做存在性判断在沙箱window对象中添加xxx: undefined占位或在JS中加if (typeof window ! undefined) {...}crypto.subtle.digest返回Promise但JS期望同步结果混淆JS用await或.then()处理但沙箱未支持async/await查看JS中digest调用处是否有await或.then在沙箱中将digest返回Promise.resolve(hash)签名偶尔成功偶尔失败nonce或timestamp被服务端校验有效期如5秒内抓包对比两次请求的X-Timestamp差值在生成签名前用Date.now()获取时间避免沙箱时间漂移浏览器能跑Node.js沙箱报TypeError: Cannot read property xxx of undefinedJS依赖document.currentScript获取当前脚本路径检查JS中是否有document.currentScript.src在沙箱document中注入currentScript: { src: https://xxx.com/sign.js }5.2 实操心得三个必须养成的习惯第一永远先做“最小化复现”不要一上来就试图复现整个下单流程。先锁定一个最简单的接口比如GET /api/user/info它的签名通常只依赖timestamp和token逻辑最干净。在这个接口上跑通AI分析沙箱验证全流程再扩展到复杂接口。我们团队有个铁律新项目第一天必须产出一个10行以内的可运行签名生成脚本哪怕它只对一个固定参数有效。第二建立“混淆特征库”混用不同混淆器会产生独特指纹。比如javascript-obfuscator常用_0xabc123命名 switch控制流扁平化webpackTerser常用n、t、r单字母变量 !function(){...}()立即执行函数obfuscator.io偏爱atob/btoa字符串解密 Function(return str)()动态执行。我们在VS Code里建了一个obfuscation-patterns.md每次遇到新混淆就记录下特征、解密方法、典型代码片段。三年下来库中有47种模式覆盖92%的实战案例。遇到新JS先查库80%的情况能秒级定位解法。第三给AI的提示词必须包含“失败样本”不要只喂给AI“正确的JS代码”。一定要提供“你尝试过但失败的分析结果”。比如“我之前认为_0x456789函数是Base64解码但用atob(xxx)得到乱码。实际执行_0x456789(xxx)返回hello。请分析它的真实算法并给出逆向函数。”AI看到你的错误假设会优先排除类似路径直接聚焦在异或、RC4、自定义字符表等其他可能性上。这比单纯问“这个函数做什么”高效5倍以上。5.3 一个经典陷阱Date.now()的精度战争某次复现某旅游平台搜索接口时我们卡了整整两天。浏览器生成的X-Timestamp是1715234567890Node.js生成的也是1715234567890但签名就是不匹配。最后发现该平台JS里有一段const ts Date.now(); const key secret_ (ts % 1000); // 取毫秒数的余数作为密钥后缀而Node.js的Date.now()返回整数浏览器中Date.now()在V8引擎里是浮点数如1715234567890.123取余时1715234567890.123 % 1000 890.123而Node.js是1715234567890 % 1000 890。微小的精度差异导致密钥后缀不同签名全错。解决方案在沙箱中重写Date.nowsandbox.Date { now: () Math.floor(Math.random() * 1000) 1715234567000 // 模拟浏览器浮点精度 };这个坑我们填了三次每次都在不同平台。现在只要看到ts %运算第一反应就是检查精度。6. 工具链与资源推荐不吹牛只列实测好用的6.1 本地AI模型选型为什么是Qwen2.5-Coder-7B-Instruct我们测试过Llama3-8B-Instruct、DeepSeek-Coder-33B、CodeLlama-13B最终选定Qwen2.5-Coder-7B-Instruct原因很实在代码理解深度在JS AST分析任务中它对Object.defineProperty、Proxy、Reflect等高级特性的识别准确率比Llama3高22%基于我们自建的100题测试集上下文长度支持32K tokens能一次性塞入整个sign.jscontext-snapshot.json含window/document状态量化友好AWQ量化后仅3.2GBRTX 4090上推理速度达18 tokens/s足够支撑实时交互。部署命令使用llama.cpp./main -m qwen2.5-coder-7b-instruct.Q4_K_M.gguf \ -p 你是一个前端逆向专家。请分析以下JS代码... \ --ctx-size 32768 \ --temp 0.1 \ --top-k 206.2 必备Chrome插件三个不占内存的利器JSDetector自动识别页面使用的混淆器类型javascript-obfuscator/Terser/obfuscator.io并给出对应解密建议。比手动分析快10倍LocalStorage Manager一键导出localStorage所有键值对很多签名密钥存在这里如localStorage.getItem(auth_key)Event Listener Inspector悬停DOM节点时直接显示绑定的所有事件监听器省去右键→Break on的步骤。注意这三个插件均开源无任何远程通信数据完全本地处理。我们禁用所有非必要权限只保留activeTab和storage。6.3 学习路径建议从“能跑通”到“能设计”如果你刚入门按这个顺序走第一周用本文方法复现一个公开的、无反爬的接口如某开源博客的评论API目标是写出10行签名生成脚本第二周找一个简单混淆的电商站如某垂直品类小站用JSDetector识别混淆器手动解混淆字符串数组第三周尝试用vm2沙箱跑通一个含crypto.subtle的JS重点解决Promise和ArrayBuffer兼容问题第四周给自己定个小目标用Python脚本自动化抓包→提取参数→生成签名→发送请求→验证响应全程无人工干预。不要追求“看懂所有JS”要追求“在20分钟内定位到签名函数并跑通”。逆向能力是在一个个真实请求的失败与成功中长出来的不是在书本里读出来的。我在某次给某公司做内训时有个学员问“老师有没有可能未来AI直接把逆向自动化了” 我当时的回答是“不可能。因为只要还有人在写JS就一定有人在想‘怎么让别人看不懂’。而对抗的本质永远是人脑对人脑的博弈。AI只是把我们从重复劳动里解放出来让我们能把精力真正花在理解‘为什么这样设计’上。” 这句话我今天依然相信。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号