设为首页收藏本站

QQ登录

只需一步,快速开始

登录 | 立即注册 | 找回密码
查看: 126|回复: 0

www.sojson.com 网站高级JS 加密破解【解密源文件】

[复制链接]

171

主题

172

帖子

721

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
721
发表于 2018-10-20 00:22:53 | 显示全部楼层 |阅读模式
乍一看这句话吓一跳,我去这么猛,然后就很有兴趣想看看究竟是怎样一种加密算法。
对于破解JS加密算法的时候,都是先输入一个简单的语句然后分析加密后语句的规律,这里先输入一个简单的打印log:
代码拷出来格式化一下:
  1. var __encode = 'sojson.com',
  2. _0xb483 = ["\x5F\x64\x65\x63\x6F\x64\x65", "\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x73\x6F\x6A\x73\x6F\x6E\x2E\x63\x6F\x6D\x2F\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x6F\x62\x66\x75\x73\x63\x61\x74\x6F\x72\x2E\x68\x74\x6D\x6C"]; (function(_0xd642x1) {
  3.     _0xd642x1[_0xb483[0]] = _0xb483[1]
  4. })(window);
  5. var _0xdc02 = ["\x6F\x6B", "\x6C\x6F\x67"];
  6. console[_0xdc02[1]](_0xdc02[0])
复制代码
这个时候规律已经挺明显了,不急先将十六进制、Unicode等转为易读形式:
  1. <html>
  2. <head>
  3.     <meta charset="UTF-8"/>
  4.     <title>JavaScript 16进制、Unicode解码</title>
  5. </head>
  6. <body>
  7. <form action="#">
  8.     <textarea id="js-code" cols="100" rows="30"></textarea>
  9.     <button id="decode-btn" type="button">DECODE</button>
  10. </form>
  11. <script type="text/javascript">
  12.     !function () {
  13.         document.getElementById("decode-btn").addEventListener("click", event => {
  14.             const jsCodeBox = document.getElementById("js-code");
  15.             // 可能会有中文的unicode,要能够兼容
  16.             jsCodeBox.value = jsCodeBox.value.replace(/\\x..|\\u.{4}/g, hex => decode(hex));
  17.         });

  18.         function decode(hex) {
  19.             try {
  20.                 const c = parseInt(hex.substring(2), 16);
  21.                 return String.fromCharCode(c);
  22.             } catch (e) {
  23.                 console.log("parse " + hex + " error.");
  24.             }
  25.             return hex;
  26.         }
  27.     }();
  28. </script>
  29. </body>
  30. </html>
复制代码
十六进制、Unicode解码之后:
  1. var __encode = 'sojson.com',
  2. _0xb483 = ["_decode", "http://www.sojson.com/javascriptobfuscator.html"]; (function(_0xd642x1) {
  3.     _0xd642x1[_0xb483[0]] = _0xb483[1]
  4. })(window);
  5. var _0xdc02 = ["ok", "log"];
  6. console[_0xdc02[1]](_0xdc02[0])
复制代码
这个时候规律已经超级明显了,就是将属性访问、字符串常量等乱七八糟的提取到一个字典中,然后再引用这个字典,可是这种既做不到不可逆(我下面会写一个专破工具),也做不到体积小,因为len("[_0xdc02[1]]")===12,而len(".log")===4,只在属性名超过11(12-1)并且被引用多次时才能够节省空间,这里的设计一大败笔就是字典名字出现频率极高,但是给的变量名字还是这么长,哈夫曼编码了解一下呗。至于运行速度没有差别,这点时间差别人当然是感觉不出来但多做了一次数组访问肯定是慢了。
下面是针对此网站的高级JS加密写的一个专破工具,基本能够实现还原:
  1. <html>
  2. <head>
  3.     <meta charset="UTF-8"/>
  4.     <title>sojson js高级加密专破工具, https://www.sojson.com/javascriptobfuscator.html</title>
  5. </head>
  6. <body>
  7. <form action="#">
  8.     <textarea name="js-code" id="js-code" cols="100" rows="30"></textarea>
  9.     <button id="decode-btn" type="button">DECODE</button>
  10. </form>
  11. <script type="text/javascript">
  12.     !function () {
  13.         document.getElementById("decode-btn").addEventListener("click", event => {
  14.             const jsCodeBox = document.getElementById("js-code");
  15.             const rawJs = jsCodeBox.value;

  16.             let decodeJs = replaceDictionaryIndexReference(rawJs);
  17.             decodeJs = squareBracketsToDot(decodeJs);
  18.             decodeJs = dropSignature(decodeJs);
  19.             jsCodeBox.value = decodeJs;

  20.             /**
  21.              * 字典引用替换为字面值常量
  22.              *
  23.              * @param rawJs
  24.              * @returns {*}
  25.              */
  26.             function replaceDictionaryIndexReference(rawJs) {
  27.                 const dictionaryNameSet = extractDictionaryNames(rawJs);
  28.                 let decodeJs = rawJs;
  29.                 dictionaryNameSet.forEach(dicName => {
  30.                     // 将字典声明于当前上下文环境
  31.                     const dicCode = new RegExp("(var\\s+|)" + dicName + "\\s*=\\s*\\[.+?\\];").exec(decodeJs)[0];
  32.                     eval(dicCode);

  33.                     // 将访问到此变量的地方引用替换为字面值
  34.                     let isChange = false;
  35.                     decodeJs = decodeJs.replace(new RegExp(dicName + "\\[\\d+\\]", "g"), index => {
  36.                         const dicIndex = parseInt(/\[(\d+)]/.exec(index)[1]);
  37.                         let result = eval(dicName + "[" + dicIndex + "]");
  38.                         // 对于文本,需要加上双引号
  39.                         if (!result.match(/^\d+$/)) {
  40.                             result = "\"" + result + "\"";
  41.                         }
  42.                         isChange = true;
  43.                         return result;
  44.                     });

  45.                     // 如果此变量被使用过,则将其从原文中清除
  46.                     if (isChange) {
  47.                         decodeJs = decodeJs.replace(dicCode, "");
  48.                     }
  49.                 });
  50.                 return decodeJs;
  51.             }

  52.             /**
  53.              * 抽取出所有字典名称
  54.              *
  55.              * @param rawJs
  56.              * @returns {Set}
  57.              */
  58.             function extractDictionaryNames(rawJs) {
  59.                 const re = /(_+\w+?)\s*=\s*\[.+?]/g;
  60.                 // const re = /(_0x\w+?)\s*=/g;
  61.                 const dictionaryNameSet = new Set();
  62.                 while (dicName = re.exec(rawJs)) {
  63.                     dictionaryNameSet.add(dicName[1]);
  64.                 }
  65.                 return dictionaryNameSet;
  66.             }

  67.             /**
  68.              * 方法调用尽量由["foo"]的形式转为点调用
  69.              *
  70.              * @param decodeJs
  71.              * @returns {string | void | *}
  72.              */
  73.             function squareBracketsToDot(decodeJs) {
  74.                 return decodeJs.replace(/\w+\["\w+"]/g, call => {
  75.                     const nameAndAttr = call.replace("[\"", " ").replace("\"]", "").split(" ");
  76.                     try {
  77.                         // 只替换name在当前上下文中已存在并且attr的类型是function
  78.                         if (typeof eval(nameAndAttr[0] + "." + nameAndAttr[1]) === "function") {
  79.                             return nameAndAttr[0] + "." + nameAndAttr[1];
  80.                         }
  81.                     } catch (e) {
  82.                         console.log("cannot replace: " + call);
  83.                     }
  84.                     return call;
  85.                 });
  86.             }

  87.             /**
  88.              * 丢弃作者的签名
  89.              *
  90.              * @param encodeJs
  91.              * @returns {string | void | *}
  92.              */
  93.             function dropSignature(encodeJs) {
  94.                 return encodeJs.replace(/^var __encode.+?\(window\);/, "");
  95.             }

  96.         });
  97.     }();
  98. </script>
  99. </body>
  100. </html>
复制代码



著名:来自某大神之手


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

    移动客户端
    关注我们
  • 微信公众号:
  • 请期待
  • 扫描二维码加关注

Powered by 新决起论坛X3.2 © 2008-2013 Comsenz Inc.

Archiver|手机版|小黑屋| Comsenz Inc.     360网站安全检测平台

快速回复 返回顶部 返回列表