JavaScript逆向之手撸ob混淆

ob混淆

ob混淆是JavaScript混淆中的一种方法,是指将JavaScript代码中的变量名、函数名、字符串等替换为无意义的字符串,从而增加代码的保护性和防止代码的逆向分析。此外,它还可以在代码中添加死代码、无用的函数等,增加代码的复杂度和难以理解性,从而增加代码的保密性。

实战案例——艺恩

url:https://www.endata.com.cn/BoxOffice/BO/Year/index.html
访问页面,随便选择一个年份,抓包,看触发的数据包。

就只有一个GetData.ashx数据包,看下它的payload和response。


payload中有两个参数yearMethodNameyear就是你当前所查找的年份,MethodName就是触发的方法,这两个参数都是明文,不需要逆向。response中的响应数据看一下它的组成,是由0-9a-f组成,大概率是个16进制字符串,所以这段字符串就是我们需要逆向的。通过搜索url关键词,来定位。

只有一处,点进去,看下代码。

是个ajax请求,前面的参数就没有什么好说的了,重点关注success方法中的1 == (e = "{" == e[0] ? JSON.parse(e) : JSON.parse(webInstace.shell(e))).Status || 200 == e.Code ? r(e.Data) : 200 == e.code ? r(e.data) : a(e.Msg)这行代码。先来解释下这句代码的执行过程,大致分为四部分:
(1)1 == (e = "{" == e[0] ? JSON.parse(e) : JSON.parse(webInstace.shell(e))).Status:先判断e[0]和"{"是否相等,再判断ee[0]=="{"的结果是否相等,如果相等,则将1和JSON.parse(e).Status进行判断;如果不相等,则将1和JSON.parse(webInstace.shell(e)).Status进行判断。
(2)200 == e.Code:判断e.code和200是否相等。
(3)r(e.Data):上述两个条件只要有一个为真,就执行这句话。
(3)200 == e.code ? r(e.data) : a(e.Msg):如果(1)和(2)都为假,就执行这句话。判断e.code是否等于200,如果为真,执行r(e.data);如果不为真,就执行a(e.Msg)
逻辑搞清楚了,打断点,运行,让程序停在这里。

看下变量e的值。

根据e的值,就可以知道(1)这部分语句执行的是JSON.parse(webInstace.shell(e)).Status这句话,运行一下,看结果。

跟"1"相等,所以最终执行的是r(e.Data),定位到r函数的实现位置。

但是r函数内容没有加密的逻辑,所以找错地方了。再返回去找,前面的判断语句只有一处的代码实现不理解,就是webInstace.shell这个函数是怎么实现的,定位一下。

这段代码中出现了许多的花指令,都是吓唬你的,我们把这段代码摘出来分析一下。

function(_0xa0c834) {
        var _0x51eedc = {
            'pKENi': function _0x2f627(_0x5b6f5a, _0x440924) {
                return _0x5b6f5a === _0x440924;
            },
            'wnfPa': 'ZGz',
            'VMmle': '7|1|8|9|5|2|3|6|0|4',
            'GKWFf': function _0x1a4e13(_0x40cfde, _0x16f3c2) {
                return _0x40cfde == _0x16f3c2;
            },
            'MUPgQ': function _0x342f0d(_0x19038b, _0x4004d6) {
                return _0x19038b >= _0x4004d6;
            },
            'hLXma': function _0x55adaf(_0x45a871, _0x161bdf) {
                return _0x45a871 + _0x161bdf;
            },
            'JdOlO': function _0x13e00a(_0x5899a9, _0x4bb34d) {
                return _0x5899a9 + _0x4bb34d;
            },
            'qrTpg': function _0x1198fb(_0x55b317, _0x22e1db, _0x1b091a) {
                return _0x55b317(_0x22e1db, _0x1b091a);
            },
            'pdmMk': function _0xe2b022(_0x4af286, _0x4c2fd4) {
                return _0x4af286 - _0x4c2fd4;
            },
            'xVKWW': function _0x1094a3(_0x5f3627, _0x2a0ac5, _0x3ad2e5) {
                return _0x5f3627(_0x2a0ac5, _0x3ad2e5);
            }
        };
        if (_0x51eedc[_0x2246('0x258', '@1Ws')](_0x2246('0x259', 'E&PI'), _0x51eedc['wnfPa'])) {
            this['_append'](a);
            return this[_0x2246('0x25a', 'GL3Q')]();
        } else {
            var _0x492a62 = _0x51eedc[_0x2246('0x25b', '&59Q')][_0x2246('0x25c', ')q#9')]('|')
              , _0x356b01 = 0x0;
            while (!![]) {
                switch (_0x492a62[_0x356b01++]) {
                case '0':
                    _0x554c90 = _grsa_JS[_0x2246('0x25d', 'E&PI')]['decrypt']({
                        'ciphertext': _grsa_JS['enc'][_0x2246('0x25e', 'sy^o')]['parse'](_0xa0c834)
                    }, _0x2cf8ae, {
                        'iv': _0x554c90,
                        'mode': _grsa_JS[_0x2246('0x16c', 'O^50')][_0x2246('0x25f', 'Who^')],
                        'padding': _grsa_JS[_0x2246('0x260', '7IfV')][_0x2246('0x261', 'E&PI')]
                    })[_0x2246('0x1c', 'yY#5')](_grsa_JS['enc'][_0x2246('0x262', ']2BX')]);
                    continue;
                case '1':
                    if (_0x51eedc[_0x2246('0x263', 'Jsmq')](null, _0xa0c834) || _0x51eedc[_0x2246('0x264', '!2eC')](0x10, _0xa0c834['length']))
                        return _0xa0c834;
                    continue;
                case '2':
                    _0xa0c834 = _0x9843d3(_0xa0c834, _0x2cf8ae, 0x8);
                    continue;
                case '3':
                    _0x2cf8ae = _grsa_JS[_0x2246('0x265', 'RQ2o')][_0x2246('0x266', '3j7z')][_0x2246('0x267', 'RQ2o')](_0x554c90);
                    continue;
                case '4':
                    return _0x554c90[_0x2246('0x268', 'cs*4')](0x0, _0x51eedc[_0x2246('0x269', 'MVsm')](_0x554c90[_0x2246('0x26a', '0J6f')]('}'), 0x1));
                case '5':
                    _0x554c90 = _0xa0c834[_0x2246('0x26b', 'UwHa')](_0x2cf8ae, 0x8);
                    continue;
                case '6':
                    _0x554c90 = _grsa_JS[_0x2246('0x26c', '4VZ$')]['Utf8']['parse'](_0x554c90);
                    continue;
                case '7':
                    if (!navigator || !navigator[_0x2246('0x26d', '0I#o')])
                        return '';
                    continue;
                case '8':
                    var _0x554c90 = _0x51eedc[_0x2246('0x26e', 'Yb4P')](_0x51eedc[_0x2246('0x26f', 'BQ5p')](parseInt, _0xa0c834[_0x51eedc[_0x2246('0x270', 'Z2VK')](_0xa0c834['length'], 0x1)], 0x10), 0x9)
                      , _0x2cf8ae = _0x51eedc[_0x2246('0x271', 'yY#5')](parseInt, _0xa0c834[_0x554c90], 0x10);
                    continue;
                case '9':
                    _0xa0c834 = _0x9843d3(_0xa0c834, _0x554c90, 0x1);
                    continue;
                }
                break;
            }
        }
    }

这段代码中就出现了非常明显的ob混淆的特征:第一个就是会有一个大号数组,里面的内容大概率是类似base64的东西,例如代码中的_0x51eedc;第二个就是会有一个还原数组正确顺序的操作,例如代码中的VMmle。由于_0x51eedc只是声明的一个数组,暂时先不看。先看if中的条件语句_0x51eedc[_0x2246('0x258', '@1Ws')](_0x2246('0x259', 'E&PI'), _0x51eedc['wnfPa']),把其中的变量先还原一下,去console中看看对应的值是什么。

那么_0x51eedc[_0x2246('0x258', '@1Ws')](_0x2246('0x259', 'E&PI'), _0x51eedc['wnfPa'])相当于_0x51eedc['pKENi']('tgg', _0x51eedc['wnfPa']),其中_0x51eedc是声明的数组,那就找_0x51eedc['pKENi']是什么。'pKENi': function _0x2f627(_0x5b6f5a, _0x440924) { return _0x5b6f5a === _0x440924;},,这是用来判断所传的两个参数是否相等的,其中一个参数是tgg,另一个是_0x51eedc['wnfPa'],也就是ZGz,这两个肯定不相等,所以执行的一定是else里面的代码,if中的代码就废了。接下来看else中的代码。

var _0x492a62 = _0x51eedc[_0x2246('0x25b', '&59Q')][_0x2246('0x25c', ')q#9')]('|')
          , _0x356b01 = 0x0;
        while (!![]) {
            switch (_0x492a62[_0x356b01++]) {
            case '0':
                _0x554c90 = _grsa_JS[_0x2246('0x25d', 'E&PI')]['decrypt']({
                    'ciphertext': _grsa_JS['enc'][_0x2246('0x25e', 'sy^o')]['parse'](_0xa0c834)
                }, _0x2cf8ae, {
                    'iv': _0x554c90,
                    'mode': _grsa_JS[_0x2246('0x16c', 'O^50')][_0x2246('0x25f', 'Who^')],
                    'padding': _grsa_JS[_0x2246('0x260', '7IfV')][_0x2246('0x261', 'E&PI')]
                })[_0x2246('0x1c', 'yY#5')](_grsa_JS['enc'][_0x2246('0x262', ']2BX')]);
                continue;
            case '1':
                if (_0x51eedc[_0x2246('0x263', 'Jsmq')](null, _0xa0c834) || _0x51eedc[_0x2246('0x264', '!2eC')](0x10, _0xa0c834['length']))
                    return _0xa0c834;
                continue;
            case '2':
                _0xa0c834 = _0x9843d3(_0xa0c834, _0x2cf8ae, 0x8);
                continue;
            case '3':
                _0x2cf8ae = _grsa_JS[_0x2246('0x265', 'RQ2o')][_0x2246('0x266', '3j7z')][_0x2246('0x267', 'RQ2o')](_0x554c90);
                continue;
            case '4':
                return _0x554c90[_0x2246('0x268', 'cs*4')](0x0, _0x51eedc[_0x2246('0x269', 'MVsm')](_0x554c90[_0x2246('0x26a', '0J6f')]('}'), 0x1));
            case '5':
                _0x554c90 = _0xa0c834[_0x2246('0x26b', 'UwHa')](_0x2cf8ae, 0x8);
                continue;
            case '6':
                _0x554c90 = _grsa_JS[_0x2246('0x26c', '4VZ$')]['Utf8']['parse'](_0x554c90);
                continue;
            case '7':
                if (!navigator || !navigator[_0x2246('0x26d', '0I#o')])
                    return '';
                continue;
            case '8':
                var _0x554c90 = _0x51eedc[_0x2246('0x26e', 'Yb4P')](_0x51eedc[_0x2246('0x26f', 'BQ5p')](parseInt, _0xa0c834[_0x51eedc[_0x2246('0x270', 'Z2VK')](_0xa0c834['length'], 0x1)], 0x10), 0x9)
                  , _0x2cf8ae = _0x51eedc[_0x2246('0x271', 'yY#5')](parseInt, _0xa0c834[_0x554c90], 0x10);
                continue;
            case '9':
                _0xa0c834 = _0x9843d3(_0xa0c834, _0x554c90, 0x1);
                continue;
            }
            break;
        }

先把其中的以_0x2246开头的去console中输出结果还原一下,还原结果如下:

var _0x492a62 = _0x51eedc['VMmle']['split']('|')
          , _0x356b01 = 0x0;
        while (!![]) {
            switch (_0x492a62[_0x356b01++]) {
            case '0':
                _0x554c90 = _grsa_JS['DES']['decrypt']({
                    'ciphertext': _grsa_JS['enc']['Hex']['parse'](_0xa0c834)
                }, _0x2cf8ae, {
                    'iv': _0x554c90,
                    'mode': _grsa_JS['mode']['ECB'],
                    'padding': _grsa_JS['pad']['Pkcs7']
                })['toString'](_grsa_JS['enc']['Utf8']);
                continue;
            case '1':
                if (_0x51eedc['GKWFf'](null, _0xa0c834) || _0x51eedc['MUPgQ'](0x10, _0xa0c834['length']))
                    return _0xa0c834;
                continue;
            case '2':
                _0xa0c834 = _0x9843d3(_0xa0c834, _0x2cf8ae, 0x8);
                continue;
            case '3':
                _0x2cf8ae = _grsa_JS['enc']['Utf8']['parse'](_0x554c90);
                continue;
            case '4':
                return _0x554c90['substring'](0x0, _0x51eedc['hLXma'](_0x554c90['lastIndexOf']('}'), 0x1));
            case '5':
                _0x554c90 = _0xa0c834['substr'](_0x2cf8ae, 0x8);
                continue;
            case '6':
                _0x554c90 = _grsa_JS['enc']['Utf8']['parse'](_0x554c90);
                continue;
            case '7':
                if (!navigator || !navigator['userAgent'])
                    return '';
                continue;
            case '8':
                var _0x554c90 = _0x51eedc['JdOlO'](_0x51eedc['qrTpg'](parseInt, _0xa0c834[_0x51eedc['pdmMk'](_0xa0c834['length'], 0x1)], 0x10), 0x9)
                  , _0x2cf8ae = _0x51eedc['xVKWW'](parseInt, _0xa0c834[_0x554c90], 0x10);
                continue;
            case '9':
                _0xa0c834 = _0x9843d3(_0xa0c834, _0x554c90, 0x1);
                continue;
            }
            break;
        }

先看第一句var _0x492a62 = _0x51eedc['VMmle']['split']('|') , _0x356b01 = 0x0;_0x51eedc['VMmle']就是字符串'7|1|8|9|5|2|3|6|0|4',那么这句话就是把'7|1|8|9|5|2|3|6|0|4'按照|进行分割,_0x492a62 得到的就是一个数组,_0x356b01 赋值为0。
接着看while (!![]),把!![]在console中输出一下值为true,那就会进入循环里面。switch (_0x492a62[_0x356b01++])先看_0x492a62[_0x356b01++],这是从索引0开始取_0x492a62数组中的值的,所以拿到的顺序就是7、1、8、9、5、2、3、6、0、4,这样的话,我们就可以把下面的case语句重新排个序了,如下:

    if (!navigator || !navigator['userAgent'])
                    return '';
    if (_0x51eedc['GKWFf'](null, _0xa0c834) || _0x51eedc['MUPgQ'](0x10, _0xa0c834['length']))
                    return _0xa0c834;
    var _0x554c90 = _0x51eedc['JdOlO'](_0x51eedc['qrTpg'](parseInt, _0xa0c834[_0x51eedc['pdmMk'](_0xa0c834['length'], 0x1)], 0x10), 0x9)
                  , _0x2cf8ae = _0x51eedc['xVKWW'](parseInt, _0xa0c834[_0x554c90], 0x10);
    _0xa0c834 = _0x9843d3(_0xa0c834, _0x554c90, 0x1);
    _0x554c90 = _0xa0c834['substr'](_0x2cf8ae, 0x8);
    _0xa0c834 = _0x9843d3(_0xa0c834, _0x2cf8ae, 0x8);
    _0x2cf8ae = _grsa_JS['enc']['Utf8']['parse'](_0x554c90);
    _0x554c90 = _grsa_JS['enc']['Utf8']['parse'](_0x554c90);
    _0x554c90 = _grsa_JS['DES']['decrypt']({
                    'ciphertext': _grsa_JS['enc']['Hex']['parse'](_0xa0c834)
                }, _0x2cf8ae, {
                    'iv': _0x554c90,
                    'mode': _grsa_JS['mode']['ECB'],
                    'padding': _grsa_JS['pad']['Pkcs7']
                })['toString'](_grsa_JS['enc']['Utf8']);
    return _0x554c90['substring'](0x0, _0x51eedc['hLXma'](_0x554c90['lastIndexOf']('}'), 0x1));

看第一个if判断语句,navigator其实是window.navigator,在控制台输出一下。

所以navigatornavigator['userAgent']都不为空,第一个if判断语句不会执行。
看第二个if判断语句,一个条件语句是_0x51eedc['GKWFf'](null, _0xa0c834),另一个是_0x51eedc['MUPgQ'](0x10, _0xa0c834['length'])。其中_0x51eedc['GKWFf']函数是用来判断所传的两个参数是否相等的,_0x51eedc['MUPgQ']函数是用来判断所传的两个参数,第一个参数是否大于等于第二个参数的。_0xa0c834就是我们调用该函数是传递进来的数据,也就是变量e,在上文中已经查看过值了,明显不为空,且长度大于16,所以第二个if判断语句也不会执行。
下面就一行一行代码来解析了。为了讲解方便,我们将_0xa0c834全部替换成mi,该变量就是传给整个函数的数据。
(1)var _0x554c90 = _0x51eedc['JdOlO'](_0x51eedc['qrTpg'](parseInt, a[_0x51eedc['pdmMk'](mi['length'], 0x1)], 0x10), 0x9):从里往外,先看_0x51eedc['pdmMk'](mi['length'], 0x1)_0x51eedc['pdmMk']函数把所传的参数做减法,化简一下就是mi['length']-1_0x51eedc['qrTpg']函数用于将后两个参数传给第一个参数做运算,故_0x51eedc['qrTpg'](parseInt, mi[_0x51eedc['pdmMk'](mi['length'], 0x1)], 0x10其实就是parseInt(mi[mi['length']-1],16);_0x51eedc['JdOlO']函数用于将所传的两个参数做加法,故整句话的化简下来就是var _0x554c90 = parseInt(mi[mi['length']- 1], 16) + 9
(2)_0x2cf8ae = _0x51eedc['xVKWW'](parseInt, mi[_0x554c90], 0x10);:看_0x51eedc['xVKWW']函数的作用,将后两个参数作为第一个参数的参数,化简就是_0x2cf8ae = parseInt(mi[_0x554c90], 16)
(3)mi = _0x9843d3(mi, _0x554c90, 0x1):先看_0x9843d3的实现过程,具体代码如下:

var _0x9843d3 = function(_0x29d556, _0xcc6df, _0x3d7020) {
        if (0x0 == _0xcc6df)
            return _0x29d556[_0x2246('0x254', '4VZ$')](_0x3d7020);
        var _0x48914b;
        _0x48914b = '' + _0x29d556[_0x2246('0x255', 'GL3Q')](0x0, _0xcc6df);
        return _0x48914b += _0x29d556['substr'](_0x4da59e[_0x2246('0x256', 'DK[&')](_0xcc6df, _0x3d7020));
    };

先判断第二个参数是否为0,如果为0,执行return的语句,不为0就往下执行。这里传过来的第二个参数是(1)的执行结果,不可能为0,所以return语句就不用管了,往下看。
把其中以_0x2246的表达式先替换一下,如下:

var _0x9843d3 = function(_0x29d556, _0xcc6df, _0x3d7020) {
        var _0x48914b;
        _0x48914b = '' + _0x29d556['substr'](0x0, _0xcc6df);
        return _0x48914b += _0x29d556['substr'](_0x4da59e['bUIIa'](_0xcc6df, _0x3d7020));
    };

其中_0x4da59e['bUIIa']函数的实现如下:

就是一个加法,所以_0x9843d3函数就是一个截取字符串的操作。
(4)_0x554c90 = mi['substr'](_0x2cf8ae, 0x8):也是一个截取字符串的操作
(5)mi = _0x9843d3(mi, _0x2cf8ae, 0x8):也是一个截图字符串的操作
(6)_0x2cf8ae = _grsa_JS['enc']['Utf8']['parse'](_0x554c90):一个编码操作。
(7)_0x554c90 = _grsa_JS['enc']['Utf8']['parse'](_0x554c90):一个编码操作。
(8)_0x554c90 = _grsa_JS['DES']['decrypt']({ 'ciphertext': _grsa_JS['enc']['Hex']['parse'](mi) }, _0x2cf8ae, { 'iv': _0x554c90, 'mode': _grsa_JS['mode']['ECB'], 'padding': _grsa_JS['pad']['Pkcs7'] })['toString'](_grsa_JS['enc']['Utf8']):DES算法,密文是参数mi经过Hex操作后的,key是(6)执行后的结果,mode是ECB,iv那就没用了,最后解密完之后,再进行utf-8的字符串转化。
(9)return _0x554c90['substring'](0x0, _0x51eedc['hLXma'](_0x554c90['lastIndexOf']('}'), 0x1))_0x51eedc['hLXma']做加法操作,所以也是做个字符串的截取。
上述中的_grsa_JS就是调用的crypto-js库,所以在代码中可以引入crypto-js库,把_grsa_JS替换掉。最终得到的代码如下:

var CryptoJS = require("crypto-js")

function fn(mi) {
    var _0x51eedc = {
        'pKENi': function _0x2f627(_0x5b6f5a, _0x440924) {
            return _0x5b6f5a === _0x440924;
        },
        'wnfPa': 'ZGz',
        'VMmle': '7|1|8|9|5|2|3|6|0|4',
        'GKWFf': function _0x1a4e13(_0x40cfde, _0x16f3c2) {
            return _0x40cfde == _0x16f3c2;
        },
        'MUPgQ': function _0x342f0d(_0x19038b, _0x4004d6) {
            return _0x19038b >= _0x4004d6;
        },
        'hLXma': function _0x55adaf(_0x45a871, _0x161bdf) {
            return _0x45a871 + _0x161bdf;
        },
        'JdOlO': function _0x13e00a(_0x5899a9, _0x4bb34d) {
            return _0x5899a9 + _0x4bb34d;
        },
        'qrTpg': function _0x1198fb(_0x55b317, _0x22e1db, _0x1b091a) {
            return _0x55b317(_0x22e1db, _0x1b091a);
        },
        'pdmMk': function _0xe2b022(_0x4af286, _0x4c2fd4) {
            return _0x4af286 - _0x4c2fd4;
        },
        'xVKWW': function _0x1094a3(_0x5f3627, _0x2a0ac5, _0x3ad2e5) {
            return _0x5f3627(_0x2a0ac5, _0x3ad2e5);
        }
    };

    var _0x9843d3 = function(_0x29d556, _0xcc6df, _0x3d7020) {
        var _0x48914b;
        _0x48914b = '' + _0x29d556['substr'](0x0, _0xcc6df);
        return _0x48914b += _0x29d556['substr'](_0xcc6df + _0x3d7020);
    };


    var _0x554c90 = parseInt(mi[mi['length']- 1], 16) + 9
                  , _0x2cf8ae = parseInt(mi[_0x554c90], 16);
    mi = _0x9843d3(mi, _0x554c90, 0x1);
    _0x554c90 = mi['substr'](_0x2cf8ae, 0x8);
    mi = _0x9843d3(mi, _0x2cf8ae, 0x8);
    _0x2cf8ae = CryptoJS['enc']['Utf8']['parse'](_0x554c90);
    _0x554c90 = CryptoJS['enc']['Utf8']['parse'](_0x554c90);
    _0x554c90 = CryptoJS['DES']['decrypt']({
                    'ciphertext': CryptoJS['enc']['Hex']['parse'](mi)
                }, _0x2cf8ae, {
                    'iv': _0x554c90,
                    'mode': CryptoJS['mode']['ECB'],
                    'padding': CryptoJS['pad']['Pkcs7']
                })['toString'](CryptoJS['enc']['Utf8']);
    return _0x554c90['substring'](0x0, _0x51eedc['hLXma'](_0x554c90['lastIndexOf']('}'), 0x1));
}

测试一下有没有问题,给fn函数传个数据看看能不能解密成功。
测试代码:

console.log(fn('9C35017226E866474B870ADB394B42963E554FB1027A8E014D1D3B0D2527778BFCBBE09DC5A517B4F33BAC6EC911D9DD5ABE71CB747253DE5517908B024492B8899CD970953A7D7E693E1FB54B78F4CA13F54D904649CE9298E61F0FD170DD086C18DC72D563FF770A6D574879B0301DE1A04E992E06C514989D92FC7BDBEB57250881B64CD87877752F1CF8880F4755538B13FF3A0E3436D80BCC07884729C482AA97C4EF78A1CC2565A74A10EC4B504605270423F1D24C8E107DF789DE0AF8AD12E489C6331895A1156BDE999BF476475FD76E3C1227C37E30BB7E97FCCCAF6A93C772E8D1BE4978A70D62CBE0255C4FB246F9362B799C245E62ADFDF6B4A95E1CAF81970D888D0BA0B098E7864DE5723A511E69944E3D2BD68690147E74C58F07F487A1ACFBD73A5F9AB6899B6923EFBE871DAEDC87A9685D6D42A131578CB95C20A8BC3AD5D8AFE5A4923407C7129D08B0E34FA68EA56889B65BFB27CDA453069EDEC1F4F05BED06B14DF788A27E2AAD53C87001FB1BF94190EBAA9A515BF0DAD89F7670E7762796D37559F073CE393150772F9C7380274D9972DB141797EFA2B3BC54934392D1973BC0FEFDC6097657514C64C3133BA825329A1FE0895911C80B2DA975FB193FCF04404B3463575467A3D6936CCC57D4CDB8388E9687815A2D75702EE51208BABA9B34AA6FB495DDECA325F88D7804E1AA8F6FD3208D44726AEEB83A4F52927B16433D5BFBF0DA1D045085A88B6B7E14006481AFB03D2D03A27F40D88E652BF0B571D7FBA42A60B39204EA78903F5436A1A6D2B2E16C1640B5BE576B75B189DE675DBC31A66739BC1DD4675C103005EC0D55DFF3881193935BD127E608DC84CBD7B96DC7F9BC00D9BC9208758D5E1926D75DE6B016C208C1640F7A24D9A6F0779609E9A78ED73FBBB98FB4D98ACDCDA4BB92360550573A15591D749829875D2963ECB8A569CD1C8E94AC5C35A9D8C0D17C9EE02DDB547211E43F325B099849B57BB0A3B10FC74AEAFFA126BA1610B0C7C87CBD52EA2B3A9A961F2467B5F9F191349DF444ECDB7DA9B05F8D8D05B5F0C09CC3D28F525A8D1121B3CFD56B1DE7EFA1451B34B784923820EA9E33E3C8DF8AF95F05EC1905BBA5060C15A5EA5466AACFB76043F58F61F8A325A656A7B66232A52F8933CD2ECA38914D4EF911D9DD5ABE71CB7D0C13B6B4A3AAD8C24492B8899CD9709F94C01C3D93245BC8F8820EC6A31789CD6481800525697DF13370D20D9C24067A4280E0C72B09B9CDED189D6FFE28DDAEC5E9E5C8AEB2352EBB27C2D966509D192E387F45C94FF0CA3309A1235F970B86451BA2B3A6417DA052A03E1A120889BA9F10ED539266F389DCE342C68951A86D965720CD53413F8FD8AE7F08CBB346E96C6F98337D8BB06299FAF0CBB4937D908C5B669729CCDCDB453104E27BA987DE8FABF0EA291D4312240C5312261B1D520EE953E5EEFD16BB267F0BF157F70A2E8EF05F3167F51913725745E102C402765D666B1583343831068468D2CBABE6E04083A025E1B28E8472E84EFC115AA59F9B21EF0DFF78046594317072F74EC6ADD7936B900C561642439ADDC3B047C1DEB7C55CCACA2E46D563FF770A6D5748780B09FF96D5CBCCBE06C514989D92FC7AF47F52B0646FA27B33A45BBE07DAEEA80F4755538B13FF3D7F8E086DF91BA8087D8E789C5FFEDEF052A03E1A120889BA9F10ED539266F389DCE342C68951A86D965720CD53413F8FD8AE7F08CBB346EC9B39930B7F04A79299FAF0CBB4937D908C5B669729CCDCDB453104E27BA987DE8FABF0EA291D4312240C5312261B1D520EE953E5EEFD16B4A7E050C228D4FCEB1049B4C1E72E0CC045DA19FFAEF996F1B5036BF69E3FBA0EBE08721482EC00204083A025E1B28E8472E84EFC115AA596C4742FD9B9DC6C5594317072F74EC6A61C3ED33C6D1135366EEC1D29C4BBA1EB0DCD4394C59233CBA3EFD1075FEC0962AD2EA4AF54F8CC04E189B99151C714817068A63A0326D3B27A3049BA8A99A4CCD7317F5D2B4C14F67E1D331CA42557C87420E7CDBB082B9BA10FDAFEA7E98107AFF8E8E89D3AE5C26F83EB0BA84D873FB860355A159644B206F009D9E70010BF74C2F05ACE4030CB3362457AFA6126098665DA4F3B796D6735C2E6DDF99D51589C7E8860A843CB686AA20789539AD97DD7FF09493502F494BCC8F41C4BC416E419B43DA4960F289998FDCE7218DCABE44A1D44F6FBB79A3032C99AEE77103E4F16C865A60B695C6656214D10889CE5C9C054CFF3249C3452D6903837D46151A2532E193E3C5C1B3EA881398752AE7940DC6BD42A93E581FC247D1631A19F4492E89BCA125862655F0F4D26B21013E5D7D1421403FED9B50F48489EEE56246254C1F498A06CF15A148ED5637860341F75F948978475C73124886FB2664678BEABE32BDE63BD98FE3119BC57E2AFB6E5F4C3133BA825329A1FE0895911C80B2DA975FB193FCF044041154347267A5FA5036CCC57D4CDB8388E9687815A2D75702EE51208BABA9B34AA6FB495DDECA325F88D7804E1AA8F6FD3208D44726AEEB83318DC666D53770AFC472A24F7FC7134A90DD621F3AA44F2DF8C3879FC4A7BB8A2C32E6F832598F2C1DBDB732655197728903F5436A1A6D2B14B8BC28E99F626EA38FAB6E67C766641A66739BC1DD4675B99EBCFF22EDF79E9668E583D6AFFA6E38346980930EC429BA3EFD1075FEC0962AD2EA4AF54F8CC0657C9662EB63A81117068A63A0326D3B72EC67BF74D0001F67FA22488B3DB3E08110C5601EAA6A7083D0B40F93DB4CE731C815EBC154D41E304DE0D274D7D5C2FC84CA937397FA94C6061807B8FE806948DB34A872027A5C93CEDB426E8F44DAB0AA83E498A21FEA08E1F39F4342C7222E5474E2F1D43CF95D391341481F2CCFFB2C527D0AC90F2AF6603355DAC72A0B5543762AA5E6132668AD3CA3C92211E5AC086BC9D548DE5716FBE008017A9A994974BFDC2941D98E50A8ED4358EFE4C482DA2FD7B31416CAB7B3049E8EE4BE0F0ABE87319A636DBDBB068277AB66674224F0384A3BBB372DE5293A8073FF6D1884BA4DD614BBEAC07F9BC00D9BC9208758D5E1926D75DE6B9F8D43C9B96E7DFF4D9A6F0779609E9A3B4812AC97474E361CF449DABF1776A5013C0086FD4203E587420E7CDBB082B935C7A0FFE42232BC304DE0D274D7D5C2CC660D9A24CD3C95C6061807B8FE806948DB34A872027A5C223EBDC8146A4074580F341B2A091F8C08E1F39F4342C7222E5474E2F1D43CF95D391341481F2CCFFB2C527D0AC90F2AF6603355DAC72A0B3EF4610AB0210B8A46416891F343BD31574D5424DFA500BF507E67D2D087CE0E5692FEEAFF3F77A816737B667AFCFC5A82DA2FD7B31416CAB7B3049E8EE4BE0FB9A00140418D2492BB068277AB666742903CD46C9012D6EC2D42C3FADCAA5F8CBA3EFD1075FEC0962AD2EA4AF54F8CC04E189B99151C714817068A63A0326D3B17F5ABEF8C6049EE67FA22488B3DB3E0BF6334756016273F83D0B40F93DB4CE7D22460AB6D252C3A61B375CFB0FEE8AFC1A79DF111628D48D5044E26AD088F9EA9D01A56394E7EAC9DE0AF8AD12E489C6331895A1156BDE9ACBF7B53BF6A8B14C1227C37E30BB7E97FCCCAF6A93C772E8D1BE4978A70D62CBE0255C4FB246F9362B799C245E62ADFDF6B4A95E1CAF81992935DBE3FAC48B9897C266BFA81C026625275E6043B4582FCDE60BD9453D3CECA9A38BD7B5390C024456B545C9A16A9EDC87A9685D6D42A4C35B52FE131123DC3AD5D8AFE5A49233DF21B5D0FCA58CC54897F8A44520286C21F10BEF3AD02B21F4F05BED06B14DFE40F0B460584D83A5D5F15F53567CCDE7C8B868EF4D9EA86DD7F3DED0033A09380F4755538B13FF3C1BC8622885D9FA73069DA1E74E6BF32052A03E1A120889BA9F10ED539266F38E7334167D76D1A7BADECF9B222B10A3CC6061807B8FE806948DB34A872027A5C1960AEB5C28EC2B85C3EF28848EF07B508E1F39F4342C7222E5474E2F1D43CF95D391341481F2CCFFB2C527D0AC90F2AF6603355DAC72A0B3EF4610AB0210B8A091109150CDDFFABD60BCE4083C3AC6FD6555CC6548CB5CD9FD9019293A2A2237718A63EF2C824FE82DA2FD7B31416CA80537AA3D2B81DFD88D88617658F0980BB068277AB666742ECA569D57A5C55C0BF8BBF806F987CD3FA9315A5E35989E27F9BC00D9BC9208758D5E1926D75DE6B39556DE2285B6B724D9A6F0779609E9A180369E92573B8CC5FB482179D0E0C655C863D84FC1010F187420E7CDBB082B935C7A0FFE42232BC304DE0D274D7D5C2FC84CA937397FA94C6061807B8FE806948DB34A872027A5C0FED6C4F91F0D7CEB0AA83E498A21FEA08E1F39F4342C7222E5474E2F1D43CF95D391341481F2CCFFB2C527D0AC90F2AF6603355DAC72A0B5543762AA5E6132668AD3CA3C92211E578F279E37479002DB82B9BF5287660646F4FF6F17BEBF45266CEB5F65F5F760582DA2FD7B31416CA80537AA3D2B81DFD3528E35C84FB9482BB068277AB666742DF422E97A331F36F6B38C18CDDFBD7332E89BCA125862655472E5C06B0128FCCD9A3BDE3E9C03879F48489EEE5624625275A0DA4BDA6A6ED9F073CE39315077240659E460A0EE05FB141797EFA2B3BC5BA38231E7B7B7A200EC4B504605270423F1D24C8E107DF789DE0AF8AD12E489C6331895A1156BDE999BF476475FD76E3C1227C37E30BB7E97FCCCAF6A93C772E8D1BE4978A70D62CBE0255C4FB246F9362B799C245E62ADF2AC3D91D3F55CC9D1C29970CD7132FC3389051A93A1ED6AEB6FB7A39FD15BD2B2AAE77038EE6CD45A01A641231AF0D129670112B51272938EDC87A9685D6D42AD957BC6BB9D903EF913803BCAED1ED333DF21B5D0FCA58CC4ADAAC6EE06A7A7E37809E46BF8AC7106ADEB4AA0CAA8A4F13370D20D9C24067882252E4E7FB6FA8DED189D6FFE28DDA4F4ABDFC77151815F4DB6FD8A3EC53A5D469DBE14D6DF16B829875D2963ECB8A98726846E33D68AB7AFF8E8E89D3AE5C26F83EB0BA84D873FB860355A159644B206F009D9E70010B926D32DB81B6209C42FC899B54B2389898665DA4F3B796D6735C2E6DDF99D51589C7E8860A843CB686AA20789539AD97DD7FF09493502F491F77D9D816BA3C39039D20358C287664C2FD44B9C7C9F6F6537AEB2D351493C60C593201EF2F2D0B657785E91CA8FDDA656214D10889CE5C9C054CFF3249C345D7287E3CF730085F2532E193E3C5C1B390D5A395769D4B705139D997744C4D647F9BC00D9BC9208758D5E1926D75DE6B016C208C1640F7A24D9A6F0779609E9A2FE9D70185A969E8D47881FD10175FB25C863D84FC1010F187420E7CDBB082B9DB3AE91EBA33C3E2304DE0D274D7D5C2FC84CA937397FA94C6061807B8FE806948DB34A872027A5C1A2C6AB4D4F015BDE67C8C4A59543FE108E1F39F4342C7222E5474E2F1D43CF95D391341481F2CCFFB2C527D0AC90F2AF6603355DAC72A0B3EF4610AB0210B8A81A1AB2974C3EB59759646AF5C313BDE525B597DD87C1BB3854F0DF26C15B59E542B2CF6C797FF3A82DA2FD7B31416CA80537AA3D2B81DFDB979C7F13BB7E5BFBB068277AB66674279A3A470D9025774166B0E529164F53613370D20D9C24067A4280E0C72B09B9CDED189D6FFE28DDA06A07D8053811EECBE1BB194702BA2B3B8F336B251624531829875D2963ECB8A4BB1B652D76254335A9D8C0D17C9EE02DDB547211E43F325B099849B57BB0A3B10FC74AEAFFA126BA1610B0C7C87CBD52EA2B3A9A961F2467B5F9F191349DF444ECDB7DA9B05F8D8D05B5F0C09CC3D28F525A8D1121B3CFD56B1DE7EFA1451B34B784923820EA9E38B055C2085EB35C58C33D8E62156B66065BC5E77ED0FDC9BED3583018198A20C31C8AF1ACBEB588C3CD2ECA38914D4EF911D9DD5ABE71CB74BC9B5CD5279EC9624492B8899CD9709B5EA8E93BC63658786EA7A23133436C623F2BB254DCE6FAC464B17AC1CE3A59FA27F78B1CF92C77B69579610E4A04DBDE96425129F2AE1DEBDA3373344F81932266DCDC53B7E747EC53B63287274334B1677A1D3BE586F7950E33A5DF0E118344F07EE4F3FE39F5F15743B8A30CD31161E29EDFEA43BA74858C88193B0BDB7AD735F86D4F1725712D965720CD53413F8C0280E46A3E6082D6254FE4FF0A937C4299FAF0CBB4937D908C5B669729CCDCDB453104E27BA987DE8FABF0EA291D4312240C5312261B1D520EE953E5EEFD16BE540FD80F92404530CED97B6909E14E6E3DB11A681D244C6DD0C5709E9B8AF6419D5AC28C59CFE3B04083A025E1B28E8472E84EFC115AA5995CC74916EC4AD82594317072F74EC6A6DE50FFA17A80FC48B4F7745CDBDB4415FCD830DD97EB4CA81A6D26F558FB6F0607D33B58CBCA8D757E05E547817D0024F922304AF50E06403CAF1F8B7F29E5548ED5637860341F78E153BFC5BA19C6E4886FB2664678BEA388D28CEF93060BAEFDC6097657514C64C3133BA825329A1FE0895911C80B2DA975FB193FCF044046530074FB351571036CCC57D4CDB8388E9687815A2D75702EE51208BABA9B34AA6FB495DDECA325F88D7804E1AA8F6FD3208D44726AEEB836942AD35B11C9031BAA6C7D27EAA99E5BC40A0B01A10E1D6D6CAB87289509E3D3CB6319383AEA3F860C9E4890A58F2338903F5436A1A6D2B5C9E09C58E0179BAC9D6205E8899EE371A66739BC1DD4675B59E009F5C74FD1CFF022BBD36726A092E89BCA125862655CA41EF0D1BFD1FE05EA854D0817A4FFBF48489EEE5624625F6E18C455BDD8C739F073CE3931507720356FB0A293E3305B141797EFA2B3BC5786DE169931A199207742C8DF306F2EA3F1D24C8E107DF789DE0AF8AD12E489C6331895A1156BDE9C2BDE2C9322A0F27C1227C37E30BB7E97FCCCAF6A93C772E8D1BE4978A70D62CBE0255C4FB246F9362B799C245E62ADF2AC3D91D3F55CC9DE05E9FEBB2F32414389051A93A1ED6AE35AA488A94E9B499BC77A824A74767B0DFD014F8143456B2C7C04AB061F0C5D2EDC87A9685D6D42A49830F453FB0E6F2913803BCAED1ED3390528F93DDFDD94A73AB70C249991B9EA27F78B1CF92C77BF9F0A02BD42E55FAE5AA48822B92FA23BDA3373344F81932F6CBFE5AB6B95409C53B63287274334BED57BC8E3050919350E33A5DF0E118344F07EE4F3FE39F5F15743B8A30CD3116A8DABB09F7FB47935FA74A763C01ABA90E13DA17D7C6F49E4D2D099C64122E76F0A35E063F6FFE7F6961FD427C0C0D475DE33AC9D2597F17C2F39F1FB59FE289DACBC51850E2BC3E9C79BDC59A06AD2B191DBE91649FCF6E01EB7BEAF56A3C600FCAE29F127E715DD970032D72A91F71154CC2B1E468987F9F86FF5F593123E88D2E73D983281962901D42FEDF2F9A394F9BA41E72EAF3F2301D71CAF66A592D363E0BE26F1FD884F549BB9C17160B37271BF71EEA86BF27320E8C0D588A8A7D31A35F00BD2F1DE97F9BC00D9BC9208758D5E1926D75DE6BF728A823131AB17F4D9A6F0779609E9A3E1FDEC00E4FBE879C59F87C1F0B10C744B1C95C2E0D63B687420E7CDBB082B932DE75643C63C455304DE0D274D7D5C2CC660D9A24CD3C95C6061807B8FE806948DB34A872027A5C56D3E048DFA32C60E67C8C4A59543FE108E1F39F4342C7222E5474E2F1D43CF95D391341481F2CCFFB2C527D0AC90F2AF6603355DAC72A0B3EF4610AB0210B8A7F0D4A79F1DBC925AD9332DC8CEFB017EFA4B905C9FFC91C3805D60758A111F323AFA370DC672DE282DA2FD7B31416CA80537AA3D2B81DFDE510919C525CB343BB068277AB66674231BA6818A57C710F772C3AFEBB17D85E1F4F05BED06B14DF3A410CE37AE1E39C8B6D56705168BB0A09F11B4228301D343B0722232CDC6B3280F4755538B13FF3408C46B00B0F377D3069DA1E74E6BF32052A03E1A120889BA9F10ED539266F389DCE342C68951A86D965720CD53413F8FD8AE7F08CBB346EA6732884F25A1517299FAF0CBB4937D908C5B669729CCDCDB453104E27BA987DE8FABF0EA291D4312240C5312261B1D520EE953E5EEFD16BB95D67308B30DDD712ABF0B404F67BC58A90A2D9FA72D644886640D9385B6B84938965D06030166A04083A025E1B28E8472E84EFC115AA590E4319BFE4B51BBB594317072F74EC6A25936809DB3A85ABEB63079A763CF642FB7081B66E254D5C46DF70BF990F221F1F4F05BED06B14DF69C85338D210DBF2E8BF78757866E55609F11B4228301D345D13A51B5D888B3880F4755538B13FF3C1BC8622885D9FA7154F79F12D92504F052A03E1A120889BA9F10ED539266F389DCE342C68951A86D965720CD53413F8FD8AE7F08CBB346EAE9095E97E46A1E2299FAF0CBB4937D908C5B669729CCDCDB453104E27BA987DE8FABF0EA291D4312240C5312261B1D55D43DB7F1171C436C7737AFC8653F926125ABDBD33159A36EC8F06BD19511EC301FA77B216F643ADCB8BDB90C864CA3B04083A025E1B28E8472E84EFC115AA598577BB2D170394E9594317072F74EC6A6169B7C16F9AD88DD8D4713E3FBCB068418CAD4948983B8D563FF770A6D5748780B09FF96D5CBCCBE06C514989D92FC771CED028FFE9B3F3F8586B4BEACF451F92E387F45C94FF0CA3309A1235F970B870128BAF01FB7F2A5A9D8C0D17C9EE02DDB547211E43F325B099849B57BB0A3B10FC74AEAFFA126BAACD877AE7858C72BC83E0EB13967BBD7B5F9F191349DF444ECDB7DA9B05F8D8D05B5F0C09CC3D28F525A8D1121B3CFD56B1DE7EFA1451B36F435B1F5E5EC985968A39624B44D7408503B9BE539762A433531D06E8F9BC9B4EFB6FAF150F0E03D9DC1BA3CA74C1C63CD2ECA38914D4EF911D9DD5ABE71CB7B5BEDFF1DB9202DE24492B8899CD9709FAF5FCCA00CB530795B2BDC8B6A0B014A27F78B1CF92C77BE85D9035B89FD3A477077A8B64397900BDA3373344F819323CA344CC426518CBC53B63287274334B1677A1D3BE586F7950E33A5DF0E118344F07EE4F3FE39F5F15743B8A30CD31161E29EDFEA43BA7483179895FEBC45B1330631C038BC177E2D965720CD53413F8F8D5039170A17892603A7985B61EF597299FAF0CBB4937D908C5B669729CCDCDB453104E27BA987DE8FABF0EA291D4312240C5312261B1D520EE953E5EEFD16B1C3E8F06CA78CBDC12ABF0B404F67BC58C919621A83F678D25D9832BB4E5BCCC3316919EB5F59C77B827EFE02BD6D1C314200B350F54BC2688ACC1D81C9623F69CC728CCA0665596'));

运行成功,没问题。

除了采用JS代码,还可以转换成python代码。根据js代码的逻辑,python代码是很好写的。整体代码如下(包含请求得到密文,再进行解密):

import requests
import binascii
from Crypto.Cipher import DES
from Crypto.Util.Padding import unpad
import json

url = "https://www.endata.com.cn/API/GetData.ashx"
year = 2022
data = {"year": year, "MethodName": "BoxOffice_GetYearInfoData", }
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 "
                  "Safari/537.36"}
resp = requests.post(url, data=data, headers=headers)
mi = resp.text

def fn(a, b, c):        # 对应_0x9843d3函数
    if b == 0:
        return a[c:]
    data = '' + a[:b]
    data += a[b + c:]
    return data


a = int(mi[-1], 16) + 9  # a = parseInt(mi[mi['length'] - 1], 16) + 9
b = int(mi[a], 16)  # b = parseInt(mi[a], 16)
mi = fn(mi, a, 1)
a = mi[b:b + 8]  # mi['substr'](b, 8);
mi = fn(mi, b, 8)
key = a.encode("utf-8")
des = DES.new(key=key, mode=DES.MODE_ECB)
ming_bs = des.decrypt(binascii.a2b_hex(mi))
ming_bs = unpad(ming_bs, 8)
ming_str = ming_bs.decode("utf-8")
ming_str = ming_str[0:ming_str.rindex('}') + 1]
print(json.loads(ming_str))

运行结果如下:

总结:做这种ob混淆,必须要小心替换,仔细再仔细。

posted @ 2024-03-07 19:03  死不悔改奇男子  阅读(789)  评论(1编辑  收藏  举报