JavaScript代码混淆与还原技术
混淆JavaScript代码主要意义:
1、防止代码被逆向工程:混淆使得代码的逻辑变得晦涩难懂,使攻击者难以理解代码的运行原理。这可以防止恶意用户或竞争对手直接分析、修改或复制代码。 2、保护知识产权:混淆代码可以防止他人盗用和复制您的代码。通过混淆,您可以更好地保护您的知识产权,确保您的代码不会被滥用或未经授权使用。 3、减少代码大小:混淆技术可以压缩和优化代码,从而减小代码的大小,提高加载速度和性能。 4、提高安全性:通过混淆代码,可以隐藏敏感信息、算法和逻辑,从而增加代码的安全性。这对于处理敏感数据或执行关键任务的应用程序特别重要。 5、避免自动化攻击:混淆代码可以使自动化攻击工具难以识别和分析代码。这可以有效地阻止一些常见的攻击,如代码注入、XSS(跨站点脚本)和CSRF(跨站点请求伪造)等。
认知常见混淆手法:
*eval,JJEncode,AAEncode,JSFuck,Obfuscator等混淆还原 eval: 特征:出现关键字eval 还原:控制台输出(去除eval()后)给函数名,新建JS文件优化 JJEncode,AAEncode,JSFuck: 特征:包含很多$ 特征:包含很多颜文字 特征:包含很多[ ]、()、+、! 还原:控制台输出(一般去除()调用后)点击查看或直接运行 Obfuscator: 特征:包含很多——0x字母无意义的字符串,阅读难度增加 还原:控制台输出美化代码断点调试输出分析,利用AST技术解密还原
基本混淆技术
变量和函数重命名:
// 原始代码 function calculateTotal(price, quantity) { return price * quantity; } // 混淆后 function a(b,c){return b*c;}字符串编码:
// 原始代码 console.log("Hello World"); // 混淆后 console.log("\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64");控制流混淆:
// 原始代码 if (condition) { doSomething(); } // 混淆后 (function(){return condition?doSomething():null;})();
高级混淆技术
代码压缩和优化:
- 移除空白字符、注释
- 缩短变量名
- 简化表达式
代码拆分和重组:
- 将代码拆分成多个部分
- 动态加载和执行
自我修改代码:
- 代码在运行时解密并执行自身
常用混淆工具
UglifyJS - 流行的JS压缩/混淆工具
npm install uglify-js -g uglifyjs input.js -o output.js -c -mTerser - ES6+支持的UglifyJS分支
npm install terser -g terser input.js -o output.js -c -mJavaScript Obfuscator - 专门的混淆工具
npm install javascript-obfuscator -g javascript-obfuscator input.js --output output.js在线工具:
案例分享
案列一
spa9--eval()混淆
加载数据包
在响应的数据包中可以看到
<script>eval(function(p,a,c,k,e,r){e=function(c){return(c<62?'':e(parseInt(c/62)))+((c=c%62)>35?String.fromCharCode(c+29):c.toString(36))};if('0'.replace(0,e)==0){while(c--)r[e(c)]=k[c];k=[function(e){return r[e]||e}];e=function(){return'[0-9a-zA-D]'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('g h=[{0:\'凯文-杜兰特\',4:\'durant.5\',1:\'b-09-c\',2:\'i\',3:\'108.j\'},{0:\'勒布朗-詹姆斯\',4:\'james.5\',1:\'k-12-30\',2:\'206cm\',3:\'113.l\'},{0:\'斯蒂芬-库里\',4:\'curry.5\',1:\'b-7-14\',2:\'m\',3:\'83.j\'},{0:\'詹姆斯-哈登\',4:\'harden.5\',1:\'1989-n-26\',2:\'196cm\',3:\'99.8\'},{0:\'扬尼斯-安特托昆博\',4:\'antetokounmpo.5\',1:\'o-12-d\',2:\'p\',3:\'109.8\'},{0:\'拉塞尔-威斯布鲁克\',4:\'westbrook.5\',1:\'b-11-12\',2:\'m\',3:\'90.7KG\'},{0:\'凯里-欧文\',4:\'irving.5\',1:\'1992-7-23\',2:\'q\',3:\'r.9\'},{0:\'安东尼-戴维斯\',4:\'davis.5\',1:\'1993-7-11\',2:\'i\',3:\'114.8\'},{0:\'乔尔-恩比德\',4:\'embiid.5\',1:\'o-7-16\',2:\'s\',3:\'127.0KG\'},{0:\'克雷-汤普森\',4:\'thompson.5\',1:\'t-u-n\',2:\'198cm\',3:\'97.9\'},{0:\'考瓦伊-莱昂纳德\',4:\'leonard.5\',1:\'1991-d-c\',2:\'201cm\',3:\'102.1KG\'},{0:\'达米安-利拉德\',4:\'lillard.5\',1:\'t-07-15\',2:\'q\',3:\'r.9\'},{0:\'卡梅罗-安东尼\',4:\'anthony.5\',1:\'k-v-c\',2:\'203cm\',3:\'108KG\'},{0:\'尼科拉-约基奇\',4:\'jokic.5\',1:\'w-u-19\',2:\'s\',3:\'128.8\'},{0:\'卡尔-安东尼-唐斯\',4:\'towns.5\',1:\'w-11-15\',2:\'p\',3:\'112.9\'},{0:\'克里斯-保罗\',4:\'paul.5\',1:\'1985-v-d\',2:\'185cm\',3:\'79.l\'},];new Vue({el:\'#app\',data:function(){x{h,a:\'NAhwcEVLEnRoJA7acv6eZGvXWjtijppyHXh\'}},methods:{getToken(y){e a=6.f.z.A(this.a);g{0,1,2,3}=y;e B=6.f.Base64.stringify(6.f.z.A(0));e C=6.DES.encrypt(`${B}${1}${2}${3}`,a,{D:6.D.ECB,padding:6.pad.Pkcs7});x C.toString()}}})',[],40,'name|birthday|height|weight|image|png|CryptoJS|03|8KG|5KG|key|1988|29|06|let|enc|const|players|208cm|9KG|1984|4KG|191cm|08|1994|211cm|188cm|88|213cm|1990|02|05|1995|return|player|Utf8|parse|base64Name|encrypted|mode'.split('|'),0,{}))</script>
可以看到是被混淆加密的js代码
这段代码是一个经过混淆的 JavaScript 代码,使用了 eval() 函数执行一个经过编码的字符串。我来逐步分析它的结构和功能:
1. 代码结构分析
这是一个典型的 packer 混淆代码,结构为:
eval(function(p,a,c,k,e,r){...}(...))其中:
p是压缩的主代码字符串a是参数数组(这里是空数组)c是代码中需要替换的单词数量k是关键字/变量名数组e是解码函数r是替换字典
2. 解码后的主要内容
解码后可以识别出这是一个 Vue.js 应用,主要功能是:
NBA球员数据数组:
let players = [ {name: '凯文-杜兰特', image: 'durant.png', birthday: '1988-09-29', height: '208cm', weight: '108KG'}, {name: '勒布朗-詹姆斯', image: 'james.png', birthday: '1984-12-30', height: '206cm', weight: '113KG'}, // ...其他球员数据 ];Vue实例:
new Vue({ el: '#app', data: function() { return { players, a: 'NAhwcEVLEnRoJA7acv6eZGvXWjtijppyHXh' // 看起来像加密密钥 } }, methods: { getToken(player) { // 加密处理逻辑 } } })
3. 加密功能分析
getToken 方法使用了 CryptoJS 库进行加密操作:
getToken(player) {
const {name, birthday, height, weight} = player;
const key = CryptoJS.enc.Utf8.parse(this.a);
const base64Name = CryptoJS.Base64.stringify(CryptoJS.enc.Utf8.parse(name));
const encrypted = CryptoJS.DES.encrypt(
`${base64Name}${birthday}${height}${weight}`,
key,
{mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7}
);
return encrypted.toString();
}加密流程:
- 从球员对象解构出 name, birthday, height, weight
- 将密钥转换为 CryptoJS 可用的格式
- 将球员姓名进行 Base64 编码
- 使用 DES 算法加密组合字符串(Base64姓名+生日+身高+体重)
- 返回加密后的字符串
4. 代码用途推测
这段代码可能是:
- 一个NBA球员信息展示页面
- 包含对球员数据的加密功能,可能是为了生成某种令牌(token)
- 可能用于API请求验证或数据保护
5. 混淆特点
- 使用了变量名替换(如
g=let,h=players) - 字符串被拆分成数组并通过索引引用
- 使用了数字和字母的混合编码
- 关键功能被隐藏在复杂的结构中
6. 如何反混淆
要完全还原这段代码,可以:
- 使用在线反混淆工具如 https://lelinhtinh.github.io/de4js/
- 或者逐步替换代码中的变量名和字符串引用
- 使用浏览器开发者工具设置断点调试
这段代码虽然混淆程度较高,但由于保留了原始变量名在数组中,实际上还是比较容易还原的。
还原手法
在浏览器控制台中进行调试
用一个变量接收函数就能够进行还原
将得到的值复制到其他软件中,格式化就能看到原来的代码

spa10--JJEncode混淆
首先了解

还原
定位到下图所在位置,可以看懂很明显的jjendoe混淆
还原:
复制整个代码到控制台
执行后得到下面的结果
点击进去就是原本的代码
spa11-AAEncode混淆
AAEncode混淆的特征就是又很多颜文字
在这一关可以看到很明显是的颜文字特征,确定是AAencode混淆
还原
与JJEncode类似,去掉混淆代码的最后的括号
在控制台将结尾圈起来部分删掉就可以还原
点击进去就是源代码
spa12--JSFuck混淆
特征:特征:包含很多[ ]、()、+、!
还原:控制台输出(一般去除()调用后)点击查看或直接运行
还原
将代码保存到本地中,在node环境中运行就可以得到源码
spa13--Obfuscator
了解
特征:包含很多——0x字母无意义的字符串,阅读难度增加 还原:控制台输出美化代码断点调试输出分析,利用AST技术解密还原
还原
将代码美化后进行断点调试,进行对比。用AST技术。 或者使用在线工具 https://jsdec.js.org/ https://lelinhtinh.github.io/de4js/ 平台可能无法做到完美的还原,可能还原一部分或者还原不了
注意事项
- 性能影响:混淆可能会轻微影响代码执行性能
- 调试困难:混淆后的代码难以调试
- 不完全安全:混淆不是加密,有经验的开发者仍可逆向工程
- 法律合规:确保混淆代码不违反任何开源许可证
混淆是保护前端代码的有效手段,但不能替代服务器端的安全措施。