现在的位置: 首页 > IT运维 > 正文

function(p,a,c,k,e,d)解密

2013年05月19日 IT运维 ⁄ 共 3963字 暂无评论 ⁄ 被围观 14+

function(p,a,c,k,e,d)解密

上个月分析一网马时碰到的一脚本:

eval(function(p,a,c,k,e,d){e=function(c){return(c<a?\'\':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!\'\'.replace(/^/,String)){while(c--)d[e(c)]=k||e(c);k=[function(e){return d[e]}];e=function(){return\'\\w+\'};c=1};while(c--)if(k)p=p.replace(new RegExp(\'\\b\'+e(c)+\'\\b\',\'g\'),k);return p}(\'2.4("3://5.0.1")\',62,6,\'baidu|com|document|http|write|www\'.split(\'|\'),0,{}))

 

下面是详细分析。

先展开一下,这样写在一起不便于分析。

function(p,a,c,k,e,d)

{

e=function(c)   {   return(c<a?\'\':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))

};

if(!\'\'.replace(/^/,String))

{

while(c--)

d[e(c)]=k||e(c);

k=[function(e){returnd[e]}];

e=function()

{

return\'\\w+\'

};

c=1

};

while(c--)

if(k)p=p.replace(new RegExp(\'\\b\'+e(c)+\'\\b\',\'g\'),k);

return p

}(\'2.4("3://5.0.1")\',62,6,\'baidu|com|document|http|write|www\'.split(\'|\'),0,{}))

这样就比较清晰了,下面开始分析(为了让大家更好理解,修改了程序在firebug里截了几张图放在上面了)。

function(p,a,c,k,e,d) 是一个匿名函数,最后面括号里的内容是他的6个参数, (\'2.4("3://5.0.1")\',62,6,\'baidu|com|document|http|write|www\'.split(\'|\'),0, {}),最后一个参数传递的是一个花括号,在js里这是允许的,表示传递的是一个空的对象。String.split(\'|\')表示以这个符号将单词隔 开,其实也可以换成其他符号来分隔。

 

e=function(c)

{

return(c<a?\'\':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))

};

这 个函数实际上是一个62进制转换函数。e=function(c){…}函数一开始就给参数e赋值成一个函数,故参数e的原始值是无意义的,前面已经说了 参数e,一个空对象。另外,这里的参数名也是c,不要与(p,a,c,k,e,d)中的c混淆,二者作用域是不同的。函数返回值由2部分相加组成,

第1部分:(c<a? \'\' : e(parseInt(c/a)) )  如果c小于a,返回空串;否则返回e(c/a)

第2部分:((c=c%a)>35?         c=c%a,即保存余数。

String.fromCharCode(c+29)        返回余数加29后对应的字符;

:                              否则

c.toString(36))                   返回余数的36进制字符串

 

从整体上看,返回值是c对应的a(a=62)进制字符串,每个数位上可能的62个字符是\'0\',\'1\',\'2\'...\'9\',\'a\',\'b\'...\'z\',\'A\',\'B\',...\'Z\',正好是62个。有兴趣的可以自己多用几个数字测试一下。

 

继续看下面一部分。

if(!\'\'.replace(/^/,String))

{

 

}

摘自MSDN:

function replace(rgExp : RegExp, replaceText : String) : String

参数

rgExp

必 选。包含正则表达式模式和适用标志的 Regular Expression 对象的实例。也可以是 String 对象或文本。如果 rgExp 不是 Regular Expression 对象的实例,它将被转换为字符串,并对结果进行精确的搜索;字符串将不会被试图转化为正则表达式。

replaceText

必选。一个 String 对象或字符串文本,包含用于替换当前字符串对象中 rgExp 的每个成功匹配的文本。在 Jscript 5.5 或更高版本中,replaceText 参数也可是返回替换文本的函数。

if(!\'\'.replace(/^/,String)) 所以对于JScript 5.5以后,该判断总是为True,对于浏览器版本比较低的可能会返回FALSE,不过即使返回FALSE程序照样可以正常解码,后面再说。

 

while(c--)

d[e(c)]=k||e(c);  while循环填充了字典d的内容,d的原始值是空对象{}。

c是字典项数,原始值为8,k是字典单词列表,在本例中为[\'baidu\',\'com\',\'document\',\'http\', \'write\',\'www\'],

d[e(5)] = k[5]||e(5) -> d[\'5\'] = \'www\' || \'5\' -> d[\'5\'] = \'www\'

while循环结束后:

d[\'5\']=\'www\'

d[\'4\']=\'write\'

d[\'3\']=\'http\'

d[\'2\']=\'document\'

d[\'1\']=\'com\'

d[\'0\']=\'baidu\'

 

d 类似于stl的set容器的键值对,说类似于python中的dictionary可能更恰当点,即 d = { \'0\':\'baidu\', \'1\':\'com\', \'2\':\'document\', \'3\':\'http\', \'4\':\'write\', \'5\':\'www\' }。

 

k=[function(e){returnd[e]}];

e=function()

{

return\'\\w+\'                                  返回单词

};

c=1

这里给k赋值成一个数组, 只有一个元素k[0]。k[0]是个查字典函数,把参数作为索引,返回单词。如k[0](\'2\')返回d[\'2\'],即\'document\'。

 

while(c--)                                   由于c=1,循环体只执行1次

if(k)p=p.replace(new RegExp(\'\\b\'+e(c)+\'\\b\',\'g\'),k);             查字典替换

return p

最后就得到还原后的字符串了。

 

这 里提一下上面为什么最后有句c=1,前面已经提过,这里解释一下里面的玄机if(!\'\'.replace(/^/,String)) 这句无论执行成功失败,都能成功解码。这就是作者设计的巧妙的地方。考虑到现在大家的浏览器版本都比较高,不会出现返回FALSE的情况。代码还可以进一 步优化。

至于解码,就非常简单了,下面是解码代码:

function decode()

{

var code = document.getElementById(\'code\').value;

code = code.replace(/^eval/, \'\');

document.getElementById(\'code\').value = eval(code);

}

 

这段js加密代码运用比较广泛,不仅网马喜欢用它。正常网页也喜欢用,比如百度空间统计访问数量就用了他,搜狗云输入法里有它的影子。

 

最后感谢daishuo。

附:

下面一段是加密代码:

a=62; //加密标记

function encode()

{

var code = document.getElementById(\'code\').value;

code = code.replace(/[\\r\\n]+/g, \'\');//去掉回车换行

code = code.replace(/\'/g, "\'"); //单引号转义

var tmp = code.match(/\\b(\\w+)\\b/g); //匹配单词

tmp.sort(); //排序,后面处理单词会去掉重复的

var dict = [];

var i, t = \'\';

for(var i=0; i<tmp.length; i++){

if(tmp[i] != t)

dict.push(t = tmp[i]); //加到数组尾部

}

var len = dict.length; //数组长度,即项数

var ch;

for(i=0; i<len; i++)

{

ch = num(i);

code = code.replace(new RegExp(\'\\b\'+dict[i]+\'\\b\',\'g\'), ch);//将字典中的单词用字符62进制数字代替

if(ch == dict[i]) dict[i] = \'\';

}

给我留言

您必须 [ 登录 ] 才能发表留言!

×
#