前言

JS逆向一直以来都是重难点,挖掘SRC,小程序常常会遇到各种签名与加密,不会JS逆向就寸步难行,但一旦逆向出来,往往会一马平川,发现各种越权漏洞……基于此,笔者找到一个靶场很适合新手师傅们从0到1地去学习JS逆向的各种场景,题目有难有易,覆盖多种实际场景(不是广子)。本文从原始的手工扣代码补环境出发,写了一份0基础题解(1-6),适合想入门JS逆向的师傅看,结合靶场题目动手练习,你会发现JS逆向其实也不难呢~

image-20251011145733990

题一-基础爬虫

直接爬就完了,没有什么说的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests

#初始化配置
base_url ="https://www.mashangpa.com/api/problem-detail/1/data/"
header={ 'Cookie': ''}
all_num=[]

#遍历page参数
for page in range(1,21):
url=f'{base_url}?page={page}'
response =requests.get(url,headers=header)
data=response.json()
#提取数组
if 'current_array' in data:
num=data['current_array']
all_num.extend(num)
else:
print("该页无数据")
#数组元素求和
print(sum(all_num))

题二-请求头伪造

需要注意的是要多加几个请求头,只加UA头还是无法绕过反爬机制

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

base_url = "https://www.mashangpa.com/api/problem-detail/3/data/"
headers = {
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8",
"priority": "u=1, i",
"referer": "https://www.mashangpa.com/problem-detail/2/",
"sec-ch-ua": "\"Chromium\";v=\"140\", \"Not=A?Brand\";v=\"24\", \"Google Chrome\";v=\"140\"",
"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/140.0.0.0 Safari/537.36"
}
cookies = {
}
all_num=[]

for page in range(1,21):
url=f'{base_url}?page={page}'
response = requests.get(url, headers=headers, cookies=cookies)
data=response.json()

if 'current_array' in data:
num=data['current_array']
all_num.extend(num)
else:
print(response.text)

print(sum(all_num))

题三-无限debug

打开f12,本地替换对应的js文件,删掉debug相关代码即可

题四-sign逆向

F12调试翻页接口,发现请求参数携带签名sign和时间戳

image-20250929103942195

如果我们要爬取计算出答案,就需要逆向出sign的生成算法,实时携带有效的sign去请求翻页获取数据

全局搜索sign,定位到生成逻辑

image-20250929105627554

window.token = window.md5("tuling" + timestamp + pageNumber)

sign: window.token

说明sign的生成逻辑就是’tuling’拼接时间戳再拼接页数最后计算整体的md5值

image-20250929113747180

但是要注意的是这个MD5函数,有可能是直接使用第三方官方库那么便简单了,直接调用即可,但是也有可能是自实现的或者进行了魔改加盐,这种情况就需要跟进一下相关函数,进行扣代码补环境,然后本地调用

image-20250929111705772

发现md5函数定义,显然是自实现的,于是我们需要扣代码出来

在两个return处下断,发现走的是下面的支路

image-20250929111907096

调用了l,h函数

image-20250929112409445

后续的算法细节其实可以不必分析了,因为用到的函数都能很容易的找出来,直接开始扣代码,缺什么函数补什么函数就行

image-20250929112511327

首先我们需要计算构造的参数是sign,先扣出最关键的一行生成代码,并把它赋值为sign

1
const sign = window.md5("tuling" + timestamp + pageNumber)

然后缺啥补啥

补上timestamp

1
const timestamp = new Date().getTime()

pageNumber需要动态传参,于是作为函数参数

1
2
3
4
function getsign(pageNumber){
const timestamp = new Date().getTime()
const sign = window.md5("tuling" + timestamp + pageNumber)
}

还缺少md5函数,直接copy过来

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
window = this, function (n) {
function r(n, r) {
var t = (65535 & n) + (65535 & r);
return (n >> 16) + (r >> 16) + (t >> 16) << 16 | 65535 & t
}

function t(n, t, o, u, e, c) {
return r(function (n, r) {
return n << e | n >>> 32 - e
}(r(r(t, n), r(u, c))), o)
}

function o(n, r, o, u, e, c, f) {
return t(r & o | ~r & u, n, r, e, c, f)
}

function u(n, r, o, u, e, c, f) {
return t(r & u | o & ~u, n, r, e, c, f)
}

function e(n, r, o, u, e, c, f) {
return t(r ^ o ^ u, n, r, e, c, f)
}

function c(n, r, o, u, e, c, f) {
return t(o ^ (r | ~u), n, r, e, c, f)
}

function f(n, t) {
var f, i, a, h, g;
n[t >> 5] |= 128 << t % 32, n[14 + (t + 64 >>> 9 << 4)] = t;
var l = 1732584193, d = -271733879, v = -1732584194, C = 271733878;
for (f = 0; f < n.length; f += 16) d = c(d = c(d = c(d = c(d = e(d = e(d = e(d = e(d = u(d = u(d = u(d = u(d = o(d = o(d = o(d = o(a = d, v = o(h = v, C = o(g = C, l = o(i = l, d, v, C, n[f], 7, -680876936), d, v, n[f + 1], 12, -389564586), l, d, n[f + 2], 17, 606105819), C, l, n[f + 3], 22, -1044525330), v = o(v, C = o(C, l = o(l, d, v, C, n[f + 4], 7, -176418897), d, v, n[f + 5], 12, 1200080426), l, d, n[f + 6], 17, -1473231341), C, l, n[f + 7], 22, -45705983), v = o(v, C = o(C, l = o(l, d, v, C, n[f + 8], 7, 1770035416), d, v, n[f + 9], 12, -1958414417), l, d, n[f + 10], 17, -42063), C, l, n[f + 11], 22, -1990404162), v = o(v, C = o(C, l = o(l, d, v, C, n[f + 12], 7, 1804603682), d, v, n[f + 13], 12, -40341101), l, d, n[f + 14], 17, -1502002290), C, l, n[f + 15], 22, 1236535329), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 1], 5, -165796510), d, v, n[f + 6], 9, -1069501632), l, d, n[f + 11], 14, 643717713), C, l, n[f], 20, -373897302), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 5], 5, -701558691), d, v, n[f + 10], 9, 38016083), l, d, n[f + 15], 14, -660478335), C, l, n[f + 4], 20, -405537848), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 9], 5, 568446438), d, v, n[f + 14], 9, -1019803690), l, d, n[f + 3], 14, -187363961), C, l, n[f + 8], 20, 1163531501), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 13], 5, -1444681467), d, v, n[f + 2], 9, -51403784), l, d, n[f + 7], 14, 1735328473), C, l, n[f + 12], 20, -1926607734), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 5], 4, -378558), d, v, n[f + 8], 11, -2022574463), l, d, n[f + 11], 16, 1839030562), C, l, n[f + 14], 23, -35309556), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 1], 4, -1530992060), d, v, n[f + 4], 11, 1272893353), l, d, n[f + 7], 16, -155497632), C, l, n[f + 10], 23, -1094730640), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 13], 4, 681279174), d, v, n[f], 11, -358537222), l, d, n[f + 3], 16, -722521979), C, l, n[f + 6], 23, 76029189), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 9], 4, -640364487), d, v, n[f + 12], 11, -421815835), l, d, n[f + 15], 16, 530742520), C, l, n[f + 2], 23, -995338651), v = c(v, C = c(C, l = c(l, d, v, C, n[f], 6, -198630844), d, v, n[f + 7], 10, 1126891415), l, d, n[f + 14], 15, -1416354905), C, l, n[f + 5], 21, -57434055), v = c(v, C = c(C, l = c(l, d, v, C, n[f + 12], 6, 1700485571), d, v, n[f + 3], 10, -1894986606), l, d, n[f + 10], 15, -1051523), C, l, n[f + 1], 21, -2054922799), v = c(v, C = c(C, l = c(l, d, v, C, n[f + 8], 6, 1873313359), d, v, n[f + 15], 10, -30611744), l, d, n[f + 6], 15, -1560198380), C, l, n[f + 13], 21, 1309151649), v = c(v, C = c(C, l = c(l, d, v, C, n[f + 4], 6, -145523070), d, v, n[f + 11], 10, -1120210379), l, d, n[f + 2], 15, 718787259), C, l, n[f + 9], 21, -343485551), l = r(l, i), d = r(d, a), v = r(v, h), C = r(C, g);
return [l, d, v, C]
}

function i(n) {
var r, t = "", o = 32 * n.length;
for (r = 0; r < o; r += 8) t += String.fromCharCode(n[r >> 5] >>> r % 32 & 255);
return t
}

function a(n) {
var r, t = [];
for (t[(n.length >> 2) - 1] = void 0, r = 0; r < t.length; r += 1) t[r] = 0;
var o = 8 * n.length;
for (r = 0; r < o; r += 8) t[r >> 5] |= (255 & n.charCodeAt(r / 8)) << r % 32;
return t
}

function h(n) {
var r, t, o = "0123456789abcdef", u = "";
for (t = 0; t < n.length; t += 1) r = n.charCodeAt(t), u += o.charAt(r >>> 4 & 15) + o.charAt(15 & r);
return u
}

function g(n) {
return unescape(encodeURIComponent(n))
}

function l(n) {
return function (n) {
return i(f(a(n), 8 * n.length))
}(g(n))
}

function d(n, r) {
return function (n, r) {
var t, o, u = a(n), e = [], c = [];
for (e[15] = c[15] = void 0, 16 < u.length && (u = f(u, 8 * n.length)), t = 0; t < 16; t += 1) e[t] = 909522486 ^ u[t], c[t] = 1549556828 ^ u[t];
return o = f(e.concat(a(r)), 512 + 8 * r.length), i(f(c.concat(o), 640))
}(g(n), g(r))
}

window.md5 = function (n, r, t) {
return r ? t ? d(r, n) : function (n, r) {
return h(d(n, r))
}(r, n) : t ? l(n) : function (n) {
return h(l(n))
}(n)
}
}();

function getsign(pageNumber){
const timestamp = new Date().getTime()
const sign = window.md5("tuling" + timestamp + pageNumber)
}

image-20250929114529060

调试输出一下sign看是否缺少函数

1
2
3
4
5
6
function getsign(pageNumber){
const timestamp = new Date().getTime()
const sign = window.md5("tuling" + timestamp + pageNumber)
return(sign)
}
console.log(getsign(1))

image-20250929114804323

ok,到这里其实已经把环境补好了能够正常生成sign了

接下来实现python代码

还是和之前一样,先把架子搭建好,再解决sign的问题

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

base_url = "https://www.mashangpa.com/api/problem-detail/4/data/"
headers = {
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8",
"priority": "u=1, i",
"referer": "https://www.mashangpa.com/problem-detail/2/",
"sec-ch-ua": "\"Chromium\";v=\"140\", \"Not=A?Brand\";v=\"24\", \"Google Chrome\";v=\"140\"",
"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/140.0.0.0 Safari/537.36"
}
cookies = {
}
all_num=[]

for page in range(1,21):
url=f'{base_url}?page={page}&sign={sign}&_ts={timestamp}'
response=requests.get(url,headers=headers,cookies=cookies)
data=response.json()
if 'current_array' in data:
num=data['current_array']
all_num.extend(num)
else:
print("该页无数据")
print(sum(all_num))

可以看到我们python代码是缺少sign和timestamp参数值的,这两个参数需要从js代码里计算后取出,于是需要用到一个py与js交互数据的库,execjs

1
2
pip install PyExecJS
import execjs

修改js代码,返回sign,timestamp字段

1
2
3
4
5
6
7
8
function getsign(pageNumber){
const timestamp = new Date().getTime()
const sign = window.md5("tuling" + timestamp + pageNumber)
return{
"sign":sign,
"timestamp":timestamp
}
}

修改python代码,读取4.js代码

1
2
with open('4.js','r',encoding='utf-8') as f:
js_code = execjs.compile(f.read())

调用getsign函数传入page值,并遍历,接收sign和timestamp再构造发起请求

1
2
3
4
5
6
7
8
9
10
11
12
13
for page in range(1,21):
result=js_code.call('getsign',page)
sign=result['sign']
timestamp=result['timestamp']
url=f'{base_url}?page={page}&sign={sign}&_ts={timestamp}'
response=requests.get(url,headers=headers,cookies=cookies)
data=response.json()
if 'current_array' in data:
num=data['current_array']
all_num.extend(num)
else:
print("该页无数据")
print(sum(all_num))

最终脚本如下:

task4.py

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


base_url = "https://www.mashangpa.com/api/problem-detail/4/data/"
headers = {
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8",
"priority": "u=1, i",
"referer": "https://www.mashangpa.com/problem-detail/2/",
"sec-ch-ua": "\"Chromium\";v=\"140\", \"Not=A?Brand\";v=\"24\", \"Google Chrome\";v=\"140\"",
"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/140.0.0.0 Safari/537.36"
}
cookies = {
}
all_num=[]

with open('4.js','r',encoding='utf-8') as f:
js_code = execjs.compile(f.read())
for page in range(1,21):
result=js_code.call('getsign',page)
sign=result['sign']
timestamp=result['timestamp']
url=f'{base_url}?page={page}&sign={sign}&_ts={timestamp}'
print(url)
response=requests.get(url,headers=headers,cookies=cookies)
data=response.json()
if 'current_array' in data:
num=data['current_array']
all_num.extend(num)
else:
print("该页无数据")
print(f'答案是: {sum(all_num)}')

4.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
window = this, function (n) {
function r(n, r) {
var t = (65535 & n) + (65535 & r);
return (n >> 16) + (r >> 16) + (t >> 16) << 16 | 65535 & t
}

function t(n, t, o, u, e, c) {
return r(function (n, r) {
return n << e | n >>> 32 - e
}(r(r(t, n), r(u, c))), o)
}

function o(n, r, o, u, e, c, f) {
return t(r & o | ~r & u, n, r, e, c, f)
}

function u(n, r, o, u, e, c, f) {
return t(r & u | o & ~u, n, r, e, c, f)
}

function e(n, r, o, u, e, c, f) {
return t(r ^ o ^ u, n, r, e, c, f)
}

function c(n, r, o, u, e, c, f) {
return t(o ^ (r | ~u), n, r, e, c, f)
}

function f(n, t) {
var f, i, a, h, g;
n[t >> 5] |= 128 << t % 32, n[14 + (t + 64 >>> 9 << 4)] = t;
var l = 1732584193, d = -271733879, v = -1732584194, C = 271733878;
for (f = 0; f < n.length; f += 16) d = c(d = c(d = c(d = c(d = e(d = e(d = e(d = e(d = u(d = u(d = u(d = u(d = o(d = o(d = o(d = o(a = d, v = o(h = v, C = o(g = C, l = o(i = l, d, v, C, n[f], 7, -680876936), d, v, n[f + 1], 12, -389564586), l, d, n[f + 2], 17, 606105819), C, l, n[f + 3], 22, -1044525330), v = o(v, C = o(C, l = o(l, d, v, C, n[f + 4], 7, -176418897), d, v, n[f + 5], 12, 1200080426), l, d, n[f + 6], 17, -1473231341), C, l, n[f + 7], 22, -45705983), v = o(v, C = o(C, l = o(l, d, v, C, n[f + 8], 7, 1770035416), d, v, n[f + 9], 12, -1958414417), l, d, n[f + 10], 17, -42063), C, l, n[f + 11], 22, -1990404162), v = o(v, C = o(C, l = o(l, d, v, C, n[f + 12], 7, 1804603682), d, v, n[f + 13], 12, -40341101), l, d, n[f + 14], 17, -1502002290), C, l, n[f + 15], 22, 1236535329), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 1], 5, -165796510), d, v, n[f + 6], 9, -1069501632), l, d, n[f + 11], 14, 643717713), C, l, n[f], 20, -373897302), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 5], 5, -701558691), d, v, n[f + 10], 9, 38016083), l, d, n[f + 15], 14, -660478335), C, l, n[f + 4], 20, -405537848), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 9], 5, 568446438), d, v, n[f + 14], 9, -1019803690), l, d, n[f + 3], 14, -187363961), C, l, n[f + 8], 20, 1163531501), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 13], 5, -1444681467), d, v, n[f + 2], 9, -51403784), l, d, n[f + 7], 14, 1735328473), C, l, n[f + 12], 20, -1926607734), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 5], 4, -378558), d, v, n[f + 8], 11, -2022574463), l, d, n[f + 11], 16, 1839030562), C, l, n[f + 14], 23, -35309556), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 1], 4, -1530992060), d, v, n[f + 4], 11, 1272893353), l, d, n[f + 7], 16, -155497632), C, l, n[f + 10], 23, -1094730640), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 13], 4, 681279174), d, v, n[f], 11, -358537222), l, d, n[f + 3], 16, -722521979), C, l, n[f + 6], 23, 76029189), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 9], 4, -640364487), d, v, n[f + 12], 11, -421815835), l, d, n[f + 15], 16, 530742520), C, l, n[f + 2], 23, -995338651), v = c(v, C = c(C, l = c(l, d, v, C, n[f], 6, -198630844), d, v, n[f + 7], 10, 1126891415), l, d, n[f + 14], 15, -1416354905), C, l, n[f + 5], 21, -57434055), v = c(v, C = c(C, l = c(l, d, v, C, n[f + 12], 6, 1700485571), d, v, n[f + 3], 10, -1894986606), l, d, n[f + 10], 15, -1051523), C, l, n[f + 1], 21, -2054922799), v = c(v, C = c(C, l = c(l, d, v, C, n[f + 8], 6, 1873313359), d, v, n[f + 15], 10, -30611744), l, d, n[f + 6], 15, -1560198380), C, l, n[f + 13], 21, 1309151649), v = c(v, C = c(C, l = c(l, d, v, C, n[f + 4], 6, -145523070), d, v, n[f + 11], 10, -1120210379), l, d, n[f + 2], 15, 718787259), C, l, n[f + 9], 21, -343485551), l = r(l, i), d = r(d, a), v = r(v, h), C = r(C, g);
return [l, d, v, C]
}

function i(n) {
var r, t = "", o = 32 * n.length;
for (r = 0; r < o; r += 8) t += String.fromCharCode(n[r >> 5] >>> r % 32 & 255);
return t
}

function a(n) {
var r, t = [];
for (t[(n.length >> 2) - 1] = void 0, r = 0; r < t.length; r += 1) t[r] = 0;
var o = 8 * n.length;
for (r = 0; r < o; r += 8) t[r >> 5] |= (255 & n.charCodeAt(r / 8)) << r % 32;
return t
}

function h(n) {
var r, t, o = "0123456789abcdef", u = "";
for (t = 0; t < n.length; t += 1) r = n.charCodeAt(t), u += o.charAt(r >>> 4 & 15) + o.charAt(15 & r);
return u
}

function g(n) {
return unescape(encodeURIComponent(n))
}

function l(n) {
return function (n) {
return i(f(a(n), 8 * n.length))
}(g(n))
}

function d(n, r) {
return function (n, r) {
var t, o, u = a(n), e = [], c = [];
for (e[15] = c[15] = void 0, 16 < u.length && (u = f(u, 8 * n.length)), t = 0; t < 16; t += 1) e[t] = 909522486 ^ u[t], c[t] = 1549556828 ^ u[t];
return o = f(e.concat(a(r)), 512 + 8 * r.length), i(f(c.concat(o), 640))
}(g(n), g(r))
}

window.md5 = function (n, r, t) {
return r ? t ? d(r, n) : function (n, r) {
return h(d(n, r))
}(r, n) : t ? l(n) : function (n) {
return h(l(n))
}(n)
}
}();


function getsign(pageNumber){
const timestamp = new Date().getTime()
const sign = window.md5("tuling" + timestamp + pageNumber)
return{
"sign":sign,
"timestamp":timestamp
}
}

运行出结果

image-20250929130852856

题五-参数值逆向

image-20250929131846974

可以看到参数值加密了

还是照样,全局搜索”xl”

image-20250929132009544

打上断点验证一下看看数据流

image-20250929132032206

const params = { page: pageNumber, _ts: timestamp, };

JSON.stringify({xl: encryptedQuery})

let encryptedQuery = encrypt(jsonString);

可以得出加密流程是把page和时间戳转为json然后拿给encrypt函数加密,观察encrypt函数

image-20250929132229614

发现题五与题四的区别是加密函数代码被混淆了,但是其实仍然不影响我们直接扣代码

image-20250929132542482

于是还是和之前一样,拿出生成xl的关键代码

1
2
const jsonString = JSON.stringify(params);
let encryptedQuery = encrypt(jsonString);

补params

1
2
3
4
5
6
7
8
9
function getxl(pageNumber){
const timestamp = new Date().getTime();
const params = {
page: pageNumber,
_ts: timestamp,
};
const jsonString = JSON.stringify(params);
let encryptedQuery = encrypt(jsonString);
}

就差encrypt函数了,直接copy下来

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
const _0x38addf = _0x66a7;

function _0x66a7(_0x7461a9, _0x14ffcc) {
const _0x4f0d09 = _0x4f0d();
return _0x66a7 = function (_0x66a780, _0x2abc15) {
_0x66a780 = _0x66a780 - 0xc5;
let _0x477d8f = _0x4f0d09[_0x66a780];
return _0x477d8f;
}, _0x66a7(_0x7461a9, _0x14ffcc);
}

(function (_0x59b24b, _0x16d38a) {
const _0x3e5f1c = _0x66a7, _0x14ae46 = _0x59b24b();
while (!![]) {
try {
const _0x5e1110 = parseInt(_0x3e5f1c(0xca)) / 0x1 + -parseInt(_0x3e5f1c(0xd4)) / 0x2 * (-parseInt(_0x3e5f1c(0xd5)) / 0x3) + parseInt(_0x3e5f1c(0xc8)) / 0x4 + -parseInt(_0x3e5f1c(0xcc)) / 0x5 * (-parseInt(_0x3e5f1c(0xd0)) / 0x6) + -parseInt(_0x3e5f1c(0xd3)) / 0x7 + -parseInt(_0x3e5f1c(0xcd)) / 0x8 + -parseInt(_0x3e5f1c(0xcf)) / 0x9;
if (_0x5e1110 === _0x16d38a) break; else _0x14ae46['push'](_0x14ae46['shift']());
} catch (_0x4fbd75) {
_0x14ae46['push'](_0x14ae46['shift']());
}
}
}(_0x4f0d, 0x897b4), dd = {'a': CryptoJS});
let key = dd['a'][_0x38addf(0xd6)][_0x38addf(0xc7)][_0x38addf(0xc9)](_0x38addf(0xce)),
iv = dd['a'][_0x38addf(0xd6)]['Utf8'][_0x38addf(0xc9)]('0123456789ABCDEF');

function _0x4f0d() {
const _0x341c37 = ['2440720SaQcQw', 'jo8j9wGw%6HbxfFn', '9735516pjwmiO', '68862pbatqQ', 'mode', 'AES', '1923264HnviQd', '36906bPsIrd', '12hEJHOd', 'enc', 'pad', 'encrypt', 'Hex', 'Utf8', '689460JbShaf', 'parse', '957060HmuxSn', 'toString', '445UZKyxv'];
_0x4f0d = function () {
return _0x341c37;
};
return _0x4f0d();
}

function encrypt(_0x277028) {
const _0x4d843e = _0x38addf;
let _0x2703a2 = dd['a'][_0x4d843e(0xd6)]['Utf8']['parse'](_0x277028),
_0x50fcf0 = dd['a'][_0x4d843e(0xd2)][_0x4d843e(0xc5)](_0x2703a2, key, {
'mode': dd['a'][_0x4d843e(0xd1)]['CBC'],
'padding': dd['a'][_0x4d843e(0xd7)]['Pkcs7'],
'iv': iv
});
return _0x50fcf0['ciphertext'][_0x4d843e(0xcb)](CryptoJS[_0x4d843e(0xd6)][_0x4d843e(0xc6)]);
}


function getxl(pageNumber){
const timestamp = new Date().getTime();
const params = {
page: pageNumber,
_ts: timestamp,
};
const jsonString = JSON.stringify(params);
let encryptedQuery = encrypt(jsonString);
return encryptedQuery
}

console.log(getxl(1))

还需要注意的是该段代码还调用库CryptoJS

image-20250929134244417

这里有,直接下载crypto-js.js到本地即可

image-20251009103017159

不要忘了使用const CryptoJS = require("crypto-js");导入该库

然后调试输出,成功生成xl的值

image-20250929134113691

接着是python代码,就很简单了,直接在task4.py的基础上修改下就好了

task5.py

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

base_url = "https://www.mashangpa.com/api/problem-detail/5/data/"
headers = {
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8",
"priority": "u=1, i",
"referer": "https://www.mashangpa.com/problem-detail/2/",
"sec-ch-ua": "\"Chromium\";v=\"140\", \"Not=A?Brand\";v=\"24\", \"Google Chrome\";v=\"140\"",
"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/140.0.0.0 Safari/537.36"
}
cookies = {
}
all_num=[]

with open('5.js','r',encoding='utf-8') as f:
js_code = execjs.compile(f.read())
for page in range(1,21):
result=js_code.call('getxl',page)
data={"xl":result}
print(data)
response=requests.post(base_url,headers=headers,cookies=cookies,json=data)
data=response.json()
if 'current_array' in data:
num=data['current_array']
all_num.extend(num)
else:
print("该页无数据")
print(f'答案是: {sum(all_num)}')

运行出结果

image-20251011152358700

题六-请求响应逆向

image-20251011152426210

可以看到请求包携带了签名S,以及时间戳Tt

响应也加密了

image-20251008231809982

我们先搞定请求,定位到签名逻辑

image-20251009094907191

hhh对象包含了签名s和tt时间戳

image-20251009094947042

hhh的生成逻辑

image-20251009095416952

我们直接补环境,还是一样,先拿出生成签名的关键代码

1
2
3
4
5
6
7
8
9
function getreq(){
const ttt = new Date().getTime();
const token = window.xxoo("sssssbbbbb" + ttt);
const hhh = {
s: token,
tt: ttt,
};
console.log(hhh)
}

再全部把缺少的加密函数复制过来就行

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
window = this, function (n) {
function r(n, r) {
var t = (65535 & n) + (65535 & r);
return (n >> 16) + (r >> 16) + (t >> 16) << 16 | 65535 & t
}

function t(n, t, o, u, e, c) {
return r(function (n, r) {
return n << e | n >>> 32 - e
}(r(r(t, n), r(u, c))), o)
}

function o(n, r, o, u, e, c, f) {
return t(r & o | ~r & u, n, r, e, c, f)
}

function u(n, r, o, u, e, c, f) {
return t(r & u | o & ~u, n, r, e, c, f)
}

function e(n, r, o, u, e, c, f) {
return t(r ^ o ^ u, n, r, e, c, f)
}

function c(n, r, o, u, e, c, f) {
return t(o ^ (r | ~u), n, r, e, c, f)
}

function f(n, t) {
var f, i, a, h, g;
n[t >> 5] |= 128 << t % 32, n[14 + (t + 64 >>> 9 << 4)] = t;
var l = 1732584193, d = -271733879, v = -1732584194, C = 271733878;
for (f = 0; f < n.length; f += 16) d = c(d = c(d = c(d = c(d = e(d = e(d = e(d = e(d = u(d = u(d = u(d = u(d = o(d = o(d = o(d = o(a = d, v = o(h = v, C = o(g = C, l = o(i = l, d, v, C, n[f], 7, -680876936), d, v, n[f + 1], 12, -389564586), l, d, n[f + 2], 17, 606105819), C, l, n[f + 3], 22, -1044525330), v = o(v, C = o(C, l = o(l, d, v, C, n[f + 4], 7, -176418897), d, v, n[f + 5], 12, 1200080426), l, d, n[f + 6], 17, -1473231341), C, l, n[f + 7], 22, -45705983), v = o(v, C = o(C, l = o(l, d, v, C, n[f + 8], 7, 1770035416), d, v, n[f + 9], 12, -1958414417), l, d, n[f + 10], 17, -42063), C, l, n[f + 11], 22, -1990404162), v = o(v, C = o(C, l = o(l, d, v, C, n[f + 12], 7, 1804603682), d, v, n[f + 13], 12, -40341101), l, d, n[f + 14], 17, -1502002290), C, l, n[f + 15], 22, 1236535329), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 1], 5, -165796510), d, v, n[f + 6], 9, -1069501632), l, d, n[f + 11], 14, 643717713), C, l, n[f], 20, -373897302), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 5], 5, -701558691), d, v, n[f + 10], 9, 38016083), l, d, n[f + 15], 14, -660478335), C, l, n[f + 4], 20, -405537848), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 9], 5, 568446438), d, v, n[f + 14], 9, -1019803690), l, d, n[f + 3], 14, -187363961), C, l, n[f + 8], 20, 1163531501), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 13], 5, -1444681467), d, v, n[f + 2], 9, -51403784), l, d, n[f + 7], 14, 1735328473), C, l, n[f + 12], 20, -1926607734), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 5], 4, -378558), d, v, n[f + 8], 11, -2022574463), l, d, n[f + 11], 16, 1839030562), C, l, n[f + 14], 23, -35309556), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 1], 4, -1530992060), d, v, n[f + 4], 11, 1272893353), l, d, n[f + 7], 16, -155497632), C, l, n[f + 10], 23, -1094730640), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 13], 4, 681279174), d, v, n[f], 11, -358537222), l, d, n[f + 3], 16, -722521979), C, l, n[f + 6], 23, 76029189), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 9], 4, -640364487), d, v, n[f + 12], 11, -421815835), l, d, n[f + 15], 16, 530742520), C, l, n[f + 2], 23, -995338651), v = c(v, C = c(C, l = c(l, d, v, C, n[f], 6, -198630844), d, v, n[f + 7], 10, 1126891415), l, d, n[f + 14], 15, -1416354905), C, l, n[f + 5], 21, -57434055), v = c(v, C = c(C, l = c(l, d, v, C, n[f + 12], 6, 1700485571), d, v, n[f + 3], 10, -1894986606), l, d, n[f + 10], 15, -1051523), C, l, n[f + 1], 21, -2054922799), v = c(v, C = c(C, l = c(l, d, v, C, n[f + 8], 6, 1873313359), d, v, n[f + 15], 10, -30611744), l, d, n[f + 6], 15, -1560198380), C, l, n[f + 13], 21, 1309151649), v = c(v, C = c(C, l = c(l, d, v, C, n[f + 4], 6, -145523070), d, v, n[f + 11], 10, -1120210379), l, d, n[f + 2], 15, 718787259), C, l, n[f + 9], 21, -343485551), l = r(l, i), d = r(d, a), v = r(v, h), C = r(C, g);
return [l, d, v, C]
}

function i(n) {
var r, t = "", o = 32 * n.length;
for (r = 0; r < o; r += 8) t += String.fromCharCode(n[r >> 5] >>> r % 32 & 255);
return t
}

function a(n) {
var r, t = [];
for (t[(n.length >> 2) - 1] = void 0, r = 0; r < t.length; r += 1) t[r] = 0;
var o = 8 * n.length;
for (r = 0; r < o; r += 8) t[r >> 5] |= (255 & n.charCodeAt(r / 8)) << r % 32;
return t
}

function h(n) {
var r, t, o = "0123456789abcdef", u = "";
for (t = 0; t < n.length; t += 1) r = n.charCodeAt(t), u += o.charAt(r >>> 4 & 15) + o.charAt(15 & r);
return u
}

function g(n) {
return unescape(encodeURIComponent(n))
}

function l(n) {
return function (n) {
return i(f(a(n), 8 * n.length))
}(g(n))
}

function d(n, r) {
return function (n, r) {
var t, o, u = a(n), e = [], c = [];
for (e[15] = c[15] = void 0, 16 < u.length && (u = f(u, 8 * n.length)), t = 0; t < 16; t += 1) e[t] = 909522486 ^ u[t], c[t] = 1549556828 ^ u[t];
return o = f(e.concat(a(r)), 512 + 8 * r.length), i(f(c.concat(o), 640))
}(g(n), g(r))
}

window.xxoo = function (n, r, t) {
return r ? t ? d(r, n) : function (n, r) {
return h(d(n, r))
}(r, n) : t ? l(n) : function (n) {
return h(l(n))
}(n)
}
}();

dd = {
a: CryptoJS
}
let kkkk = dd.a.enc.Utf8.parse("xxxxxxxxoooooooo");
let iiii = dd.a.enc.Utf8.parse("0123456789ABCDEF");


function xxxxoooo(encryptedHex) {
let enccc = dd.a.enc.Hex.parse(encryptedHex);
let deccc = dd.a.AES["decr" + "ypt"]({ciphertext: enccc}, kkkk, {
mode: dd.a.mode.CBC,
padding: dd.a.pad.Pkcs7,
iv: iiii,
});
return deccc.toString(dd.a.enc.Utf8);
}

function getreq(){
const ttt = new Date().getTime();
const token = window.xxoo("sssssbbbbb" + ttt);
const hhh = {
s: token,
tt: ttt,
};
console.log(hhh)
}

还需要下载crypto-js.js到本地,并导入该库

1
const CryptoJS = require("crypto-js");

运行调试一下,生成成功!

image-20251009104103135

继续完整响应数据的解密

分析可得,data包含加密的响应数据t,xxxxoooo函数就是解密函数,接收data.t加密值进行解密

image-20251009104523167

下断调试,运行打印一下就知道了

image-20251009104726372

开始补环境,拿出关键解密代码

1
2
3
4
function my_encry(data){
const encry_data = xxxxoooo(data);
return (encry_data)
}

补齐解密函数和库,运行调试一下

解密成功

image-20251009105609210

然后写py,在原来题5脚本基础上修改即可

先调整js,返回计算值

1
2
3
4
5
6
7
8
9
function getreq(){
const ttt = new Date().getTime();
const token = window.xxoo("sssssbbbbb" + ttt);
const hhh = {
s: token,
tt: ttt,
};
return {"S":token,"Tt":ttt.toString()}
}
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
import requests
import execjs
import json

base_url = "https://www.mashangpa.com/api/problem-detail/6/data/"
headers = {
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8",
"priority": "u=1, i",
"referer": "https://www.mashangpa.com/problem-detail/6/",
"sec-ch-ua": "\"Chromium\";v=\"140\", \"Not=A?Brand\";v=\"24\", \"Google Chrome\";v=\"140\"",
"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/140.0.0.0 Safari/537.36"
}
cookies = {
}
all_num=[]



with open('6.js','r',encoding='utf-8') as f:
js_code = execjs.compile(f.read())
for page in range(1,21):
hhh=js_code.call('getreq')
headers.update(hhh)
url=f'{base_url}?page={page}'
response=requests.get(url,headers=headers,cookies=cookies)
data=response.json()
data=js_code.call('my_encry',data['t'])
data=json.loads(data)
if 'current_array' in data:
num=data['current_array']
all_num.extend(num)
else:
print("该页无数据")
print(f'答案是: {sum(all_num)}')

运行出结果

image-20251009114228884

ok就写到这里,先更1-6,后面有空再更新,但其实网上已有完整的题解,只是我自认为我写得比较详细~

感谢师傅们的阅读~