js攻防对抗之混淆加强 - Touale Cula's Blog

此题来源于某一个对抗网站,无聊玩玩分析和对抗,锻炼锻炼自己的逻辑和分析能力!

该题还是有些东西了,需要运用一些技巧,分析过程极其头疼,调试过程中经常出现运行结果和执行结果不同!


题目内容

任务5:抓取全部5页直播间热度,计算前5名直播间热度的加和

注:本页cookie有效期仅有50秒钟


初步分析

请求内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET https://match.yuanrenxue.com/api/match/5?page=2&m=1650885312646&f=1650885310000 HTTP/1.1
Host: match.yuanrenxue.com
Connection: keep-alive
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="100", "Microsoft Edge";v="100"
Accept: application/json, text/javascript, */*; q=0.01
DNT: 1
X-Requested-With: XMLHttpRequest
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36 Edg/100.0.1185.50
sec-ch-ua-platform: "Windows"
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://match.yuanrenxue.com/match/5
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: qpfccr=true; sessionid=2ioqt7zbtvl0l8ka71uf5cr7fv0; Hm_lvt_c99546cf032aDKyPQ40QcUVwUqI+yx6Uj6tposl4mB+LxqtUHxqFle03TFpxiJ8emtqPSPZr6gZ6LHnuMv3ofR7QKuQmQc=


返回内容:

1
2
3
4
5
6
7
8
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 25 Apr 2022 11:15:46 GMT
Content-Type: application/json
Content-Length: 215
Connection: keep-alive

{"status": "1", "state": "success", "data": [{"value": 6481}, {"value": 5877}, {"value": 2243}, {"value": 8356}, {"value": 5741}, {"value": 5339}, {"value": 5937}, {"value": 2232}, {"value": 2032}, {"value": 2446}]}

将请求进行重放,发现返回内容为空;对返回头进行系查看,发现返回头正常,说明服务器响应正常

keep-alive
1
2
3
4
Date: Mon, 25 Apr 2022 11:17:33 GMT
Content-Length: 0
Content-Type: text/html; charset=utf-8
Server: nginx

那么应该就是提交的参数存在问题,回想题目存在cookie50秒有效,猜测可能是cookie过期,应该不是由于数据包的单一禁重放问题,那么重新抓包,并马上二次发送

1
{"status": "1", "state": "success", "data": [{"value": 7880}, {"value": 1179}, {"value": 8637}, {"value": 6510}, {"value": 6346}, {"value": 3460}, {"value": 3690}, {"value": 8395}, {"value": 2406}, {"value": 5634}]}

OK,返回正常。对cookie参数以及url参数进行二分法发送和修改,发现参数中m,f,以及cookie中的m和RM4hZBv0dDon443M是必要的!

那么可以有一个初步结论,那么就是url中的参数是时间戳,两者是否存在相关性不确定,但是两者应该和cookie的参数存在强烈的相关性,也就是cookie应该是由m和f生成的!


深度分析

ok,基本可以确定本次攻防是和cookie有关,那么只需要等待50秒或者将cookie修改成错误的值,使cookie重新生成,并且定位到cookie生成的位置,那么基本就能得到题目的解了!


对于cookie生成的定位,可以通过hook使其生成时中断,然后查看堆栈即可定位到,hook代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// ==UserScript==
// @name Hook Cookie
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @include *
// @grant none
// @run-at document-start
// ==/UserScript==

Object.defineProperty(document, 'cookie', {
set: function(value) {
debugger;
return value;
},
});

在开发者工具的调试器中输入该代码,并修改本地存储的cookie,使其cookie错误开始生成


ok,点击下一页,理论上就会触发断点

但从实际操作发现,并没有发生断点,进行调试检查操作。重新输入hook代码,在console处输入:

1
document.cookie=""

成功断下来,说明hook代码没问题,那么继续定位刚刚的问题,重新点下一页,还是没有断下来,再次在console处修改cookie,发现此时并没有成功断下来

经过上面的问题定位,可以基本确认可能是点击下一页后导致hook代码失效,也就是说是页面刷新导致的!

此时,解决方案如下,利用油小猴插件,注入脚本代码,在页面载入时自动注入hook代码即可!


注入后,成功断下来,观察堆栈信息

将其在控制台打印,可以基本确认此处是cookie的m生成值,$Wa 是1650886418000,_0x474032($Wa)是’69e2b50c58fa7c93da4ba854306fe5e0’。这里进行小小的猜测,对1650886418000进行md5加密是4ef47f4ebd857f2efc40f1749239ff3b,那么 _0x474032应该不是一个简单的md5加密函数!

此时进入_0x474032定义处

1
2
3
function _0x474032(_0x233f82, _0xe2ed33, _0x3229f9) {
return _0xe2ed33 ? _0x3229f9 ? v(_0xe2ed33, _0x233f82) : y(_0xe2ed33, _0x233f82) : _0x3229f9 ? _0x41873d(_0x233f82) : _0x37614a(_0x233f82);
}

这是一个简单的混淆,利用控制台对三元判断进行筛选,可以得到函数解混淆是:

1
2
3
function _0x474032(_0x233f82, _0xe2ed33, _0x3229f9) {
return _0x37614a(_0x233f82)
}

再次进入_0x37614a,找到定义,下个断点

1
2
3
function _0x37614a(_0x32e7c1) {
return _0x499969(_0x41873d(_0x32e7c1));
}

不难发现,_0x32e7c1是1650886418000,_0x41873d(_0x32e7c1)运算后结果是’iâµ\fXú|\x93ÚK¨T0oåà’,再进行_0x499969(‘iâµ\fXú|\x93ÚK¨T0oåà’)得到’69e2b50c58fa7c93da4ba854306fe5e0’。

此时分为两步,分别分析_0x41873d和,再进行_0x499969。一步一步分析,虽然过程不是很顺利,但是最终也可得到结果。


ok,那么下一个分析RM4hZBv0dDon443M的生成,RM4hZBv0dDon443M定位还是有点难的

还是一样,下hook断点,定位生成的地方

1
2
3
4
5
try {
_0x3d0f3f[_$Fe] = 'R' + 'M' + '4' + 'h' + 'Z' + 'B' + 'v' + '0' + 'd' + 'D' + 'o' + 'n' + '4' + '4' + '3' + 'M=' + _0x4e96b4['_$ss'] + ';\x20path=/';
} catch (_0x5399ac) {
_0x3d0f3f[_$Fe] = 'R' + 'M' + '4' + 'h' + 'Z' + 'B' + 'v' + '0' + 'd' + 'D' + 'o' + 'n' + '4' + '4' + '3' + 'T=' + '=True;\x20path=/';
}

很明显,此处 ‘R’ + ‘M’ + ‘4’ + ‘h’ + ‘Z’ + ‘B’ + ‘v’ + ‘0’ + ‘d’ + ‘D’ + ‘o’ + ‘n’ + ‘4’ + ‘4’ + ‘3’ 是为了防止被搜索得到,并且将 _0x4e96b4[‘_$ss’]得到

1
2
3

_0x4e96b4['_$ss']
'4YdsK7l1cxkyOncsZ+PsF6dlJF1G9NaEDwPSVc0pWsWBXxzbmb7RlsBVegcRDL/v3/hHJba/RySK+nJvfKHa7215u7ScHaIxwDNqgumavj19vcyrFqHwEGjgoPMGSNU4D2iCTFXKDcDh62fQS/LMDGk5zNznY/fm1hrRyMxuH9c4Afas/4/KJfEDrY162S8YWUZoKJJUPRuAXmrw7ZOhzWdrqSCfHoRQsclDh0rNcTE='

那么就知道RM4hZBv0dDon443M应该是和_0x4e96b4[‘_$ss’]挂钩,也就是说,只要找到_0x4e96b4[‘_$ss’]赋值的地方就行了,ok,直接搜索_0x4e96b4[‘_$ss’],发现仅有一次,没有对他赋值的地方,应该是在赋值的过程中混淆了

对堆栈进行检查,仅发现四处堆栈,且关系不是很大

进入该函数

发现这里是一个while循环,并且不断的判断,猜测应该是不断对if下再次赋值再次if,不断的控制流然后赋值。此处可以用一个比较巧妙的方式,在第一个if处进行断点,且该断点是日志断点,打印出_0x456805和_0x4e96b4[‘_$ss’],那么就可以知道_0x4e96b4[‘_$ss’]是在什么时候被赋值了,日志断点代码如下:

1
_0x456805, _0x4e96b4['_$ss']

发现日志打印如下:

1
2
3
4
5
6
7
8
9
10
11
12
VM15735:1 353 undefined
VM15736:1 212 undefined
VM15737:1 490 undefined
VM15738:1 190 undefined
VM15739:1 450 undefined
VM15740:1 56 undefined
VM15741:1 56 undefined
VM15742:1 154 undefined
VM15744:1 406 'aG2dz6vi3S1FhsLExLIe9rKBp/kqX1Ly+yVPIZVDFnP5MHcj+ZUHENKI+Alh8sm7NPgG2aj4EEuYOkdnP4GjsLT21pCH8dUzSln5HYoPBL0qZACSHzg0w9edxP60JaN+hC8Qf/j3E5TYdF/0GV1/AINZUkogz363v9M+rtYqWpXgqHK8c3HmJZyuwZQHdEtYmst7bChpfG8KsvM+pyjja5gWwvQDVRXK8gg0WqPwB3Y='
VM15745:1 438 'aG2dz6vi3S1FhsLExLIe9rKBp/kqX1Ly+yVPIZVDFnP5MHcj+ZUHENKI+Alh8sm7NPgG2aj4EEuYOkdnP4GjsLT21pCH8dUzSln5HYoPBL0qZACSHzg0w9edxP60JaN+hC8Qf/j3E5TYdF/0GV1/AINZUkogz363v9M+rtYqWpXgqHK8c3HmJZyuwZQHdEtYmst7bChpfG8KsvM+pyjja5gWwvQDVRXK8gg0WqPwB3Y='
VM15746:1 406 'aG2dz6vi3S1FhsLExLIe9rKBp/kqX1Ly+yVPIZVDFnP5MHcj+ZUHENKI+Alh8sm7NPgG2aj4EEuYOkdnP4GjsLT21pCH8dUzSln5HYoPBL0qZACSHzg0w9edxP60JaN+hC8Qf/j3E5TYdF/0GV1/AINZUkogz363v9M+rtYqWpXgqHK8c3HmJZyuwZQHdEtYmst7bChpfG8KsvM+pyjja5gWwvQDVRXK8gg0WqPwB3Y='
VM15747:1 438 'aG2dz6vi3S1FhsLExLIe9rKBp/kqX1Ly+yVPIZVDFnP5MHcj+ZUHENKI+Alh8sm7NPgG2aj4EEuYOkdnP4GjsLT21pCH8dUzSln5HYoPBL0qZACSHzg0w9edxP60JaN+hC8Qf/j3E5TYdF/0GV1/AINZUkogz363v9M+rtYqWpXgqHK8c3HmJZyuwZQHdEtYmst7bChpfG8KsvM+pyjja5gWwvQDVRXK8gg0WqPwB3Y='

也就是说,0x4e96b4[‘$ss’]应该是在154这个过程中找到的,那么只要我们进入154的判断,就能找到生成的地方了。

但,事实上,代码经过混淆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
while (0x1) {
_0x456805 = _0x5aa5a3[_0x89f606++];
if (_0x456805 < 0x100) {
if (_0x456805 < 0x40) {
if (_0x456805 < 0x10) {
if (_0x456805 < 0x4) {
if (_0x456805 < 0x1) {
return _$iJ;
} else if (_0x456805 < 0x2) {
_0x2566fa = _0x4664b4(0xeb, _$UH[0x32]);
} else if (_0x456805 < 0x3) {
_$Ig++;
} else {
_0x4664b4(0x91, 0x8000000, 0x29);
}
} else if (_0x456805 < 0x8) {
if (_0x456805 < 0x5) {
var _0x408786 = new _$gN();
} else if (_0x456805 < 0x6) {
_0x4538a3 = _$O3 != _$pS[_$UH[0x9d]] || _$1Z != _$pS[_$UH[0xde]] || _$58 != _$pS[_$UH[0x184]];
} else if (_0x456805 < 0x7) {
_0x4538a3 = _0x4664b4(0x8a);
} else {
_0x5e2d07 = _$tR[_$UH[0x9]]('div');
}
} else if (_0x456805 < 0xc) {
if (_0x456805 < 0x9) {
var _0x2566fa = '';
} else if (_0x456805 < 0xa) {
_0x4538a3 = _0x2566fa;
} else if (_0x456805 < 0xb) {
var _0x4ee652 = _$lh(_$Re(0x19));
} else {
_0x4538a3 = _$tR[_$UH[0x29]];
}
} else {
if (_0x456805 < 0xd) {
_$pS = _$_M['Math'][_$UH[0x1f]](_$pS);
} else if (_0x456805 < 0xe) {
_0x4538a3 = _0x4664b4(0x80);
} else if (_0x456805 < 0xf) {
_0x89f606 += 0x1;
} else {
_0x4538a3 = _$Yp != _$iJ;
}
}
} else if (_0x456805 < 0x20) {
...

首先他不是以明文数字进行判断,而是十六进制,如果人为肉眼识别16进制,还是非常麻烦的。并且他的顺序并不是从小到大或者从大到小的,所以154的判断分支也不一定只有一个,还有判断的过程中是否和上一个if值有关。

一个折中的方法,就是进行条件断点,比如说当xxx == 154时中断下来,但是这个过程中xxx== 154的有很多个,从下面的代码可以看到整个循环不包括if判断就有800次,如果加上if判断,可以呈现几万次控制流行动。

1
2
3
4
5
for (var _0x307e6a = 0x0; _0x307e6a <= 0x320; _0x307e6a++) {
try {
_0x4664b4(_0x307e6a);
} catch (_0x145856) {}
}

ok,如何解决上面的难题呢?一个很巧妙的方式如下,既然要找154,并且这个154要求下一步是生成_0x4e96b4[‘_$ss’]的地方,那么如果能将上述的值进行关联,也就是说,如果能确定最后三个值分别是56,56,154,那么就能确定这个154是我们要找的154,并且这个154是生成_0x4e96b4[‘_$ss’]的地方!


在while开始前,下一个条件断点,代码如下:

1
if (_0x5aa5a3[_0x89f606] == 154 && _0x5aa5a3[_0x89f606 - 1] == 56 && _0x5aa5a3[_0x89f606 - 2] == 56) { true }

成功断下后,单步走,发现敏感位置,有点像ob混淆,单步走到生成位置

发现关键代码,最关键的是’_$‘ + _$UH[0x348][0x1] + $UH[0x353][0x1]就是’$ss’,也就是说_0x4e96b4[‘_$‘ + _$UH[0x348][0x1] + _$UH[0x353][0x1]]就是_0x4e96b4[‘_$ss’],此处为_0x4e96b4[‘_$ss’]赋值位置!

1
2
3
4
5
6
7
8
_0x43e7b7(),
_$Ww = _$Tk[_$UH[0x2db]][_$UH[0x2dc]][_$UH[0xff]](_0x4e96b4['_$pr'][_$UH[0x1f]]()),
_0x29dd83 = _$Tk['A' + _$UH[0x32d]][_$UH[0x337] + _$UH[0x336]](_$Ww, _0x4e96b4[_0xc77418('0x6', 'OCbs')], {
'mode': _$Tk[_$UH[0x339] + _$UH[0x33a]][_$UH[0x2e5]],
'padding': _$Tk[_$UH[0x33b]][_$UH[0x33c] + _$UH[0x33d]]
}),
_0x4e96b4['_$' + _$UH[0x348][0x1] + _$UH[0x353][0x1]] = _0x29dd83[_$UH[0x1f]]();

对上述代码进行调试后,发现生成值应该就是:

1
2
3
4
5
6
7
8
9
_$Ww = _$Tk[_$UH[0x2db]][_$UH[0x2dc]][_$UH[0xff]](_0x4e96b4['_$pr'][_$UH[0x1f]]()),

_$Tk[_$UH[0x2db]][_$UH[0x2dc]][_$UH[0xff]](_0x4e96b4['_$pr'][_$UH[0x1f]]()),
_0x29dd83 = _$Tk['A' + _$UH[0x32d]][_$UH[0x337] + _$UH[0x336]](_$Ww, _0x4e96b4[_0xc77418('0x6', 'OCbs')], {
'mode': _$Tk[_$UH[0x339] + _$UH[0x33a]][_$UH[0x2e5]],
'padding': _$Tk[_$UH[0x33b]][_$UH[0x33c] + _$UH[0x33d]]
}).toString()

'qXl7jh5cHCSZS/RA7UZb+quOaBkKUCW8sERG1L5frtKyssYtyPbBuDPc3vBKmrr6o1aliq0S1gXc29VZBy9io54hi2Mb8GpB7NqhryqDMBC3gvqG2wDnIC72j3DjM3e8UmMkRzhzlJ8M87BW8HoD8PiPTzHcuruMpPBeQM9LpN1Fk+NJYPDTT+26bvD9hSAdXQWil5QN8fD0BN4Xo0B/ymHsX8H67/IIEwEtEaBu3/w='

继续分析,_$Ww 是一个41长的数组,对他进行还原

1
2
3
4
5
6
7
8
9
10
11
_0x4e96b4['_$pr']=[
"16df00d232f74085f681f479ce0a0694",
"1933e1a9e7e726ce1ec61bdf8a0281a4",
"dba981c2b9007997ce642776ce9d103a",
"79ddcfb2539fb2cee6203b1751ab81f9",
"43347d34aa73fbbd5ddc74598e72a5e1"
]

var _$Tk = CryptoJS;

_$Ww = _$Tk['enc']['Utf8']['parse'](_0x4e96b4['_$pr']['toString']()),

对生成位置进行还原

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
_0x4e96b4['_$qF'] = {
"words": [
1297373489,
1296328500,
1330923898,
1330924920
],
"sigBytes": 16
}
var _$Tk = CryptoJS;

_0x29dd83 = _$Tk['AES']['encrypt'](_$Ww, _0x4e96b4['_$qF'], {
'mode': _$Tk['mode']['ECB'],
'padding': _$Tk['pad']['Pkcs7']
})

ok,那么加密应该就是AES,AES导入可以通过封包搜索找到以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<script src="/static/src/core.js"></script>
<script src="/static/src/lib-typedarrays.js"></script>
<script src="/static/src/x64-core.js"></script>
<script src="/static/src/enc-utf16.js"></script>
<script src="/static/src/enc-base64.js"></script>
<script src="/static/src/md5.js"></script>
<script src="/static/src/sha1.js"></script>
<script src="/static/src/sha256.js"></script>
<script src="/static/src/sha224.js"></script>
<script src="/static/src/sha512.js"></script>
<script src="/static/src/sha384.js"></script>
<script src="/static/src/sha3.js"></script>
<script src="/static/src/ripemd160.js"></script>
<script src="/static/src/hmac.js"></script>
<script src="/static/src/pbkdf2.js"></script>
<script src="/static/src/evpkdf.js"></script>
<script src="/static/src/cipher-core.js"></script>
<script src="/static/src/mode-cfb.js"></script>
<script src="/static/src/mode-ctr.js"></script>
<script src="/static/src/mode-ofb.js"></script>
<script src="/static/src/mode-ecb.js"></script>
<script src="/static/src/pad-ansix923.js"></script>
<script src="/static/src/pad-iso10126.js"></script>
<script src="/static/src/pad-zeropadding.js"></script>
<script src="/static/src/pad-iso97971.js"></script>
<script src="/static/src/pad-nopadding.js"></script>
<script src="/static/src/rc4.js"></script>
<script src="/static/src/rabbit.js"></script>
<script src="/static/src/rabbit-legacy.js"></script>
<script src="/static/src/aes.js"></script>
<script src="/static/src/tripledes.js"></script>

将上述代码进行合并写入同一个js即可调用aes了。

那么剩下最后两个问题,一个是_0x4e96b4[‘_$qF’]怎么来的,一个是_0x4e96b4[‘_$pr’]。

先分析下_0x4e96b4[‘_$qF’],通过搜索得到

即如下,通过打印发现_0x4e96b4[‘_$is’]是’1650889239317’,基本确定应该是和url中的参数有关。

1
2
_0x4e96b4 = window;
_0x4e96b4['_$qF'] = CryptoJS['enc']['Utf8']['parse'](_0x4e96b4['btoa'](_0x4e96b4['_$is'])

相比_0x4e96b4[‘_$qF’],_0x4e96b4[‘_$pr’]的分析就有点困难了。

还是整体搜索,找到有关的地方,发现有7处

1
2
3
4
5
6
7
8
9
10
11
_0x4e96b4['_$pr'] = new _0x4d2d2c();

_0x4e96b4['_$pr']['push'](_0x474032(_$yw));

delete _0x4e96b4['_$pr'];

_0x4e96b4['_$pr']['push'](_0x474032(_$yw));

_0x4e96b4['_$pr']['push'](_0x474032(_0x3986ae));

_0x4e96b4['_$pr']['push'](_0x474032(_$Wa));

对他们分别打上断点,_0x4d2d2c()是[],作用是新建一个数组吧,发现相关的仅有

1
2
 _0x4e96b4['_$pr']['push'](_0x474032(_$yw));
_0x4e96b4['_$pr']['push'](_0x474032(_$Wa));

可以基本确定_0x474032生成的,在这两处打上日志断点,分别输出传入值和传出值

1
_$yw,_0x474032(_$yw)

得到5个值得,可以确定传入值4个一样,一个不同,并且这两个值来源于url中,都是有个问题,传入值相同,可传出值不同。

1
2
3
4
5
6
7
VM190324:  1650890846000 'aeb9062cfd96d41d94822c42fd158605'
VM190324:1 1650890846000 '26125bec564097f80f4143a4e8e5f91a'
VM190329:1 1650890846000 'c7982e7cbd7ed159eeb1f9bc16ea7fd4'
VM190334:1 1650890846000 '92190be1f9977e3709f04962ca0875cb'
VM190314:1 世上无难事,只要肯放弃
VM190314:1 世上无难事,只要肯放弃
VM190342:1 1650890846683 ff7a3ac709c7c70e36f467887baf8a96

对push位置进行分析,看一下执行后是否存在修改其他值

1
2
3
4
5
6
_0x4e96b4['_$pr']['push'](_0x474032(_$Wa));
delete _0x4e96b4['_$Jy'];
delete _0x4e96b4['_$tT'];
_0x4e96b4['_$Jy'] = _0x2d5f5b();
_0x4e96b4['_$tT'] = _0x2d5f5b() - _0x12eaf3();
return;

果然,push后,对两个关键值进行了修改,对_0x2d5f5b,_0x12eaf3定义分析

1
2
3
function _0x2d5f5b() {
return new _0x35bb1d()['valueOf']();
}
1
2
3
function _0x12eaf3() {
return _0x35bb1d[_$UH[0xff]](new _0x35bb1d());
}

调试后进行解混淆

1
2
3
function _0x2d5f5b() {
return new Date()['valueOf']();
}
1
2
3
function _0x12eaf3() {
return Date['parse'](new Date());
}

ok,基本解决了这两个参数,那么最后进行个收尾工作,进行封装


实验

生成url和cookie代码:

1
2
3
4
5
6
function getReq(t_f,page) {
var l = [];
l.push("https://match.yuanrenxue.com/api/match/5?page=" + page + "&m=" + t_f + "&f=" + t_f);
l.push("m=" + getCookie_m(t_f) + "; " + "RM4hZBv0dDon443M=" + generateCookie_RM4hZBv0dDon443M(t_f,t_f))
return JSON.stringify(l);
}

生成RM4hZBv0dDon443M代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function generateCookie_RM4hZBv0dDon443M(t_f, t_m) {

var _$Tk = CryptoJS;
var _0x4e96b4 = window;
_0x4e96b4['btoa'] = encode;
_0x4e96b4['_$is'] = t_m;
_0x4e96b4['_$qF'] = CryptoJS['enc']['Utf8']['parse'](_0x4e96b4['btoa'](_0x4e96b4['_$is'])['slice'](0x0, 0x10));

let currentList = getList(t_f, t_m)
_0x4e96b4['_$pr'] = currentList;
//console.log(currentList)

_$Ww = _$Tk['enc']['Utf8']['parse'](_0x4e96b4['_$pr']['toString']())
_0x29dd83 = _$Tk['AES']['encrypt'](_$Ww, _0x4e96b4['_$qF'], {
'mode': _$Tk['mode']['ECB'],
'padding': _$Tk['pad']['Pkcs7']
})

//console.log(_0x29dd83['toString']())
return _0x29dd83['toString']();
}

function getList(t_f, t_m) {
_0x4e96b4['_$tT'] = -0xa40bd9c;
_0x4e96b4['_$Jy'] = 0x1b821d58;
_0x4e96b4['_$6_'] = 0x20dc5d57f;
var l = [];
for (let i = 0; i < 4; i++) {
l.push(_0x474032(t_f))
delete _0x4e96b4['_$Jy'];
delete _0x4e96b4['_$tT'];
_0x4e96b4['_$Jy'] = _0x2d5f5b();
_0x4e96b4['_$tT'] = _0x2d5f5b() - _0x12eaf3();
}

_0x4e96b4['_$tT'] = -0x275e197f;
_0x4e96b4['_$Jy'] = -405537848;
_0x4e96b4['_$6_'] = -389564586;
l.push(_0x37614a(t_m))
return l;
}

生成m代码:

1
2
3
function _0x37614a(_0x32e7c1) {
return _0x499969(_0x41873d(_0x32e7c1));
}

调用结果:

1
2
3
4
["https://match.yuanrenxue.com/api/match/5?page=1&m=1650879335110&f=1650879335110",
"m=c025cc90255d5dfa8fa0fe22d7108ed8;
RM4hZBv0dDon443M=R+1XihBS2Mg/Xpn9wdRXLS7hs7XxNoepWDqzmBZXvN7yQXjKZXFXRRZnmkSryBTZFiI/pE5x5Qe/D/NuufJg7oiI8zVl1bH8OOvHzJnU6D6EIa8k1zjprSc0Mcu9RwSrk4hfRL8/9qc1v4ecFTmmSBZUqN6S3ULKHZ0P5HZyfx3zmSEkn2+46O3d6LglE5ztoNJpeJuHSffbh1lx2nVefOaWZ+CrKq+ms6wsgysWg7o="]

解答题目:

1
2
3
4
5
6
* “{"status": "1", "state": "success", "data": [{"value": 3401}, {"value": 9806}, {"value": 1497}, {"value": 5012}, {"value": 5676}, {"value": 4509}, {"value": 8380}, {"value": 6019}, {"value": 3862}, {"value": 1989}]}”
* “{"status": "1", "state": "success", "data": [{"value": 6481}, {"value": 5877}, {"value": 2243}, {"value": 8356}, {"value": 5741}, {"value": 5339}, {"value": 5937}, {"value": 2232}, {"value": 2032}, {"value": 2446}]}”
* “{"status": "1", "state": "success", "data": [{"value": 7880}, {"value": 1179}, {"value": 8637}, {"value": 6510}, {"value": 6346}, {"value": 3460}, {"value": 3690}, {"value": 8395}, {"value": 2406}, {"value": 5634}]}”
* “{"status": "1", "state": "success", "data": [{"value": 4470}, {"value": 4372}, {"value": 2526}, {"value": 7526}, {"value": 8484}, {"value": 212}, {"value": 9625}, {"value": 2594}, {"value": 7976}, {"value": 7448}]}”
* “{"status": "1", "state": "success", "data": [{"value": 6020}, {"value": 4381}, {"value": 1044}, {"value": 9368}, {"value": 2701}, {"value": 5777}, {"value": 6985}, {"value": 9877}, {"value": 8555}, {"value": 1897}]}”
* 数组:50{9877,9806,9625,9368,8637,8555,8484,8395,8380,8356,7976,7880,7526,7448,6985,6510,6481,6346,6020,6019,5937,5877,5777,5741,5676,5634,5339,5012,4509,4470,4381,4372,3862,3690,3460,3401,2701,2594,2526,2446,2406,2243,2232,2032,1989,1897,1497,1179,1044,212}

成功过关!

总结

请问有什么话想说的吗?

  • 加密处居然出现了3处,虽说混淆程度还是很低,但是很难受

  • 这道题其实有瑞数的影子,真的,首先官网明说了,后面自己做的时候感受到了。瑞数是反爬界的大山,大山。。。。