引子
最近自己的一个小项目需要一些代理IP来测试,所以就去网上找了一下代理IP的网站。
然后就找到了 www.data5u.com 这个网站。它的首页提供20个免费ip。
手工一个一个拷贝当然可以,不过写个程序抓下来不是更好,而且还可以随时一键更新。(我真是太聪明了。)
然而用脚本抓下来的IP端口号与网站上显示的完全不一样啊,仔细研究以后才发现这一块加密了。
花了几天时间解密,所以就有了这篇文章。
初遇JS加密代码
通过用Fiddle4进行抓包,发现这个网址请求很可疑:www.data5u.com/theme/data5u/javascript/pde.js?v=1.0。
返回的内容是这样的:
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[c]||e(c);k=[function(e){return d[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;}('1M(17(p,a,c,k,e,r){e=17(c){18(c<a?\'\':e(1w(c/a)))+((c=c%a)>1s?1b.1r(c+1q):c.1v(1u))};19(!\'\'.1a(/^/,1b)){1c(c--)r[e(c)]=k[c]||e(c);k=[17(e){18 r[e]}];e=17(){18\'\\\\w+\'};c=1};1c(c--)19(k[c])p=p.1a(1t 1y(\'\\\\b\'+e(c)+\'\\\\b\',\'g\'),k[c]);18 p}(\'i h$=[\\\'\\\\E\\\\n\\\\x\\\\s\\\\j\\\',"\\\\l\\\\m\\\\v\\\\o","\\\\o\\\\j\\\\G\\\\p","\\\\r\\\\q\\\\H\\\\l\\\\I\\\\J\\\\K",\\\'\\\\M\\\',"\\\\m\\\\j\\\\j\\\\s",\\\'\\\\v\\\\p\\\\m\\\\k\\\\k\\\',"\\\\k\\\\n\\\\p\\\\r\\\\j","\\\\O","","\\\\p\\\\l\\\\q\\\\Q\\\\j\\\\o","\\\\n\\\\R\\\\k\\\\o",\\\'\\\\S\\\\T\\\\V\\\\z\\\\A\\\\B\\\\C\\\\D\\\\u\\\\F\\\',"\\\\n\\\\m\\\\s\\\\k\\\\l\\\\u\\\\q\\\\j","\\\\16\\\\x\\\\r\\\\q",\\\'\\\'];$(y(){$(h$[0])[h$[1]](y(){i a=$(t)[h$[2]]();L(a[h$[3]](h$[4])!=-w){N};i b=$(t)[h$[5]](h$[6]);P{b=(b[h$[7]](h$[8]))[w];i c=b[h$[7]](h$[9]);i d=c[h$[10]];i f=[];U(i g=W;g<d;g++){f[h$[11]](h$[12][h$[3]](c[g]))};$(t)[h$[2]](X[h$[13]](f[h$[14]](h$[15]))>>Y)}Z(e){}})})\',1A,1B,\'|||||||||||||||||1C|1x|1z|1p|1h|1i|1d|1e|1f|1m|1n|1o|1g|1k|1l|1j|1W|17|1X|1Y|1V|1S|1T|1U|1Z|23|25|24|20|21|19|22|18|1R|1H|1I|1J|1G|1D|1E|1F|1O|1P|1Q|1N|||||||1K\'.1L(\'|\'),0,{}))',62,130,'|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||function|return|if|replace|String|while|x70|x68|x6c|this|x65|x61|0x1|x49|x63|x6e|x69|x72|x73|29|fromCharCode|35|new|36|toString|parseInt|var|RegExp|x74|62|69|_|x42|for|x43|x41|try|x67|x75|x6a|split|eval|catch|0x0|window|0x3|x20|x47|x48|x2e|x46|x6f|x44|x45|x5a|x4f|x66|x2a|x6d|x78|x64'.split('|'),0,{}))
直接懵逼是吧。
别慌,慢慢来。
JS代码破解
其实这类加密的破解思路就是:见eval就去掉。
首先,我们把之前那段代码去掉eval扔到浏览器的console里执行一下:
这时我们得到的新代码是:
eval(function(p,a,c,k,e,r){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--)r[e(c)]=k[c]||e(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}('i h$=[\'\\E\\n\\x\\s\\j\',"\\l\\m\\v\\o","\\o\\j\\G\\p","\\r\\q\\H\\l\\I\\J\\K",\'\\M\',"\\m\\j\\j\\s",\'\\v\\p\\m\\k\\k\',"\\k\\n\\p\\r\\j","\\O","","\\p\\l\\q\\Q\\j\\o","\\n\\R\\k\\o",\'\\S\\T\\V\\z\\A\\B\\C\\D\\u\\F\',"\\n\\m\\s\\k\\l\\u\\q\\j","\\16\\x\\r\\q",\'\'];$(y(){$(h$[0])[h$[1]](y(){i a=$(t)[h$[2]]();L(a[h$[3]](h$[4])!=-w){N};i b=$(t)[h$[5]](h$[6]);P{b=(b[h$[7]](h$[8]))[w];i c=b[h$[7]](h$[9]);i d=c[h$[10]];i f=[];U(i g=W;g<d;g++){f[h$[11]](h$[12][h$[3]](c[g]))};$(t)[h$[2]](X[h$[13]](f[h$[14]](h$[15]))>>Y)}Z(e){}})})',62,69,'|||||||||||||||||_|var|x74|x73|x65|x61|x70|x68|x6c|x6e|x69|x72|this|x49|x63|0x1|x6f|function|x44|x45|x46|x47|x48|x2e|x5a|x6d|x64|x78|x4f|x66|if|x2a|return|x20|try|x67|x75|x41|x42|for|x43|0x0|window|0x3|catch|||||||x6a'.split('|'),0,{}))
接着去eval:
得到的新代码格式化后就是这样:
var _$ = ['\x2e\x70\x6f\x72\x74', "\x65\x61\x63\x68", "\x68\x74\x6d\x6c", "\x69\x6e\x64\x65\x78\x4f\x66", '\x2a', "\x61\x74\x74\x72", '\x63\x6c\x61\x73\x73', "\x73\x70\x6c\x69\x74", "\x20", "", "\x6c\x65\x6e\x67\x74\x68", "\x70\x75\x73\x68", '\x41\x42\x43\x44\x45\x46\x47\x48\x49\x5a', "\x70\x61\x72\x73\x65\x49\x6e\x74", "\x6a\x6f\x69\x6e", ''];
$(function() {
$(_$[0])[_$[1]](function() {
var a = $(this)[_$[2]]();
if (a[_$[3]](_$[4]) != -0x1) {
return
};
var b = $(this)[_$[5]](_$[6]);
try {
b = (b[_$[7]](_$[8]))[0x1];
var c = b[_$[7]](_$[9]);
var d = c[_$[10]];
var f = [];
for (var g = 0x0; g < d; g++) {
f[_$[11]](_$[12][_$[3]](c[g]))
};
$(this)[_$[2]](window[_$[13]](f[_$[14]](_$[15])) >> 0x3)
} catch(e) {}
})
})
嗯,已经基本可读了吧。
不过第一行是什么鬼,也扔到浏览器里看看:
哦,原来是一个字符串数组啊(\x2e
这类的是ASCII的16进制表示),结合下面的代码可以猜出是用来做替换的。
好,手工做下替换:
$(function() {
$('.port')['each'](function() {
var a = $(this)['html']();
if (a['indexOf']('*') != -0x1) {
return
};
var b = $(this)["attr"]("class");
try {
b = (b["split"](" "))[0x1];
var c = b["split"]("");
var d = c["length"];
var f = [];
for (var g = 0x0; g < d; g++) {
f["push"]("ABCDEFGHIZ"["indexOf"](c[g]))
};
$(this)["html"](window["parseInt"](f["join"]("")) >> 0x3)
} catch(e) {}
})
})
主体函数已经破解出来了。怎么样,知道了思路,其实破解还是挺容易的吧。
明天继续,大家如有问题可以留言。