设为首页收藏本站

QQ登录

只需一步,快速开始

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

jspacker压缩及解压缩研究(js eval)

[复制链接]

171

主题

172

帖子

721

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
721
发表于 2018-10-20 00:26:47 | 显示全部楼层 |阅读模式
起因:
在研究爬虫的时候发现很多网站都出现了同一种方式的js混淆,并且名字都是pde.js,怀疑是使用了同一款混淆工具,所以研究一下。
这款工具叫JS Packer,并不是专门的混淆工具,而是一款js压缩工具,其官网地址为: http://dean.edwards.name/packer/
支持两种压缩方式,一种是Shrink variables比较常规的压缩方式,就是去掉一些空白符注释之类的,另一种是Base62 encode,是一种比较适合用来压缩内容单词重复率高的压缩方式。
压缩示例
所有讨论基于Base62 encode压缩方式,输入:
  1. alter("hello, world");
复制代码
输出:
  1. eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('0("1, 2");',3,3,'alter|hello|world'.split('|'),0,{}))
复制代码
格式化后:
  1. eval(function (p, a, c, k, e, r) {
  2.     e = String;
  3.     if (!''.replace(/^/, String)) {
  4.         while (c--) r[c] = k[c] || c;
  5.         k = [function (e) {
  6.             return r[e]
  7.         }];
  8.         e = function () {
  9.             return '\\w+'
  10.         };
  11.         c = 1
  12.     }
  13.     ;
  14.     while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]);
  15.     return p
  16. }('0("1, 2");', 3, 3, 'alter|hello|world'.split('|'), 0, {}))
复制代码
上面的代码看着很唬人,其实原理很简单,我们耐心分析下。

压缩原理:
简单来说就是将相同的单词进行压缩,具体为将所有单词抽取出来作为一个词典,然后将源代码中表示单词的地方改为引用词典的下标,这样的话当重复的单词很多的时候压缩效果就比较好,但是当重复的单词比较少的时候这种方法有点得不偿失。
带入具体数据来具体分析,比如下面的代码:
  1. console.log("aaaaa");
  2. console.log("aaaaa");
  3. console.log("bbbb");
复制代码
压缩之后格式化:
  1. eval(function(p, a, c, k, e, r) {
  2.     e = String;
  3.     if (!''.replace(/^/, String)) {
  4.         while (c--) r[c] = k[c] || c;
  5.         k = [function(e) {
  6.             return r[e]
  7.         }];
  8.         e = function() {
  9.             return '\\w+'
  10.         };
  11.         c = 1
  12.     };
  13.     while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]);
  14.     return p
  15. } ('0.1("2");0.1("2");0.1("3");', 4, 4, 'console|log|aaaaa|bbbb'.split('|'), 0, {}))
复制代码


可以看到规律已经很明显了,第一个 参数 '0.1("2");0.1("2");0.1("3");'中的数字对应着 'console|log|aaaaa|bbbb'.split('|') 中的下标,解压的时候只需要再将数字下标还原为单词即可。

下面是对解压缩算法的一个简单解读:
  1. // p 将原始内容中所有单词替换为字典下标后的压缩内容
  2. // a 词典大小,暂时用不到
  3. // c 词典大小,在解压时用来关联压缩内容和词典
  4. // k 词典
  5. // e 在解压时,当replace第二个参数支持function时,为\\w+,否则为与下标对应的字符串
  6. // r 当加速解压时用来保存词典
  7. eval(function(p, a, c, k, e, r) {
  8.     e = String;

  9.     // 检测当前的浏览器是否支持replace(regex, function),如果支持的话就能够加快解压速度
  10.     // 如果不支持的话可以把这一块直接忽略掉
  11.     if (!''.replace(/^/, String)) {

  12.         // 把被压缩的单词拷贝一份,因为k还有别的用处
  13.         while (c--) r[c] = k[c] || c;

  14.         // k[0]后面用来对每个匹配到的下标寻找替换字符串
  15.         k = [function(e) {
  16.             return r[e]
  17.         }];

  18.         // 用来分割原始内容
  19.         e = function() {
  20.             return '\\w+'
  21.         };

  22.         // 加速解压的时候,相当于把while变成了if
  23.         c = 1
  24.     };

  25.     // 使用词典将压缩后的下标代码扩展,如果没有上面的加速的话,c等于词典单词数,要一个一个替换了
  26.     // 如果支持replace(string, function)的话,会将匹配到的每一个数字都传递给k[c]来得到其应该被替换为的字符串
  27.     while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]);

  28.     // 完成解压
  29.     return p
  30. } ('0.1("2");0.1("2");0.1("3");', 4, 4, 'console|log|aaaaa|bbbb'.split('|'), 0, {}))
复制代码
解压缩小工具
我把这种 eval(blablabla…) 形式的统称为eval压缩,并针对此写了个一个简单的解压小工具。
思路:
1. 既然这种肯定是要在网页上执行的,那么只需要模拟执行就可以了。
2. 可能不只有一层eval,所以应该能够方便的多次连续eval。

html代码如下:
  1. <html>
  2. <head>
  3.     <meta charset="UTF-8">
  4.     <title>JavaScript eval</title>
  5. </head>
  6. <body>

  7. <textarea id="eval_code" cols="100" rows="30" placeholder="粘贴eval代码"></textarea>
  8. <button onclick="executeEval()">EVAL</button>

  9. <script type="text/javascript">
  10.     function executeEval(){
  11.         let evalCodeElt = document.getElementById("eval_code");
  12.         let evalCode = evalCodeElt.value;
  13.         // 如果不把开头的eval去掉的话直接执行会被执行两遍
  14.          evalCode = evalCode.replace(/^eval/, "");
  15.         try{
  16.             evalCodeElt.value = eval(evalCode);
  17.         }catch (e) {
  18.             alert("执行报错了:" + e);
  19.         }
  20.     }
  21. </script>
  22. </body>
  23. </html>
复制代码

效果如下:



本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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

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

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

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