JS逆向不用头秃:用大模型自动分析混淆代码完整流程

📅 发布时间:2026/8/28 17:17:30
JS逆向不用头秃:用大模型自动分析混淆代码完整流程 做了五六年前端逆向与协议分析最常被问的问题就是这段混淆JS怎么解控制流拆得七零八落、字符串全是十六进制拼接、变量名全是无意义的乱码、还插了一堆反调试死代码新人看了直接懵老手也要抠上大半天。传统的JS逆向本质上是「人工肉眼分析 动态调试验证」的体力劳动格式化、找入口、打断点、单步跟、抠字符串、还原逻辑大量时间都花在机械性的清理和梳理上。遇到强混淆的代码分析核心逻辑的时间甚至不到20%80%的精力都消耗在和混淆器的对抗上。而随着代码大模型的成熟这套工作模式完全可以重构。不是说直接把整段混淆代码扔给大模型就能出结果——那样大概率会得到一段看起来对但功能不对的“幻觉代码”。真正工程化的方案是「预处理工程化 大模型语义还原 动态校验闭环」把机械性的清理、梳理、还原工作交给AI人只做核心决策、边界约束和结果校验效率提升数倍的同时保证结果的准确性。本文就完整拆解这套自动化分析流程从预处理、分块、语义还原到动态校验每一步都附带实现逻辑和实战脚本看完就能落地属于自己的AI辅助逆向工具链。混淆代码样本工程化预处理功能分块拆解逐块语义还原动态校验闭环可读逻辑输出格式化标准化对抗代码剥离常量字符串还原死代码初步过滤核心入口锚定功能模块划分依赖关系标注大模型逐块还原锚点约束防跑偏变量语义重命名多组用例输入输出结果对比差异块重还原一、先讲清楚传统逆向的痛点与AI的定位1.1 传统JS逆向的核心痛点混淆手段迭代快特征匹配失效早期的混淆简单写个AST遍历脚本就能批量还原变量名、字符串。现在的混淆器都是生成式的每次混淆结果都不一样特征匹配脚本用几次就失效了。机械性工作占比高效率极低控制流平坦化、死代码插入、字符串拆分这些混淆手段本身没有技术难度但就是费时间。几千行的混淆代码真正核心的逻辑可能就几百行大部分时间都在剔垃圾、理结构。经验依赖强新人上手慢同样一段混淆代码老手可能一小时定位核心逻辑新人可能三天都找不到入口。大量的技巧、经验、坑点都靠人工积累没法批量复制。强对抗场景下人工分析成本极高遇到虚拟机保护、代码虚拟化、环境检测这类强混淆人工分析的成本会指数级上升一个核心算法抠一周都是常事。1.2 AI的定位辅助工具不是替代很多人觉得AI逆向就是“扔代码进去出结果”这是最大的误区。AI擅长的是语义理解、结构梳理、代码翻译、规律总结AI不擅长的是精确的逻辑还原、边界条件处理、对抗性识别正确的定位是人做策略和决策AI做执行和体力活。人负责找入口、定边界、做校验AI负责清理死代码、还原控制流、重命名变量、补充注释。把人从80%的机械劳动里解放出来专注核心的20%。二、第一步工程化预处理先把代码“洗干净”直接把混淆代码扔给大模型效果最差。就像你要翻译一篇乱码的文章得先把污渍擦掉、把字符认全再翻译。预处理的目标就是把混淆代码里的噪声尽量去掉还原成语法正确、结构清晰的基础代码大幅提升后续AI还原的准确率。2.1 格式化与语法标准化第一步永远是格式化。混淆代码一般都是压缩成一行或者乱缩进的先统一格式化变成正常的缩进结构。推荐用js-beautify比编辑器自带的格式化更强大能处理各种变形语法。constbeautifyrequire(js-beautify).js;constfsrequire(fs);letcodefs.readFileSync(obfuscated.js,utf-8);letformattedbeautify(code,{indent_size:2,space_in_empty_paren:true,wrap_line_length:120});fs.writeFileSync(formatted.js,formatted);2.2 对抗代码剥离混淆代码里通常会有反调试、反格式化、环境检测的代码这些代码不影响核心逻辑但会干扰分析和调试。常见的对抗特征debugger语句无限循环检测控制台打开死循环或者报错检测代码缩进变化执行假逻辑检测开发者工具跳转错误分支处理方法通过特征匹配AST识别找到这些代码块直接注释或者替换掉。比如最常见的无限debugger// 识别并替换所有debugger语句codecode.replace(/debugger;/g,/* debugger removed */);复杂的对抗逻辑可以用AST遍历识别特定模式批量处理。2.3 常量字符串还原这是最常见的混淆手段把明文字符串拆成十六进制、Unicode编码或者放在数组里通过索引取值。比如// 混淆前leturl/api/sign;// 混淆后leta[\x2f\x61\x70\x69\x2f\x73\x69\x67\x6e];leturla[0];还原方法简单的十六进制、Unicode转义直接正则替换还原数组取值类的通过AST遍历把常量数组的取值直接替换成字面量加密的字符串先找到解密函数批量解密替换还原之后大模型才能看懂代码里的字符串含义准确理解逻辑。2.4 死代码初步过滤混淆器会插入大量永远执行不到的死代码、只赋值不使用的变量、无效的表达式用来干扰阅读。初步过滤可以用简单的数据流分析识别从未使用的变量识别条件永远为真/假的分支识别没有副作用的表达式这一步不用追求100%干净去掉大部分明显的死代码就行剩下的交给大模型处理。三、第二步功能分块拆解化整为零逐个击破预处理完的代码还是有几千行直接喂给大模型要么上下文不够要么语义漂移效果极差。正确的做法是分而治之把大段代码按功能拆成小块逐块还原。3.1 先锚定核心入口不要从头开始读先找核心逻辑的入口。逆向的核心目标一般是签名、加密、验证这些直接搜特征关键词定位。常用锚点网络请求fetch、XMLHttpRequest、send加密算法CryptoJS、MD5、SHA、AESCanvas指纹getContext、toDataURL关键参数sign、token、password、key找到核心入口点之后向上回溯调用链就能梳理出完整的逻辑链路不用在无关代码里浪费时间。3.2 按功能模块切块锚定核心之后把代码按功能拆成独立的块每块负责一个功能初始化模块环境检测、参数初始化工具函数模块加密、编码、字符串处理核心逻辑模块签名生成、算法实现请求模块接口调用、参数拼接验证模块结果校验、反爬验证切块原则每块控制在100~300行保证大模型的上下文能完整覆盖每个块尽量独立减少跨块依赖标注清楚每个块的输入、输出、依赖的外部函数3.3 依赖关系标注切块不是随便切要标注清楚块之间的依赖关系。比如B块依赖A块的函数就要先还原A块再还原B块。可以简单梳理依赖顺序从底层工具函数开始逐层向上还原还原好的函数可以直接作为下一块的上下文。四、第三步大模型语义还原核心步骤的正确姿势这是最核心的一步但也是最容易踩坑的一步。很多人直接扔代码说“帮我还原”结果出来的代码看起来很漂亮功能完全不对。正确的还原必须有明确的约束和校验。4.1 还原提示词的正确写法提示词是决定还原质量的关键。核心原则是明确目标、划定边界、强制约束、指定格式。错误的写法帮我把这段代码还原成可读的。正确的写法你是一名资深JavaScript逆向工程师。请分析下面的混淆代码还原成可读性强的等价代码。约束规则功能完全等价还原后的代码和原代码输入输出必须完全一致不能修改任何逻辑保留核心API所有底层浏览器API、加密函数、网络调用必须保留不能修改语义化重命名所有无意义的变量名、函数名根据功能重命名成有意义的英文名称结构还原把平坦化的控制流还原成正常的顺序、分支、循环结构剔除死代码删除所有不影响逻辑的死代码、无效变量、冗余表达式补充中文注释关键逻辑、函数功能、参数含义都要加注释只输出完整的还原代码不要任何解释、说明、markdown标记代码{code}4.2 逐块还原上下文接力从最底层的工具函数开始逐块向上还原。还原第一层工具函数验证正确还原第二层的时候把第一层还原好的函数作为上下文一起喂进去逐层向上直到核心逻辑这样每一步的上下文都足够精准还原准确率远高于整段处理。4.3 不同混淆类型的针对性策略变量名混淆重点是语义化重命名根据函数功能推测变量含义控制流平坦化重点是梳理状态变量还原成标准的分支循环结构字符串加密结合上下文和功能还原字符串的实际含义死代码插入识别并剔除不影响逻辑的冗余代码虚拟机保护先还原指令集和调度逻辑再还原具体操作五、第四步动态校验闭环保证结果100%准确AI还原的代码哪怕看起来再对也不能直接信。语义漂移是大模型的固有问题特别是复杂的位运算、加密逻辑很容易细节出错。必须通过动态校验形成闭环。5.1 输入输出对比法最核心的校验方法同样的输入参数分别运行原混淆代码和还原后的代码对比输出结果是否完全一致。实现脚本示例constvmrequire(vm);constfsrequire(fs);// 加载原代码和还原代码constoriginalCodefs.readFileSync(obfuscated.js,utf-8);constrestoredCodefs.readFileSync(restored.js,utf-8);// 测试用例consttestCases[{input:test123,key:abc},{input:,key:},{input:1234567890,key:xyz123},{input:中文测试,key:密钥}];functionrunCode(code,input,key){constsandbox{result:null,input,key};vm.runInNewContext(coderesult sign(input, key);,sandbox);returnsandbox.result;}// 对比测试console.log(开始校验...);letallPasstrue;testCases.forEach((tc,i){constr1runCode(originalCode,tc.input,tc.key);constr2runCode(restoredCode,tc.input,tc.key);if(r1r2){console.log(用例${i1}: 通过);}else{console.log(用例${i1}: 失败);console.log(原输出:,r1);console.log(还原输出:,r2);allPassfalse;}});console.log(allPass?全部校验通过:存在差异需重新还原);5.2 多维度覆盖测试用例要覆盖多个维度正常输入空输入超长输入特殊字符、中文边界值覆盖的场景越多校验越可靠。加密算法这类精确逻辑必须所有用例全部通过才算还原正确。5.3 差异定位与重还原如果校验不通过不要整段重新还原。先定位到具体哪个函数、哪个块输出不一致针对有问题的块重新还原给出更明确的约束和提示。反复迭代直到所有用例全部通过。六、工程化封装打造自己的AI逆向工具链单步操作熟练之后可以把整个流程封装成自动化工具链批量处理混淆代码。6.1 完整自动化链路输入混淆代码 ↓ 自动预处理格式化、去对抗、还原字符串 ↓ 自动识别入口点按功能切块 ↓ 调用大模型API逐块还原 ↓ 自动运行测试用例校验 ↓ 输出还原后的可读代码 校验报告6.2 批量处理能力对于大量相似的混淆代码可以批量处理。比如同一个站点的多个页面、同一个混淆器生成的多份代码统一预处理、统一还原策略批量输出结果。6.3 知识库沉淀把常见的混淆模式、还原策略、校验方法沉淀成知识库不断优化提示词和处理流程。用的越多准确率越高速度越快。七、踩坑与最佳实践坑1直接整段代码扔给大模型后果上下文不够、语义漂移、逻辑错误还原出来的代码中看不中用。正确分块处理从底层到上层逐块还原逐步验证。坑2只看代码美观不做动态校验后果看起来还原得很漂亮实际跑起来结果不对关键逻辑错了都不知道。正确所有还原的代码必须经过动态校验输入输出完全一致才算通过。坑3完全依赖AI自己不看逻辑后果遇到对抗性代码、假逻辑AI会直接当真逻辑还原结果完全跑偏。正确人把控核心方向和边界AI做体力活关键逻辑人工复核。坑4提示词太简单没有约束后果AI自由发挥删改关键逻辑添加自己的想象。正确提示词明确约束规则哪些不能改、哪些必须保留、输出什么格式都写清楚。最佳实践先动态调试找入口再AI还原效率最高越小的块还原准确率越高不要贪大核心加密算法一定要多组用例校验还原过程结合AST工具做预处理比纯AI效果好常用的混淆模式沉淀成固定的处理模板最后JS逆向这个领域从来不是比谁能扛、谁能熬而是比谁的方法更高效、工具链更强大。大模型没有替代逆向工程师但它重构了这个工种的工作模式从以前的「从头到尾人工抠」变成现在的「策略工具AI辅助」。人从体力劳动里解放出来专注于核心逻辑、对抗策略和流程设计效率和产出都完全不是一个量级。说到底工具在进化人的能力也要进化。善用AI把重复的工作交给机器把精力放在真正有价值的地方才是技术人的核心竞争力。