url:https://www.endata.com.cn/BoxOffice/BO/Year/index.html
JS 逆向
请求分析
请求头没啥特别的。
year:2025
MethodName:BoxOffice_GetYearInfoData
请求负载没有加密。
很明显响应是进过加密的。
逆向过程
调用栈没什么特别异常的地方,没有请求和响应拦截器的使用痕迹,这返回搜也没得搜;那就只能用最朴素的办法了。
根据 jquery 的特征可以知道他的 resp 处理在哪里,[[jquery特征]]:
这里是一个三目运算符,如果字符串第一个是 {
那么就走前面的逻辑,但是密文显然不符合,所以走后面的逻辑,所以 shell()
里面就是解密的逻辑!
应对 OB 混淆
可以看到这里的解密过程,是经过 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)
};
然后把他们全部替换掉。
使用控制台解密花指令,如果缺少函数就搜索复制过来,最后得到结果:
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)
评论