JavaScript代码混淆与还原技术

约 16 分钟读完

混淆JavaScript代码主要意义:

1、防止代码被逆向工程:混淆使得代码的逻辑变得晦涩难懂,使攻击者难以理解代码的运行原理。这可以防止恶意用户或竞争对手直接分析、修改或复制代码。 2、保护知识产权:混淆代码可以防止他人盗用和复制您的代码。通过混淆,您可以更好地保护您的知识产权,确保您的代码不会被滥用或未经授权使用。 3、减少代码大小:混淆技术可以压缩和优化代码,从而减小代码的大小,提高加载速度和性能。 4、提高安全性:通过混淆代码,可以隐藏敏感信息、算法和逻辑,从而增加代码的安全性。这对于处理敏感数据或执行关键任务的应用程序特别重要。 5、避免自动化攻击:混淆代码可以使自动化攻击工具难以识别和分析代码。这可以有效地阻止一些常见的攻击,如代码注入、XSS(跨站点脚本)和CSRF(跨站点请求伪造)等。

认知常见混淆手法:

*eval,JJEncode,AAEncode,JSFuck,Obfuscator等混淆还原 eval: 特征:出现关键字eval 还原:控制台输出(去除eval()后)给函数名,新建JS文件优化 JJEncode,AAEncode,JSFuck: 特征:包含很多$ 特征:包含很多颜文字 特征:包含很多[ ]、()、+、! 还原:控制台输出(一般去除()调用后)点击查看或直接运行 Obfuscator: 特征:包含很多——0x字母无意义的字符串,阅读难度增加 还原:控制台输出美化代码断点调试输出分析,利用AST技术解密还原

基本混淆技术

  1. 变量和函数重命名

    // 原始代码
    function calculateTotal(price, quantity) {
      return price * quantity;
    }
    
    // 混淆后
    function a(b,c){return b*c;}
  2. 字符串编码

    // 原始代码
    console.log("Hello World");
    
    // 混淆后
    console.log("\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64");
  3. 控制流混淆

    // 原始代码
    if (condition) {
      doSomething();
    }
    
    // 混淆后
    (function(){return condition?doSomething():null;})();

高级混淆技术

  1. 代码压缩和优化

    • 移除空白字符、注释
    • 缩短变量名
    • 简化表达式
  2. 代码拆分和重组

    • 将代码拆分成多个部分
    • 动态加载和执行
  3. 自我修改代码

    • 代码在运行时解密并执行自身

常用混淆工具

  1. UglifyJS - 流行的JS压缩/混淆工具

    npm install uglify-js -g
    uglifyjs input.js -o output.js -c -m
  2. Terser - ES6+支持的UglifyJS分支

    npm install terser -g
    terser input.js -o output.js -c -m
  3. JavaScript Obfuscator - 专门的混淆工具

    npm install javascript-obfuscator -g
    javascript-obfuscator input.js --output output.js
  4. 在线工具

案例分享

案列一

访问https://scrape.center/

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 应用,主要功能是:

  1. 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'},
      // ...其他球员数据
    ];
  2. 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();
}

加密流程:

  1. 从球员对象解构出 name, birthday, height, weight
  2. 将密钥转换为 CryptoJS 可用的格式
  3. 将球员姓名进行 Base64 编码
  4. 使用 DES 算法加密组合字符串(Base64姓名+生日+身高+体重)
  5. 返回加密后的字符串
4. 代码用途推测

这段代码可能是:

  1. 一个NBA球员信息展示页面
  2. 包含对球员数据的加密功能,可能是为了生成某种令牌(token)
  3. 可能用于API请求验证或数据保护
5. 混淆特点
  1. 使用了变量名替换(如 g = let, h = players
  2. 字符串被拆分成数组并通过索引引用
  3. 使用了数字和字母的混合编码
  4. 关键功能被隐藏在复杂的结构中
6. 如何反混淆

要完全还原这段代码,可以:

  1. 使用在线反混淆工具如 https://lelinhtinh.github.io/de4js/
  2. 或者逐步替换代码中的变量名和字符串引用
  3. 使用浏览器开发者工具设置断点调试

这段代码虽然混淆程度较高,但由于保留了原始变量名在数组中,实际上还是比较容易还原的。

还原手法

在浏览器控制台中进行调试 用一个变量接收函数就能够进行还原 将得到的值复制到其他软件中,格式化就能看到原来的代码

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/ 平台可能无法做到完美的还原,可能还原一部分或者还原不了

注意事项

  1. 性能影响:混淆可能会轻微影响代码执行性能
  2. 调试困难:混淆后的代码难以调试
  3. 不完全安全:混淆不是加密,有经验的开发者仍可逆向工程
  4. 法律合规:确保混淆代码不违反任何开源许可证

混淆是保护前端代码的有效手段,但不能替代服务器端的安全措施。

← v-jstools JS 逆向与代码混淆还原相关方法、资源及思路总结 →