JavaScript类似于eval加密编码方式的解密解码过程(Unpack)

!本文可能 超过1年没有更新,今后内容也许不会被维护或者支持,部分内容可能具有时效性,涉及技术细节或者软件使用方面,本人不保证相应的兼容和可操作性。

类似于下面这样的代码,肯定你在研究前端JavaScript脚本时遇到过:

1
2
3
4
5
6
7
8
9
10
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,
'alert|Hello|World'.split('|'),0,{}))

很多朋友以为这段代码是“加密”的,其实这也谈不上是加密,只能算是一种编码(Encode)或者也可以成为是一种打包(packer),类似于base64这样的编码,都是可以以一定方式还原的,当然也就是“解密”了。

我们仔细分析这一段代码,不难发现代码开头都是eval,特征字符串是function(p,a,c,k,e,r)或者是function(p,a,c,k,e,d),其实这样的pack方式是dean edwards提出的,你可以访问其个人主页以获取这方面的最新信息。后来还有一些编码打包方式也是eval开头,但是特征字符串p,a,c,k,e,r(d)改变了,我们姑且称为是这种打包方式的一个变种吧,其实解码很简单,我们回顾一下JavaScript脚本中eval含义及用法。

检查 JavaScript 代码并执行。
eval(codeString)
必选项 codestring 参数是包含有效 JavaScript 代码的字符串值。这个字符串将由 JavaScript 分析器进行分析和执行。

其实就是调用JavaScript分析解释器处理有效的js脚本字符串,注意我这里提到的是字符串,有点类似于ASP的Execute方法。好,既然eval执行的字符串,那么function(p,a,c,k,e,r)函数肯定返回的是字符串,究竟是什么内容呢?你猜对了,就是我们要解码的源代码,其实function(p,a,c,k,e,r)相当于是个自解码函数,返回的就是解码好的源代码,然后传递给eval,那么这段解码后的字符串脚本就执行了。

到这里,突破点就有了,那就是function(p,a,c,k,e,r)这样的自解码函数,我们要获取其返回的字符串,怎么办?很简单,替换eval函数就可以了,比如替换成alert或者document.write,那么明文是不是显示出来了?刚开始讲到的代码可以变成这样:

1
2
3
4
5
6
7
8
9
10
alert(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,
'alert|Hello|World'.split('|'),0,{}))

很好,原文已经显示出来了,我们可以喝口水了,不过这样也不是很方便的哎,所以我专门写了个在线eval解密解码unpack的工具,大家可以访问这里来使用,哦,对了,针对多层编码的情况,我这里主要是判断开头eval实现的,另外还加入脚本格式化功能,便于解码后代码的阅读。(据网友反映:该在线工具目前在IE9和最新版FF6下工作正常,其他浏览器可能会有问题。不过我会尽快调查以解决该问题!)

若无特别说明,本网站文章均为原创,原则上这些文章不允许转载,但是如果阁下是出于研究学习目的可以转载到阁下的个人博客或者主页,转载遵循创作共同性“署名-非商业性使用-相同方式共享”原则,请转载时注明作者出处谢绝商业性、非署名、采集站、垃圾站或者纯粹为了流量的转载。谢谢合作!

    • 请使用IE9和最新版FF6浏览器,脚本在低版本的浏览器下可能无法正常运行。另外请确保要解码的脚本代码是完整正确的,不完整的代码片段也会导致解码出错。本解码仅支持eval(function(p,a,c,k,e……这种形式的编码方式。

  1. eval(102,117,110,99,116,105,111,110,32,99,104,101,99,107,40,41,123,13,10,09,118,97,114,32,97,32,61,32,39,100,52,103,39,59,13,10,09,105,102,40,100,111,99,117,109,101,110,116,46,103,101,116,69,108,101,109,101,110,116,66,121,73,100,40,39,116,120,116,39,41,46,118,97,108,117,101,61,61,97,41,123,13,10,09,09,119,105,110,100,111,119,46,108,111,99,97,116,105,111,110,46,104,114,101,102,61,97,43,34,46,112,104,112,34,59,13,10,09,125,101,108,115,101,123,13,10,09,09,97,108,101,114,116,40,34,23494,30721,38169,35823,34,41,59,13,10,09,125,13,10,125)
    这是怎么回事呢

    • 额,这种编码方式还真没注意过,我想如果这些数字是参数eval也接受不了这么数据吧,eval的函数原型是eval(string),其中string必需。是要计算的字符串,其中含有要计算的 JavaScript 表达式或要执行的语句。所以猜测可能是某种文本编码方式。

        • 我查了一下,这里逗号分隔的数字如果不理解为函数参数,可能是逗号表达式列表,关于逗号表达式可以参考MDN的Comma operator以及文章《The JavaScript Comma Operator》
          不过我把eval改成alert后只输出了数字102,不清楚你所使用的浏览器,我是在IE8下测试的。根据我测试的结果,这里应该还是参数列表,JavaScript对于无效的参数会丢弃,所以输出的是102,如果将这串逗号分隔的数字再括号起来,那么这里就应该看作是逗号表达式了,我测试了下在逗号表达式的情形下,alert会输出最右边的数字125,并没有输出文本形式。

请稍后...

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*