url:https://www.endata.com.cn/BoxOffice/BO/Year/index.html

JS 逆向

请求分析

image.png

请求头没啥特别的。

year:2025
MethodName:BoxOffice_GetYearInfoData

请求负载没有加密。

image.png

很明显响应是进过加密的。

逆向过程

image.png

调用栈没什么特别异常的地方,没有请求和响应拦截器的使用痕迹,这返回搜也没得搜;那就只能用最朴素的办法了。

根据 jquery 的特征可以知道他的 resp 处理在哪里,[[jquery特征]]:

image.png

这里是一个三目运算符,如果字符串第一个是 { 那么就走前面的逻辑,但是密文显然不符合,所以走后面的逻辑,所以 shell() 里面就是解密的逻辑!

应对 OB 混淆

image.png

可以看到这里的解密过程,是经过 OB 混淆的,所以这里需要处理!

这里很明显是一个花指令,我们可以来看看他们的功能

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

然后把他们全部替换掉。

image.png

使用控制台解密花指令,如果缺少函数就搜索复制过来,最后得到结果:

var _grsa_JS = require("crypto-js")  

var _0x4da59e = {  
    'bUIIa': function _0x2a2af9(_0x779387, _0x4a4fec) {  
        return _0x779387 + _0x4a4fec;  
    }  
};  

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

function fn(e) {  

        if ((null == e) || (0x10 >= e['length']))  
            return e;  

        var _0x554c90 = parseInt(e[(e['length'] - 0x1)], 0x10) + 0x9, _0x2cf8ae = parseInt(e[_0x554c90], 0x10);  

        e = _0x9843d3(e, _0x554c90, 0x1);  

        _0x554c90 = e['substr'](_0x2cf8ae, 0x8);  

        e = _0x9843d3(e, _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'](e)  
                }, _0x2cf8ae, {  
                    'iv': _0x554c90,  
                    'mode': _grsa_JS['mode']['ECB'],  
                    'padding': _grsa_JS['pad']['Pkcs7']  
                })['toString'](_grsa_JS['enc']['Utf8']);  

        return _0x554c90['substring'](0x0, _0x554c90['lastIndexOf']('}') + 0x1);  
}

Python 爬虫

import requests  
import execjs  

url = "https://www.endata.com.cn/API/GetData.ashx"  

headers = {  
    "Accept": "text/plain, */*; q=0.01",  
    "Accept-Encoding": "gzip, deflate, br",  
    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",  
    "Cache-Control": "no-cache",  
    "Connection": "keep-alive",  
    "Content-Length": "46",  
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",  
    "Host": "www.endata.com.cn",  
    "Origin": "https://www.endata.com.cn",  
    "Pragma": "no-cache",  
    "Sec-Ch-Ua": "\"Chromium\";v=\"122\", \"Not(A:Brand\";v=\"24\", \"Google Chrome\";v=\"122\"",  
    "Sec-Ch-Ua-Mobile": "?0",  
    "Sec-Ch-Ua-Platform": "\"Windows\"",  
    "Sec-Fetch-Dest": "empty",  
    "Sec-Fetch-Mode": "cors",  
    "Sec-Fetch-Site": "same-origin",  
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36",  
    "X-Requested-With": "XMLHttpRequest"  
}  

data = {  
    "year": "2024",  
    "MethodName": "BoxOffice_GetYearInfoData"  
}  

resp = requests.post(url=url, headers=headers, data=data)  

# print(resp.text)  

f = open("en.js", mode="r", encoding="utf-8")  
code = f.read()  
f.close()  

js = execjs.compile(code)  

ming = js.call("fn", resp.text)  

print(ming)