猿人学第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/5
  • user-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 求和即得到答案。

posted @ 2026-11-08 00:24  Johnjincaaa  阅读(4)  评论(0)    收藏  举报