以下为 sojson.v5 加密的一段 JS 代码,觉得颇有想法,分析如下
先贴上加密后的代码:
;var encode_version = 'sojson.v5', gnppc = '', _0x2fe8=['LGBiw4k1cA==','fsO2wqxcJFBm','DMKyw7jDoTh3B1gG','CsKzw7bDtzFwR0tX','N8OZw49Xwq4=','5LmY6IGJ5YqS6ZiXYxXDtWQ+wph0fk0=','wpgyLnc='];(function(_0x214fce,_0x478cbd){var _0x3ed235=function(_0x2df8c2){while(--_0x2df8c2){_0x214fce['push'](_0x214fce['shift']());}};_0x3ed235(++_0x478cbd);}(_0x2fe8,0xbc));var _0x769b=function(_0x11b350,_0x54cb55){_0x11b350=_0x11b350-0x0;var _0x158905=_0x2fe8[_0x11b350];if(_0x769b['initialized']===undefined){(function(){var _0x112b73=typeof window!=='undefined'?window:typeof process==='object'&&typeof require==='function'&&typeof global==='object'?global:this;var _0x1877d5='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';_0x112b73['atob']||(_0x112b73['atob']=function(_0x427506){var _0x57cf5e=String(_0x427506)['replace'](/=+$/,'');for(var _0xa01407=0x0,_0x8e1ee7,_0x5b0908,_0x5ccd63=0x0,_0x1ece14='';_0x5b0908=_0x57cf5e['charAt'](_0x5ccd63++);~_0x5b0908&&(_0x8e1ee7=_0xa01407%0x4?_0x8e1ee7*0x40+_0x5b0908:_0x5b0908,_0xa01407++%0x4)?_0x1ece14+=String['fromCharCode'](0xff&_0x8e1ee7>>(-0x2*_0xa01407&0x6)):0x0){_0x5b0908=_0x1877d5['indexOf'](_0x5b0908);}return _0x1ece14;});}());var _0x26fda9=function(_0xd0f609,_0x733185){var _0x5940da=[],_0x13cd6f=0x0,_0xdb599d,_0x31a8ae='',_0xe7fbe6='';_0xd0f609=atob(_0xd0f609);for(var _0x501ebb=0x0,_0x15d71e=_0xd0f609['length'];_0x501ebb<_0x15d71e;_0x501ebb++){_0xe7fbe6+='%'+('00'+_0xd0f609['charCodeAt'](_0x501ebb)['toString'](0x10))['slice'](-0x2);}_0xd0f609=decodeURIComponent(_0xe7fbe6);for(var _0x352bd8=0x0;_0x352bd8<0x100;_0x352bd8++){_0x5940da[_0x352bd8]=_0x352bd8;}for(_0x352bd8=0x0;_0x352bd8<0x100;_0x352bd8++){_0x13cd6f=(_0x13cd6f+_0x5940da[_0x352bd8]+_0x733185['charCodeAt'](_0x352bd8%_0x733185['length']))%0x100;_0xdb599d=_0x5940da[_0x352bd8];_0x5940da[_0x352bd8]=_0x5940da[_0x13cd6f];_0x5940da[_0x13cd6f]=_0xdb599d;}_0x352bd8=0x0;_0x13cd6f=0x0;for(var _0x11c9a3=0x0;_0x11c9a3<_0xd0f609['length'];_0x11c9a3++){_0x352bd8=(_0x352bd8+0x1)%0x100;_0x13cd6f=(_0x13cd6f+_0x5940da[_0x352bd8])%0x100;_0xdb599d=_0x5940da[_0x352bd8];_0x5940da[_0x352bd8]=_0x5940da[_0x13cd6f];_0x5940da[_0x13cd6f]=_0xdb599d;_0x31a8ae+=String['fromCharCode'](_0xd0f609['charCodeAt'](_0x11c9a3)^_0x5940da[(_0x5940da[_0x352bd8]+_0x5940da[_0x13cd6f])%0x100]);}return _0x31a8ae;};_0x769b['rc4']=_0x26fda9;_0x769b['data']={};_0x769b['initialized']=!![];}var _0x15bdef=_0x769b['data'][_0x11b350];if(_0x15bdef===undefined){if(_0x769b['once']===undefined){_0x769b['once']=!![];}_0x158905=_0x769b['rc4'](_0x158905,_0x54cb55);_0x769b['data'][_0x11b350]=_0x158905;}else{_0x158905=_0x15bdef;}return _0x158905;};(function(_0x2511be,_0xfd7278){_0x2511be[_0x769b('0x0','CnJU')]='a';_0xfd7278[_0x769b('0x1','ZfFO')]='b';_0xfd7278[_0x769b('0x2','(UOg')]='c';}(window,document));;if(!(typeof encode_version!==_0x769b('0x3','TpgB')&&encode_version===_0x769b('0x4','TpgB'))){window[_0x769b('0x5','I27i')](_0x769b('0x6','Q6Tv'));};encode_version = 'sojson.v5';
经过代码美化,修改混淆变量,改善了可阅读性
var encode_version = 'sojsonE.v5',
azjqh = '',
jstext = ['LGBiw4k1cA==','fsO2wqxcJFBm','DMKyw7jDoTh3B1gG','CsKzw7bDtzFwR0tX','N8OZw49Xwq4=','5LmY6IGJ5YqS6ZiXYxXDtWQ+wph0fk0=','wpgyLnc='];
(function(temp, x) {
var cover = function(i) {
while (--i) {
temp['push'](temp['shift']());
}
};
cover(++x);
} (jstext, 0xbc));
var jsbeat = function(id, key) {
id = id - 0x0;
var base = jstext[id];
if (jsbeat['initialized'] === undefined) {
(function() {
// 定义 atob
var temp = typeof window !== 'undefined' ? window: typeof process === 'object' && typeof require === 'function' && typeof global === 'object' ? global: this;
var char = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
temp['atob'] || (temp['atob'] = function(encodedData) {
var encodedData = String(encodedData)['replace'](/=+$/, '');
for (var i = 0x0,
j, t, k = 0x0,
c = ''; t = encodedData['charAt'](k++);~t && (j = i % 0x4 ? j * 0x40 + t: t, i++%0x4) ? c += String['fromCharCode'](0xff & j >> ( - 0x2 * i & 0x6)) : 0x0) {
t = char['indexOf'](t);
}
return c;
});
} ());
var rc4 = function(code, key) {
var a = [],
b = 0x0,
c,
result = '',
decode = '';
code = atob(code);
// 转换成 URI 编码
for (var i = 0x0, j = code['length']; i < j; i++) {
decode += '%' + ('00' + code['charCodeAt'](i)['toString'](0x10))['slice']( - 0x2);
}
code = decodeURIComponent(decode);
// RC4 加解密
for (var i = 0; i < 256; i++) {
a[i] = i;
}
for (i = 0x0; i < 0x100; i++) {
b = (b + a[i] + key['charCodeAt'](i % key['length'])) % 0x100;
c = a[i];
a[i] = a[b];
a[b] = c;
}
i = 0x0;
b = 0x0;
for (var j = 0x0; j < code['length']; j++) {
i = (i + 0x1) % 0x100;
b = (b + a[i]) % 0x100;
c = a[i];
a[i] = a[b];
a[b] = c;
result += String['fromCharCode'](code['charCodeAt'](j) ^ a[(a[i] + a[b]) % 0x100]);
}
return result;
};
jsbeat['rc4'] = rc4;
jsbeat['data'] = {};
jsbeat['initialized'] = !![];
}
var value = jsbeat['data'][id];
if (value === undefined) {
if (jsbeat['once'] === undefined) {
jsbeat['once'] = !![];
}
base = jsbeat['rc4'](base, key);
jsbeat['data'][id] = base;
} else {
base = value;
}
return base;
};
if (! (typeof encode_version !== jsbeat('0x3', 'TpgB') && encode_version === jsbeat('0x4', 'TpgB'))) {
window[jsbeat('0x5', 'I27i')](jsbeat('0x6', 'Q6Tv'));
};
encode_version = 'sojson.v5';
该加密主要是将 JS 要混淆的代码变量通过 RC4
加密后,储存在 jstext
数组变量中,然后再经过 jsbeat
函数还原即可。
如果想删除掉 不能删除sojson.v5
其实也很简单,只要删除掉类似以下代码即可(每次加密的数据是不一样的)
if (! (typeof encode_version !== jsbeat('0x3', 'TpgB') && encode_version === jsbeat('0x4', 'TpgB'))) {
window[jsbeat('0x5', 'I27i')](jsbeat('0x6', 'Q6Tv'));
};
还有通过 switch
功能打乱程序执行顺序,对照代码如下:
// 源代码
(function resize() {
window.onresize = arguments.callee;
w = window.innerWidth;
h = window.innerHeight;
can.width = window.innerWidth;
can.height = window.innerHeight;
l = Math.random();
o = 5 + 6;
})();
// 加密后
(function resize() {
var _0x4deafe = {
'Ogewt': '0|5|6|1|4|2|3',
'NHbbY': function _0x17198e(_0x51f65f, _0x2414cf) {
return _0x51f65f + _0x2414cf;
}
};
var _0x64bbb2 = (_0x4deafe['Ogewt'])['split']('|'),
_0x5b9b75 = 0;
while ( !! []) {
switch (_0x64bbb2[_0x5b9b75++]) {
case '0':
window['onresize'] = arguments['callee'];
continue;
case '1':
can['width'] = window['innerWidth'];
continue;
case '2':
l = Math['random']();
continue;
case '3':
o = _0x4deafe['NHbbY'](5, 6);
continue;
case '4':
can['height'] = window['innerHeight'];
continue;
case '5':
w = window['innerWidth'];
continue;
case '6':
h = window['innerHeight'];
continue;
};
break;
};
})();
可以看出它使用了 case
调整了程序执行顺序,_0x4deafe
变量是关键,它可用来解密和恢复,通过提取 case
代码块按 '0|5|6|1|4|2|3'
顺序排列基本上就还原了代码
后话:
这种加密方法,虽不说能百分百还原,但百分八、九十能读懂正常执行就差不多了,它本身采用的应该是语法树结构混淆方法,打乱了原有的 JS 代码结构。好了,暂且分析这么多...