猿人学-JS逆向第一届第1题

猿人学-JS逆向第一届第1题

Xxi | 晞晞的小世界 Lv1

猿人学-JS逆向第一届第1题

hello,大家好,这里是Xxi,

今天给大家带来猿人学-JS逆向第一届的第1题,也是我的第一篇教学文章

题目内容

目标网站:https://match.yuanrenxue.cn/match/1

题目1:抓取所有(5页)机票的价格,并计算所有机票价格的平均值填入答案。

抓包分析

在F12的时候,会触发一个无限debugger,我们只需要在debugger的那一行右键,

进行一个’修改断点’,输入:false,就可以解开无限debugger的问题(如下图所示)

而通过抓包后,我们会发现返回的数据是没有加密的,而加密的数据是在请求体

里面的m值是有加密的(如下图所示)

加密定位

既然已经确定了加密的数据,那我们就进行一个加密位置的定位。

我们进行调用的堆栈的查看,会发现除了一个request的堆栈跟其它的不一样(如下图)

知识点普及:jquery

jQuery作为官方维护的一个前端库,

其代码均源自开源仓库且无第三方修改记录,

遇到的话可直接排除篡改风险。

所以排除下来,只剩下request这个堆栈可以去看看。

加密逻辑

打开VM15042:6这个堆栈后,会发现代码进行了一个ob混淆(如下图)

我们可以借助猿人学官方的一个工具,网址是:https://tool.yuanrenxue.cn/decode_obfuscator

配置如下:

进行解除混淆后,我们放到pycharm进行观察,

可以发现,m值的一个生成过程(代码如下)

1
"m": _0x57feae + "丨" + _0x2268f9 / 1000

我们逐个来分析:

首先是_0x57feae,它的生成过程如下:

1
_0x57feae = oo0O0(_0x2268f9["toString"]()) + window["f"];

而在_0x57feae里面用到的_0x2268f9生成的过程如下:

1
_0x2268f9 = Date["parse"](new Date()) + 100000000

代码解读:_0x2268f9 = 时间戳 + 100000000

整体逆向的逻辑是:将_0x2268f9传入_0x57feae里面

而m值是:m = _0x57feae + “丨” + _0x2268f9 / 1000

加密逆向

_0x57feae的逻辑是oo0O0(_0x2268f9“toString”) + window[“f”]

我们先研究oo0O0(_0x2268f9“toString”),

在_0x57feae这一行打上断点,发现oo0O0(_0x2268f9“toString”)是空值,

那反过来也就是说,我们要的值是在window[“f”],

在控制台输出window[“f”],发现是有值的(如下图)

像window[“f”]这种取值方式,其实是向字典里面去取值,

而向字段里面取值就代表着,这个值肯定是个固定值,

而字典的话,肯定是需要去进行一个赋值,才能通过里面去取值。

所以我们去判断一下,oo0O0(_0x2268f9“toString”)是否在进行赋值。

我们进去oo0O0的源代码,去里面找window[“f”]的赋值过程。

但是翻找了一圈,我们会发现找不到window[“f”]的所在。

但是这个时候,出现了一个eval的函数调用(代码如下):

1
eval(atob(window['b'])[J('0x0', ']dQW')](J('0x1', 'GTu!'), '\x27' + mw + '\x27'));

知识点普及:eval

eval与Base64结合可实现代码混淆,

eval(解密base64加密字符串),

eval能够执行字符串格式的js代码,

而base64又能够对字符串进行加密。

在前端是通过atob解码、btoa加密配合使用。

我们将eval这一行打上断点,

然后进行在控制台输入:atob(window[‘b’])[J(‘0x0’, ‘]dQW’)](J(‘0x1’, ‘GTu!’), ‘\x27’ + mw + ‘\x27’)

我们得到解密的源代码(如下图)

我们丢到pycharm里面格式一下,得到了window[“f”]的生成过程:

1
window.f = hex_md5('1747341285000')

逆向代码

到现在为止,我们已经找到了所有加密的值的生成过程,接下来就是代码部分。

改写前的m值生成过程代码:

1
2
3
4
5
6
7
var _0x2268f9 = Date["parse"](new Date()) + 100000000,
_0x57feae = oo0O0(_0x2268f9["toString"]()) + window["f"];

const _0x5d83a3 = {
"page": window["page"],
"m": _0x57feae + "丨" + _0x2268f9 / 1000
};

改写后的m值生成过程代码:

1
2
3
4
5
6
7
function get_m() {

var _0x2268f9 = Date["parse"](new Date()) + 100000000,
_0x57feae = hex_md5(_0x2268f9.toString());

return _0x57feae + "丨" + _0x2268f9 / 1000
}

结合window[“f”]的生成过程后,js的所有代码如下:

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
var hexcase = 0;
var b64pad = "";
var chrsz = 16;

function hex_md5(a) {
return binl2hex(core_md5(str2binl(a), a.length * chrsz))
}

function b64_md5(a) {
return binl2b64(core_md5(str2binl(a), a.length * chrsz))
}

function str_md5(a) {
return binl2str(core_md5(str2binl(a), a.length * chrsz))
}

function hex_hmac_md5(a, b) {
return binl2hex(core_hmac_md5(a, b))
}

function b64_hmac_md5(a, b) {
return binl2b64(core_hmac_md5(a, b))
}

function str_hmac_md5(a, b) {
return binl2str(core_hmac_md5(a, b))
}

function md5_vm_test() {
return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"
}

function core_md5(p, k) {
p[k >> 5] |= 128 << ((k) % 32);
p[(((k + 64) >>> 9) << 4) + 14] = k;
var o = 1732584193;
var n = -271733879;
var m = -1732584194;
var l = 271733878;
for (var g = 0; g < p.length; g += 16) {
var j = o;
var h = n;
var f = m;
var e = l;
o = md5_ff(o, n, m, l, p[g + 0], 7, -680976936);
l = md5_ff(l, o, n, m, p[g + 1], 12, -389564586);
m = md5_ff(m, l, o, n, p[g + 2], 17, 606105819);
n = md5_ff(n, m, l, o, p[g + 3], 22, -1044525330);
o = md5_ff(o, n, m, l, p[g + 4], 7, -176418897);
l = md5_ff(l, o, n, m, p[g + 5], 12, 1200080426);
m = md5_ff(m, l, o, n, p[g + 6], 17, -1473231341);
n = md5_ff(n, m, l, o, p[g + 7], 22, -45705983);
o = md5_ff(o, n, m, l, p[g + 8], 7, 1770035416);
l = md5_ff(l, o, n, m, p[g + 9], 12, -1958414417);
m = md5_ff(m, l, o, n, p[g + 10], 17, -42063);
n = md5_ff(n, m, l, o, p[g + 11], 22, -1990404162);
o = md5_ff(o, n, m, l, p[g + 12], 7, 1804660682);
l = md5_ff(l, o, n, m, p[g + 13], 12, -40341101);
m = md5_ff(m, l, o, n, p[g + 14], 17, -1502002290);
n = md5_ff(n, m, l, o, p[g + 15], 22, 1236535329);
o = md5_gg(o, n, m, l, p[g + 1], 5, -165796510);
l = md5_gg(l, o, n, m, p[g + 6], 9, -1069501632);
m = md5_gg(m, l, o, n, p[g + 11], 14, 643717713);
n = md5_gg(n, m, l, o, p[g + 0], 20, -373897302);
o = md5_gg(o, n, m, l, p[g + 5], 5, -701558691);
l = md5_gg(l, o, n, m, p[g + 10], 9, 38016083);
m = md5_gg(m, l, o, n, p[g + 15], 14, -660478335);
n = md5_gg(n, m, l, o, p[g + 4], 20, -405537848);
o = md5_gg(o, n, m, l, p[g + 9], 5, 568446438);
l = md5_gg(l, o, n, m, p[g + 14], 9, -1019803690);
m = md5_gg(m, l, o, n, p[g + 3], 14, -187363961);
n = md5_gg(n, m, l, o, p[g + 8], 20, 1163531501);
o = md5_gg(o, n, m, l, p[g + 13], 5, -1444681467);
l = md5_gg(l, o, n, m, p[g + 2], 9, -51403784);
m = md5_gg(m, l, o, n, p[g + 7], 14, 1735328473);
n = md5_gg(n, m, l, o, p[g + 12], 20, -1921207734);
o = md5_hh(o, n, m, l, p[g + 5], 4, -378558);
l = md5_hh(l, o, n, m, p[g + 8], 11, -2022574463);
m = md5_hh(m, l, o, n, p[g + 11], 16, 1839030562);
n = md5_hh(n, m, l, o, p[g + 14], 23, -35309556);
o = md5_hh(o, n, m, l, p[g + 1], 4, -1530992060);
l = md5_hh(l, o, n, m, p[g + 4], 11, 1272893353);
m = md5_hh(m, l, o, n, p[g + 7], 16, -155497632);
n = md5_hh(n, m, l, o, p[g + 10], 23, -1094730640);
o = md5_hh(o, n, m, l, p[g + 13], 4, 681279174);
l = md5_hh(l, o, n, m, p[g + 0], 11, -358537222);
m = md5_hh(m, l, o, n, p[g + 3], 16, -722881979);
n = md5_hh(n, m, l, o, p[g + 6], 23, 76029189);
o = md5_hh(o, n, m, l, p[g + 9], 4, -640364487);
l = md5_hh(l, o, n, m, p[g + 12], 11, -421815835);
m = md5_hh(m, l, o, n, p[g + 15], 16, 530742520);
n = md5_hh(n, m, l, o, p[g + 2], 23, -995338651);
o = md5_ii(o, n, m, l, p[g + 0], 6, -198630844);
l = md5_ii(l, o, n, m, p[g + 7], 10, 11261161415);
m = md5_ii(m, l, o, n, p[g + 14], 15, -1416354905);
n = md5_ii(n, m, l, o, p[g + 5], 21, -57434055);
o = md5_ii(o, n, m, l, p[g + 12], 6, 1700485571);
l = md5_ii(l, o, n, m, p[g + 3], 10, -1894446606);
m = md5_ii(m, l, o, n, p[g + 10], 15, -1051523);
n = md5_ii(n, m, l, o, p[g + 1], 21, -2054922799);
o = md5_ii(o, n, m, l, p[g + 8], 6, 1873313359);
l = md5_ii(l, o, n, m, p[g + 15], 10, -30611744);
m = md5_ii(m, l, o, n, p[g + 6], 15, -1560198380);
n = md5_ii(n, m, l, o, p[g + 13], 21, 1309151649);
o = md5_ii(o, n, m, l, p[g + 4], 6, -145523070);
l = md5_ii(l, o, n, m, p[g + 11], 10, -1120210379);
m = md5_ii(m, l, o, n, p[g + 2], 15, 718787259);
n = md5_ii(n, m, l, o, p[g + 9], 21, -343485551);
o = safe_add(o, j);
n = safe_add(n, h);
m = safe_add(m, f);
l = safe_add(l, e)
}
return Array(o, n, m, l)
}

function md5_cmn(h, e, d, c, g, f) {
return safe_add(bit_rol(safe_add(safe_add(e, h), safe_add(c, f)), g), d)
}

function md5_ff(g, f, k, j, e, i, h) {
return md5_cmn((f & k) | ((~f) & j), g, f, e, i, h)
}

function md5_gg(g, f, k, j, e, i, h) {
return md5_cmn((f & j) | (k & (~j)), g, f, e, i, h)
}

function md5_hh(g, f, k, j, e, i, h) {
return md5_cmn(f ^ k ^ j, g, f, e, i, h)
}

function md5_ii(g, f, k, j, e, i, h) {
return md5_cmn(k ^ (f | (~j)), g, f, e, i, h)
}

function core_hmac_md5(c, f) {
var e = str2binl(c);
if (e.length > 16) {
e = core_md5(e, c.length * chrsz)
}
var a = Array(16), d = Array(16);
for (var b = 0; b < 16; b++) {
a[b] = e[b] ^ 909522486;
d[b] = e[b] ^ 1549556828
}
var g = core_md5(a.concat(str2binl(f)), 512 + f.length * chrsz);
return core_md5(d.concat(g), 512 + 128)
}

function safe_add(a, d) {
var c = (a & 65535) + (d & 65535);
var b = (a >> 16) + (d >> 16) + (c >> 16);
return (b << 16) | (c & 65535)
}

function bit_rol(a, b) {
return (a << b) | (a >>> (32 - b))
}

function str2binl(d) {
var c = Array();
var a = (1 << chrsz) - 1;
for (var b = 0; b < d.length * chrsz; b += chrsz) {
c[b >> 5] |= (d.charCodeAt(b / chrsz) & a) << (b % 32)
}
return c
}

function binl2str(c) {
var d = "";
var a = (1 << chrsz) - 1;
for (var b = 0; b < c.length * 32; b += chrsz) {
d += String.fromCharCode((c[b >> 5] >>> (b % 32)) & a)
}
return d
}

function binl2hex(c) {
var b = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var d = "";
for (var a = 0; a < c.length * 4; a++) {
d += b.charAt((c[a >> 2] >> ((a % 4) * 8 + 4)) & 15) + b.charAt((c[a >> 2] >> ((a % 4) * 8)) & 15)
}
return d
}

function binl2b64(d) {
var c = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var f = "";
for (var b = 0; b < d.length * 4; b += 3) {
var e = (((d[b >> 2] >> 8 * (b % 4)) & 255) << 16) | (((d[b + 1 >> 2] >> 8 * ((b + 1) % 4)) & 255) << 8) | ((d[b + 2 >> 2] >> 8 * ((b + 2) % 4)) & 255);
for (var a = 0; a < 4; a++) {
if (b * 8 + a * 6 > d.length * 32) {
f += b64pad
} else {
f += c.charAt((e >> 6 * (3 - a)) & 63)
}
}
}
return f
};

function get_m() {

var _0x2268f9 = Date["parse"](new Date()) + 100000000,
_0x57feae = hex_md5(_0x2268f9.toString());


return _0x57feae + "丨" + _0x2268f9 / 1000
}

console.log(get_m())

解题代码

然后我们结合逆向的js代码,进行解题代码的编写:

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
import requests
import execjs

headers = {
"user-agent": "你自己的UA"
}
cookies = {
"sessionid": "你自己的sessionid值"
}

url = "https://match.yuanrenxue.cn/api/match/1"
num = []

with open('第一题.js', 'r', encoding='utf-8') as f:
ctx = execjs.compile(f.read())

for page in range(1, 6):
params = {
"page": page,
"m": ctx.call("get_m")
}

# 发送请求并解析JSON
response = requests.get(url, headers=headers, cookies=cookies, params=params)
data = response.json() # 关键修改:将响应解析为字典

print(f"Page {page} Data:", data) # 打印解析后的完整数据结构

# 遍历解析后的数据
for item in data['data']: # data是字典中的键
num.append(item['value'])

# 计算最终平均值
print("Final Average:", sum(num) / len(num) if num else 0)

运行代码我们可以得到答案为:4700(如下图)

结语

这是我的第一篇教学视频,感谢各位的支持。

后续会继续更新下去,还请多多支持,有不懂的地方可以直接与我交流和指正!

微信:weixi040917

  • 标题: 猿人学-JS逆向第一届第1题
  • 作者: Xxi | 晞晞的小世界
  • 创建于 : 2025-05-14 21:59:04
  • 更新于 : 2025-05-15 13:15:02
  • 链接: https://xixixi.cc/2025/05/14/猿人学-JS逆向第一届第1题/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论