sojson.v5 加密算法分析

以下为 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 代码结构。好了,暂且分析这么多...
赞(0) 打赏
取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

    暂无评论...