猿人学第5题「js混淆-乱码增强」解题记录
猿人学第5题「js混淆-乱码增强」解题记录
题目链接:https://match.yuanrenxue.cn/match/5
难度:★★★☆☆ | 一句话概括:第1题的加强版,签名从单个m升级为「多个参数 + 多个 cookie」,涉及 MD5 与 AES-ECB 加密。
一、题目目标与规则
- 请求全部 5 页数据(每页 10 个值),把 50 个值相加得到答案。
- 第 5 页请求时 UA 要改成
yuanrenxue。 - 请求必须携带
sessionid,每个已登录用户的数字答案不同(所以要登录取自己的 cookie)。 - 关键点:请求参数和 Cookie 都由一段被「乱码增强」混淆过的 JS 动态生成,浏览器端先算好签名,再发请求。
二、抓包与接口分析
目标接口是一个 GET 请求:
GET https://match.yuanrenxue.cn/api/question/5?page=N&m=<ts>&f=<ts>
URL 参数:
| 参数 | 含义 | 来源 |
|---|---|---|
page |
页码,1~5 | 自己拼 |
m |
当前毫秒时间戳字符串 | Date.now() |
f |
同样是毫秒时间戳 | Date.parse(new Date()) |
请求头要点:
referer: https://match.yuanrenxue.cn/match/5user-agent:前 4 页正常浏览器 UA 也行,第 5 页必须为yuanrenxue。x-requested-with: XMLHttpRequest
Cookie 要点:
| Cookie | 含义 | 来源 |
|---|---|---|
sessionid |
登录态,必备 | 登录后浏览器复制 |
Hm_lvt_xxx / Hm_lpvt_xxx / HMACCOUNT / yuanrenxue_cookie |
统计类 cookie | 浏览器复制即可 |
m |
时间戳的 MD5 | JS 计算 |
RM4hZBv0dDon443M |
AES-ECB 加密结果 | JS 计算 |
响应结构是 JSON,data 字段是一个长度 10 的数组:
{
"status": "1",
"state": "success",
"data": [ ...10 个数字... ]
}
对 5 页的 data 全部求和,就是答案。
三、逆向思路
1. 核心函数 get_params()
页面加载后会调用一个 get_params(),它返回 4 个关键值:
return {
'cookie_m': cookie_m, // MD5(时间戳字符串)
'RM4hZBv0dDon443M': ..., // AES-ECB 加密结果
'm': _$is, // 毫秒时间戳字符串
'f': Date.parse(new Date()) // 毫秒时间戳
}
其中 m 和 f 是「时间戳」,但注意:URL 里的 m 是时间戳,而 Cookie 里的 m 是 MD5,两者不是同一个东西。
2. 四个值的生成逻辑
// 1) m:当前毫秒时间戳字符串
_$is = _0x2d5f5b()["toString"]() // 等价 Date.now() 的字符串
// 2) f:Date.parse(new Date()),毫秒
// 3) cookie_m:时间戳字符串的 MD5
cookie_m = _0x474032(_$is) // _0x474032 -> MD5
// 4) RM4hZBv0dDon443M:AES-ECB-PKCS7
key = CryptoJS.enc.Utf8.parse(btoa(_$is).slice(0, 16))
_$Ww = CryptoJS.enc.Utf8.parse(prs.toString()) // prs 是一串 MD5 哈希数组
_0x29dd83 = CryptoJS.AES.encrypt(_$Ww, key, {
'mode': CryptoJS.mode.ECB,
'padding': CryptoJS.pad.Pkcs7
})
关键点:
- AES 的 key 来自
btoa(时间戳)的前 16 个字节,务必先btoa再slice(0, 16)。 - AES 明文
prs是一串 MD5 哈希数组:get_params()里先循环 4 次,每次对时间戳求 MD5 并 push 进prs,最后再 push 一个cookie_m(也是 MD5),所以prs一共 5 个 32 位 MD5 串,toString()后是 160 个字符。
3. 乱码还原
原题 JS 是一段被「乱码增强」过的代码:变量名全是 _0x 开头的十六进制编号,字符串数组打乱、用减法偏移还原,MD5 是纯手写实现(_0x11a7a2 那一大段就是 MD5 压缩函数),AES 则直接调用 crypto-js。
手写 MD5 里还夹了反调试/环境检测干扰(XMLHttpRequest、history.pushState、$_z2 之类的死代码),但这些分支在 try/catch 里,执行不到关键路径,还原时可以直接把环境检测分支固定为常量(_$Jy、_$tT、_$6_ 这些初始值在 get_params() 里被重新赋值),于是整理成 b.js 后直接用 execjs 调用。
四、核心代码
a.py(execjs 调用 + 组装参数/cookie + 求和)
import requests
import execjs
import os
import subprocess
import sys
# 【核心修复1】强制全局 UTF-8 编码,必须放在最开头
os.environ["PYTHONIOENCODING"] = "utf-8"
sys.stdout.reconfigure(encoding='utf-8')
sys.stderr.reconfigure(encoding='utf-8')
# 【核心修复2】读取 JS 文件时自动去除 BOM 头
with open('b.js', 'r', encoding='utf-8-sig') as f:
js_code = f.read()
# 【核心修复3】手动去除所有 BOM 字符,双重保险
js_code = js_code.replace('\ufeff', '')
# 编译执行
ctx = execjs.compile(js_code)
data = ctx.call("get_params")
print(data)
a = 0
for i in range(1,6):
headers = {
"accept": "application/json, text/javascript, */*; q=0.01",
"accept-language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
"cache-control": "no-cache",
"pragma": "no-cache",
"priority": "u=1, i",
"referer": "https://match.yuanrenxue.cn/match/5",
"sec-ch-ua": "\"Chromium\";v=\"146\", \"Not-A.Brand\";v=\"24\", \"Google Chrome\";v=\"146\"",
"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": "yuanrenxue",
"x-requested-with": "XMLHttpRequest"
}
cookies = {
"Hm_lvt_434c501fe98c1a8ec74b813751d4e3e3": "1773750584",
"sessionid": "frzna2wyl0oh1grr2ut761ejtf03a20i",
"Hm_lvt_f80b2b389f44bbfb3bfe1704817d44e0": "1775317756,1775386530,1775462871,1775530065",
"HMACCOUNT": "00959BC5EB881F83",
"yuanrenxue_cookie": "1775669731|lpeBPgfXakByutEsRN3Cek7kfm7TckvbP45oLgVfffe5CoifybAjSBj4XMN9zXuFrM9yc9BcMG3fANZTkRIdvqs",
"Hm_lpvt_f80b2b389f44bbfb3bfe1704817d44e0": str(data.get('t'))[:-3],
"m": data.get('cookie_m'),
"RM4hZBv0dDon443M": data.get('RM4hZBv0dDon443M')
}
url = "https://match.yuanrenxue.cn/api/question/5"
params = {
"page": str(i),
"m": data.get("m"),
"f": data.get("f"),
}
response = requests.get(url, headers=headers, cookies=cookies, params=params)
print(response.text)
print(response)
a+= sum(response.json().get('data'))
print(a)
b.js(还原的 MD5 + AES 加密,整理成可被 execjs 调用的版本)
const CryptoJS = require('crypto-js')
var _0x1171c8 = 0x67452301;
var _0x4dae05 = -0x10325477;
var _0x183a1d = -0x67452302;
var _0xcfa373 = 0x10325476;
var _0x4e96b4 = window = global
, _0x30bc70 = String
, _0x35bb1d = Date
function _0x12eaf3() {
return _0x35bb1d["parse"](new _0x35bb1d());
}
function _0x474032(_0x233f82, _0xe2ed33, _0x3229f9) {
return _0x37614a(_0x233f82);
}
function _0x37614a(_0x32e7c1) {
return _0x499969(_0x41873d(_0x32e7c1));
}
function _0x499969(_0x82fe7e) {
var _0x5bdda4, _0x322a73, _0xd0b5cd = '0123456789abcdef', _0x21f411 = '';
for (_0x322a73 = 0x0; _0x322a73 < _0x82fe7e['length']; _0x322a73 += 0x1)
_0x5bdda4 = _0x82fe7e['charCodeAt'](_0x322a73),
_0x21f411 += _0xd0b5cd['charAt'](_0x5bdda4 >>> 0x4 & 0xf) + _0xd0b5cd['charAt'](0xf & _0x5bdda4);
return _0x21f411;
}
function _0x41873d(_0x5a6962) {
return _0x1ee7ec(_0x2b8a17(_0x5a6962));
}
function _0x2b8a17(_0x36f847) {
return unescape(encodeURIComponent(_0x36f847));
}
function _0x12b47d(_0x149183) {
var _0xabbcb3, _0x1145c3 = '', _0x4fce58 = 0x20 * _0x149183['length'];
for (_0xabbcb3 = 0x0; _0xabbcb3 < _0x4fce58; _0xabbcb3 += 0x8)
_0x1145c3 += _0x30bc70['fromCharCode'](_0x149183[_0xabbcb3 >> 0x5] >>> _0xabbcb3 % 0x20 & 0xff);
return _0x1145c3;
}
function _0x1ee7ec(_0x206333) {
return _0x12b47d(_0x11a7a2(_0x35f5f2(_0x206333), 0x8 * _0x206333['length']));
}
function _0x35f5f2(_0x243853) {
var _0x139b8b, _0xa791a1 = [];
for (_0xa791a1[(_0x243853['length'] >> 0x2) - 0x1] = void 0x0,
_0x139b8b = 0x0; _0x139b8b < _0xa791a1['length']; _0x139b8b += 0x1)
_0xa791a1[_0x139b8b] = 0x0;
var _0x41a533 = 0x8 * _0x243853['length'];
for (_0x139b8b = 0x0; _0x139b8b < _0x41a533; _0x139b8b += 0x8)
_0xa791a1[_0x139b8b >> 0x5] |= (0xff & _0x243853['charCodeAt'](_0x139b8b / 0x8)) << _0x139b8b % 0x20;
return _0xa791a1;
}
function _0x48d200(_0x4b706e, _0x3c3a85, _0x111154, _0x311f9f, _0x5439cf, _0x38cac7, _0x26bd2e) {
return _0xaaef84(_0x3c3a85 & _0x111154 | ~_0x3c3a85 & _0x311f9f, _0x4b706e, _0x3c3a85, _0x5439cf, _0x38cac7, _0x26bd2e);
}
function _0xaaef84(_0xaf3112, _0x2a165a, _0x532fb4, _0x10aa40, _0x41c4e7, _0x1cb4da) {
return _0x12e4a8(_0x3634fc(_0x12e4a8(_0x12e4a8(_0x2a165a, _0xaf3112), _0x12e4a8(_0x10aa40, _0x1cb4da)), _0x41c4e7), _0x532fb4);
}
function _0x3634fc(_0x5803ba, _0x1ce5b2) {
return _0x5803ba << _0x1ce5b2 | _0x5803ba >>> 0x20 - _0x1ce5b2;
}
function _0x11a7a2(_0x193f00, _0x1cfe89) {
_0x193f00[_0x1cfe89 >> 0x5] |= 0x80 << _0x1cfe89 % 0x20,
_0x193f00[0xe + (_0x1cfe89 + 0x40 >>> 0x9 << 0x4)] = _0x1cfe89;
try {
var _0x42fb36 = 16
// var _0x42fb36 = _0x4e96b4['XMLHttpRequest']['prototype']['DONE'] * 0x4; // arg1
} catch (_0x1b1b35) {
var _0x42fb36 = 0x1;
}
try {
_0x4e96b4['$_z2'][0x0] = 'Q';
} catch (_0x4c574d) {
try {
op = 27;
// op = _0x4e96b4['$_zw']['length']// arg2
} catch (_0x58af26) {
var _0x3b7935 = 0x0;
for (var _0x1badc3 = 0x0; _0x1badc3 < 0xf4240; _0x1badc3++) {
_0x3b7935 = _0x3b7935 + _0x1badc3['toString']();
history['pushState'](0x0, 0x0, _0x3b7935);
}
}
if (op > 0x14) {
b64pad = 1
// eval('b64pad = _0x4e96b4[\'$_zw\'][9][\'length\'];');
} else if (op < 0xa) {
_0x4e96b4['$_zw'] = [0x1, 0x8, 0x2, 0x4, 0x17, 0x2d, 0x8, 0xf, 0x51, 0x44, 0xd, 0x48, 0x46];
}
}
var _0x1badc3, _0x38ca59, _0x431764, _0x43f1b4, _0x5722c0, _0x3e0c38 = _0x1171c8, _0xdb4d2c = _0x4dae05,
_0x1724c5 = _0x183a1d, _0x257ec6 = _0xcfa373;
try {
if (_0x4e96b4['_$6_']) {
} else {
_0x4e96b4['_$6_'] = 0x20dc5d57f;
}
} catch (_0x15bf3f) {
_0x4e96b4['_$6_'] = 0x2421603;
}
for (_0x1badc3 = 0x0; _0x1badc3 < _0x193f00['length']; _0x1badc3 += _0x42fb36)
_0x38ca59 = _0x3e0c38,
_0x431764 = _0xdb4d2c,
_0x43f1b4 = _0x1724c5,
_0x5722c0 = _0x257ec6,
_0x3e0c38 = _0x48d200(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3], 0x7, 0x7d60c),
_0x257ec6 = _0x48d200(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0x1], 0xc, _0x4e96b4['_$6_']),
_0x1724c5 = _0x48d200(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0x2], 0x11, 0x242070db),
_0xdb4d2c = _0x48d200(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0x3], 0x16, -0x3e423112),
_0x3e0c38 = _0x48d200(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0x4], 0x7, -0xa83f051),
_0x257ec6 = _0x48d200(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0x5], 0xc, 0x4787c62a),
_0x1724c5 = _0x48d200(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0x6], 0x11, -0x57cfb9ed),
_0xdb4d2c = _0x48d200(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0x7], 0x16, -0x2b96aff),
_0x3e0c38 = _0x48d200(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0x8], 0x7, 0x698098d8),
_0x257ec6 = _0x48d200(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0x9], 0xc, -0x74bb0851),
_0x1724c5 = _0x48d200(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0xa], 0x11, -0xa44f),
_0xdb4d2c = _0x48d200(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0xb], 0x16, -0x76a32842),
_0x3e0c38 = _0x48d200(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0xc], 0x7, 0x6b901122),
_0x257ec6 = _0x48d200(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0xd], 0xc, -0x2678e6d),
_0x1724c5 = _0x48d200(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0xe], 0x11, -0x5986bc72),
_0xdb4d2c = _0x48d200(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0xf], 0x16, 0x49b40821),
_0x3e0c38 = _0x3180ec(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0x1], 0x5, -0x9e1da9e),
_0x257ec6 = _0x3180ec(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0x6], 0x9, -0x3fbf4cc0),
_0x1724c5 = _0x3180ec(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0xb], 0xe, 0x265e5a51),
_0xdb4d2c = _0x3180ec(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3], 0x14, -0x16493856),
_0x3e0c38 = _0x3180ec(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0x5], 0x5, -0x29d0efa3),
_0x257ec6 = _0x3180ec(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0xa], 0x9, 0x2441453),
_0x1724c5 = _0x3180ec(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0xf], 0xe, _0x4e96b4['_$tT']),
_0xdb4d2c = _0x3180ec(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0x4], 0x14, _0x4e96b4['_$Jy']),
_0x3e0c38 = _0x3180ec(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0x9], 0x5, 0x21e1cde6),
_0x257ec6 = _0x3180ec(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0xe], 0x9, -0x3cc8aa0a),
_0x1724c5 = _0x3180ec(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0x3], 0xe, -0xb2af279),
_0xdb4d2c = _0x3180ec(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0x8], 0x14, 0x455a14ed),
_0x3e0c38 = _0x3180ec(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0xd], 0x5, -0x5caa8e7b),
_0x257ec6 = _0x3180ec(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0x2], 0x9, -0x3105c08),
_0x1724c5 = _0x3180ec(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0x7], 0xe, 0x676f02d9),
_0xdb4d2c = _0x3180ec(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0xc], 0x14, -0x72d5b376),
_0x3e0c38 = _0x32032f(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0x5], 0x4, -0x241282e),
_0x257ec6 = _0x32032f(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0x8], 0xb, -0x788e097f),
_0x1724c5 = _0x32032f(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0xb], 0x10, 0x6d9d6122),
_0xdb4d2c = _0x32032f(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0xe], 0x17, -0x21ac7f4),
_0x3e0c38 = _0x32032f(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0x1], 0x4, -0x5b4115bc * b64pad),
_0x257ec6 = _0x32032f(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0x4], 0xb, 0x4bdecfa9),
_0x1724c5 = _0x32032f(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0x7], 0x10, -0x944b4a0),
_0xdb4d2c = _0x32032f(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0xa], 0x17, -0x41404390),
_0x3e0c38 = _0x32032f(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0xd], 0x4, 0x289b7ec6),
_0x257ec6 = _0x32032f(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3], 0xb, -0x155ed806),
_0x1724c5 = _0x32032f(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0x3], 0x10, -0x2b10cf7b),
_0xdb4d2c = _0x32032f(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0x6], 0x17, 0x2d511fd9),
_0x3e0c38 = _0x32032f(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0x9], 0x4, -0x3d12017),
_0x257ec6 = _0x32032f(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0xc], 0xb, -0x1924661b),
_0x1724c5 = _0x32032f(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0xf], 0x10, 0x1fa27cf8),
_0xdb4d2c = _0x32032f(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0x2], 0x17, -0x3b53a99b),
_0x3e0c38 = _0x4b459d(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3], 0x6, -0xbd6ddbc),
_0x257ec6 = _0x4b459d(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0x7], 0xa, 0x432aff97),
_0x1724c5 = _0x4b459d(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0xe], 0xf, -0x546bdc59),
_0xdb4d2c = _0x4b459d(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0x5], 0x15, -0x36c5fc7),
_0x3e0c38 = _0x4b459d(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0xc], 0x6, 0x655b59c3),
_0x257ec6 = _0x4b459d(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0x3], 0xa, -0x70ef89ee),
_0x1724c5 = _0x4b459d(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0xa], 0xf, -0x644f153),
_0xdb4d2c = _0x4b459d(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0x1], 0x15, -0x7a7ba22f),
_0x3e0c38 = _0x4b459d(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0x8], 0x6, 0x6fa87e4f),
_0x257ec6 = _0x4b459d(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0xf], 0xa, -0x1d31920),
_0x1724c5 = _0x4b459d(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0x6], 0xf, -0x5cfebcec),
_0xdb4d2c = _0x4b459d(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0xd], 0x15, 0x4e0811a1),
_0x3e0c38 = _0x4b459d(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 0x4], 0x6, -0x8ac817e),
_0x257ec6 = _0x4b459d(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 0xb], 0xa, -1120211379),
_0x1724c5 = _0x4b459d(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 0x2], 0xf, 0x2ad7d2bb),
_0xdb4d2c = _0x4b459d(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 0x9], 0x15, -0x14792c01),
_0x3e0c38 = _0x12e4a8(_0x3e0c38, _0x38ca59),
_0xdb4d2c = _0x12e4a8(_0xdb4d2c, _0x431764),
_0x1724c5 = _0x12e4a8(_0x1724c5, _0x43f1b4),
_0x257ec6 = _0x12e4a8(_0x257ec6, _0x5722c0);
return [_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6];
}
function _0x3180ec(_0x401705, _0x240e6a, _0x56b131, _0x5a5c20, _0x1f2a72, _0x2bfc1, _0x19741a) {
return _0xaaef84(_0x240e6a & _0x5a5c20 | _0x56b131 & ~_0x5a5c20, _0x401705, _0x240e6a, _0x1f2a72, _0x2bfc1, _0x19741a);
}
function _0x32032f(_0x520fdf, _0x13921d, _0x1af9d5, _0x4a2311, _0xb6d40a, _0x1d58da, _0x361df0) {
return _0xaaef84(_0x13921d ^ _0x1af9d5 ^ _0x4a2311, _0x520fdf, _0x13921d, _0xb6d40a, _0x1d58da, _0x361df0);
}
function _0x4b459d(_0x8d8f2a, _0x406d34, _0x53e7d7, _0x26c827, _0xec41ea, _0x52dead, _0x3f66e7) {
return _0xaaef84(_0x53e7d7 ^ (_0x406d34 | ~_0x26c827), _0x8d8f2a, _0x406d34, _0xec41ea, _0x52dead, _0x3f66e7);
}
function _0x12e4a8(_0x7542c8, _0x5eada0) {
var _0x41f81f = (0xffff & _0x7542c8) + (0xffff & _0x5eada0);
return (_0x7542c8 >> 0x10) + (_0x5eada0 >> 0x10) + (_0x41f81f >> 0x10) << 0x10 | 0xffff & _0x41f81f;
}
function _0x2d5f5b() {
return new _0x35bb1d()['valueOf']();
}
function get_params() {
let prs = []
_0x4e96b4['_$Jy'] = 461512024
_0x4e96b4['_$tT'] = -172015004
_0x4e96b4['_$6_'] = 8821003647
for (let i = 1; i < 5; i++) {
prs['push'](_0x474032(_0x12eaf3()))
console.log('_$6_=', _0x4e96b4['_$6_'], '\t_$tT=', _0x4e96b4['_$tT'], '\t_$Jy=', _0x4e96b4['_$Jy'], '\t _$Wa=', _0x12eaf3(), '\t m=', _0x474032(_0x12eaf3()))
_0x4e96b4['_$Jy'] = _0x2d5f5b();
_0x4e96b4['_$tT'] = -678335
}
_0x4e96b4['_$Jy'] = -405537848
_0x4e96b4['_$tT'] = -660478335
_0x4e96b4['_$6_'] = -389564586
_$is = _0x2d5f5b()["toString"]()
// _$is = '1774430921160'
cookie_m = _0x474032(_$is)
prs['push'](cookie_m)
// console.log(prs)
key = CryptoJS['enc']['Utf8']["parse"](btoa(_$is)['slice'](0x0, 0x10))
_$Ww = CryptoJS["enc"]["Utf8"]["parse"](prs["toString"]())
_0x29dd83 = CryptoJS["AES"]["encrypt"](_$Ww, key, {
'mode': CryptoJS["mode"]["ECB"],
'padding': CryptoJS["pad"]["Pkcs7"]
})
return {
'cookie_m': cookie_m,
'RM4hZBv0dDon443M': _0x29dd83.toString(),
'm': _$is,
'f': Date.parse(new Date())
}
}
console.log(get_params())
说明:上面的
b.js是还原后的可运行版本。它依赖 Node 环境的require('crypto-js'),因此execjs的运行时必须是 Node。MD5 部分为手写实现,AES 部分走 crypto-js。
五、踩坑记录
| # | 坑 | 说明 / 解决 |
|---|---|---|
| 1 | AES 的 key 顺序 | key 来自 btoa(时间戳) 的前 16 字节,一定要先 btoa 再 slice(0, 16),顺序反了签名就不对。 |
| 2 | URL 的 m 与 Cookie 的 m 不是同一个东西 |
URL 参数 m 是时间戳;Cookie 里的 m 是 MD5(时间戳字符串)。别拿错。 |
| 3 | RM4hZBv0dDon443M 这个 cookie 名带随机性 |
实际以当前页面为准,页面 JS 里生成的键名可能变化,抓包确认后再写死。 |
| 4 | execjs 需要 window=global,并处理好 BOM |
Node 里没有 window,用 window = global 兜底;读取 JS 文件用 utf-8-sig 并手动 replace('',''),否则语法报错。 |
| 5 | f 和 m 都是时间戳但含义略不同 |
m 是字符串时间戳(Date.now().toString()),f 是 Date.parse(new Date()),本质都是毫秒时间戳。 |
| 6 | 第 5 页 UA | 前 4 页普通 UA 即可,第 5 页必须 yuanrenxue,否则拿不到数据或校验失败。 |
| 7 | sessionid 必须带 |
每个登录用户的答案不同,不带 sessionid 拿不到自己的数据。 |
六、总结
第5题本质是把「时间戳 → MD5 → AES-ECB」这条签名链藏进乱码增强的手写 MD5 里。逆向时抓住 get_params() 的四个返回值即可:m、f 是两个时间戳,cookie_m 是时间戳的 MD5,RM4hZBv0dDon443M 是「5 个 MD5 串拼接」的 AES-ECB 密文。把还原后的 JS 整理成 b.js,用 execjs 调用生成签名,再用 requests 组装参数和 cookie 逐页请求、累加 data 求和即得到答案。

浙公网安备 33010602011771号