
做前端协议分析、工业数据采集的同行基本都绕不开JS混淆这道坎。抓包下来的核心逻辑代码要么变量全是a、b、c挤成一团看不懂要么整段代码包在eval里全是十六进制字符串更狠一点的上控制流平坦化把顺理成章的逻辑拆成switch-case大分发跳来跳去根本理不清流程。早年刚接触的时候我对着几百行混淆代码硬啃一下午还原不了几十行逻辑走了大量弯路。后来把主流工具和方法都摸了一遍才发现绝大多数场景根本不用手动抠选对工具和方法几分钟就能还原到接近源码的可读性。这篇文章把JS混淆的主流类型、对应工具选型、分场景还原步骤、进阶AST定制方案全部梳理清楚从入门到进阶覆盖90%的常规反混淆需求。一、先搞懂你面对的是哪种混淆很多人上来就找万能反混淆工具其实根本不存在万能的。不同的混淆手段原理完全不同对应不同的还原方法。先识别类型再选工具效率至少提升三倍。目前主流的四类混淆混淆类型代表工具典型特征还原难度基础压缩混淆uglify-js、terser变量短名化、去空格、合并声明无加密★eval字符串加密在线加密、自定义混淆大段十六进制/转义字符串靠eval动态执行★★控制流平坦化字符串加密javascript-obfuscator大段switch分发逻辑字符串全部加密跳转混乱★★★★虚拟机/解释器混淆商用加固、jsfuck无原生语法靠自定义解释器执行字节码★★★★★识别方法很简单打开代码先搜关键词。只有单字母变量就是基础压缩有eval和大串乱码就是字符串加密有巨型switch和大量case就是控制流平坦化几乎看不到正常JS关键字基本就是虚拟机混淆。我见过很多人一上来就找最强的反混淆工具结果扔进去一段uglify代码出来的效果和格式化没区别还说工具垃圾。其实就是没选对场景。二、主流反混淆工具横向对比不用每个都试按你的混淆场景选就行。工具核心能力适用场景还原度易用性js-beautify代码格式化、语法美化基础压缩混淆低仅恢复格式极高de4jseval解密、字符串静态还原eval类、简单加密混淆中高obfuscator-io-deobfuscator专项还原obfuscator.io控制流平坦化、字符串加密高中Babel 自定义插件AST级定制化转换复杂自定义混淆、批量处理极高低在线反混淆站多工具集成、开箱即用临时、小批量代码不等极高通用工具只能解决通用问题。遇到自定义混淆、魔改混淆通用工具效果会大打折扣这时候就需要上AST定制方案。三、分场景还原实战从易到难逐层拆解是否是否是否是拿到混淆代码识别混淆类型基础压缩?js-beautify格式化按逻辑语义化重命名完成还原eval字符串加密?de4js解密eval格式化语义优化控制流平坦化?专项工具解密字符串还原控制流结构清理死代码变量重命名虚拟机混淆?分析指令集模拟执行人工辅助还原逻辑1. 基础压缩混淆格式化语义化两步走这是最简单的场景也是所有还原的基础步骤。uglify、terser这类压缩只是把代码变紧凑没有改变逻辑。第一步用js-beautify格式化恢复缩进和换行把一行流拆成正常结构。npx js-beautify obfuscated.js-oformatted.js第二步顺着业务逻辑给变量重命名。这一步工具替代不了但格式化之后结构清晰了先找入口函数再顺着调用链往下捋用到哪个改哪个不用一次性全改。几百行的代码十几分钟就能把核心变量改成有意义的名字。2. eval/字符串加密混淆直接解密执行结果这类混淆的本质是“代码字符串化”把正常代码转成加密字符串运行时通过eval、Function构造函数动态解析执行。最简单的还原方法把代码里的eval改成console.log放到浏览器或者Node里跑一遍明文直接输出。但遇到多层嵌套eval、字符串拆分拼接的情况手动改就很麻烦。批量处理直接用de4js自动识别并解密多层evalnpx de4js input.js output.js绝大多数单层、双层eval混淆跑一遍就能还原出明文代码再格式化一遍就可以正常阅读。踩坑提醒有些混淆会把eval拆成字符串拼接比如e‘val’直接搜关键词搜不到。这时候找最终调用的构造函数顺着调用链往上找就能定位。3. 控制流平坦化混淆专项工具拆解switch这是目前最常见也最头疼的类型obfuscator.io生成的混淆基本都是这个路数字符串全部加密核心逻辑被拆成一个巨大的switch分发器通过一个变量控制执行顺序代码跳来跳去根本看不出先后逻辑。手动理清楚控制流要花几倍的时间用专门的反混淆工具可以自动完成大部分工作nodedeobfuscate.js obfuscated.js clean.js还原之后会做三件事所有加密字符串替换成明文拆解switch分发结构把case按执行顺序拼接回正常代码清理无用的死代码和垃圾变量还原完的代码变量名还是短名但逻辑结构已经非常清晰再做一遍语义化重命名可读性基本接近源码。客观说控制流还原不是100%完美的特别复杂的多层嵌套可能还会有残留但已经能减少80%的阅读成本。四、进阶AST定制反混淆搞定自定义混淆通用工具解决不了的场景比如厂商自定义混淆、批量处理需求就得上AST级别的定制还原。这也是工业级反混淆的主流方案。AST就是抽象语法树把代码从文本形式转成树状结构每个语法元素都是一个节点。我们可以遍历所有节点针对混淆特征做定向转换最后生成干净的代码。核心三步解析、转换、生成。其中转换是核心想怎么改就怎么写插件。举个最简单的字符串解密例子核心逻辑片段constparserrequire(babel/parser);consttraverserequire(babel/traverse).default;constgeneraterequire(babel/generator).default;consttrequire(babel/types);// 1. 解析成ASTconstastparser.parse(obfuscatedCode);// 2. 遍历节点替换加密字符串traverse(ast,{CallExpression(path){// 匹配自定义解密函数的调用if(path.node.callee.namedecodeStr){constargValuepath.node.arguments[0].value;// 提前计算明文替换整个调用节点constplainTextcustomDecode(argValue);path.replaceWith(t.stringLiteral(plainText));}}});// 3. 生成最终代码constresultgenerate(ast,{concise:false},obfuscatedCode);这种方式的优势是极度灵活。不管什么自定义混淆只要能找到加密规律、控制流特征就能写插件批量还原。大规模、常态化的反混淆需求基本都是走AST定制的路线。五、反混淆的边界与常见坑不要神化反混淆也有明确的边界和绕不开的坑。多层嵌套混淆混淆套混淆eval里面还有控制流不能指望一次跑完。需要逐层识别、逐层解密像剥洋葱一样一层一层往里剥。反调试与环境检测很多混淆代码自带反调试检测到开发者工具就不执行或者跑死循环。本地运行解密前要先把反调试逻辑干掉或者绕过。死代码注入大量插入永远执行不到的垃圾分支和无用变量干扰阅读。还原的时候要同步做死代码清理不然还是很乱。虚拟机混淆纯字节码解释器型的混淆通用工具基本没用。需要分析指令集、写模拟解释器才能还原时间成本极高。完整性校验有些代码会校验自身哈希改动后直接不运行。还原的时候注意保留校验逻辑或者提前把校验绕过。合规声明本文仅用于技术研究与学习交流所有反混淆操作均需在合法授权范围内进行不得用于破解软件、非法获取数据等违反法律法规的行为。技术本身没有对错使用者请严守合规底线。六、总结JS反混淆这件事思路永远比工具重要。先识别混淆类型再从最简单的工具开始试能格式化解决的就不用解密能通用工具解决的就不用写AST。不要上来就搞最复杂的方案大多数场景根本用不上。混淆和反混淆是不断对抗的过程没有一劳永逸的万能工具。理解了底层原理遇到新的混淆手段也能快速找到突破口。