网址:https://www.qcc.com/firm/5dffb644394922f9073544a08f38be9f.html

解析流程

以查看公司财务数据为例,通过多次请求发现请求参数固定,如果是请求同一类数据请求头也固定,但请求头中有个参数会跟着不同的请求体进行变更,可以查看一下,直接通过发起程序追栈

image-20230517114041452

代码量有点多,我们直接全局搜索headers[ ,通过查看,发现第二条更符合,打上断点查看

image-20230517115511582

image-20230517115421711

这一段就是我们想要的结果了

1
2
3
4
5
var i = (0,a.default)(t, e.data), l = (0,r.default)(t, e.data, (0,s.default)());
e.headers[i] = l
//改写一下
var i = a.default(t, e.data), l = r.default(t, e.data, s.default());
e.headers[i] = l

image-20230517115921628

t是请求url,e.data是请求体

分别查看一下r.default,a.default,s.defaul

首先,s.default是一个固定值,c5c144235c8441642f9af0413f60588e

1
2
3
4
eval(list.join(""))
'c5c144235c8441642f9af0413f60588e'
window.tid
'c5c144235c8441642f9af0413f60588e'

image-20230517125902519

a.default返回的结果

1
2
3
4
5
return (0,o.default)(t + n, (0,a.default)(t)).toLowerCase().substr(8, 20)
// 改写一下
o.default(t + n,a.default(t)).toLowerCase().substr(8, 20)
// t + n = '/api/datalist/financiallist{"keyno":"5dffb644394922f9073544a08f38be9f","type":"hk","reporttype":1,"currency":"usd","rate":1}'

image-20230517130548190

这个里面的a.default是这样的

image-20230517130918246

o.default是一个固定值

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
{
"n": 20,
"codes": {
"0": "W",
"1": "l",
"2": "k",
"3": "B",
"4": "Q",
"5": "g",
"6": "f",
"7": "i",
"8": "i",
"9": "r",
"10": "v",
"11": "6",
"12": "A",
"13": "K",
"14": "N",
"15": "k",
"16": "4",
"17": "L",
"18": "1",
"19": "8"
}
}

再查看a.default返回的o.default

image-20230517132308217

然后再查看这个o.default

image-20230517132247427

好的 一切都明了了,hmac算法,用到请求体和请求url,并没有加入随机参数和时间,所以相同的请求体请求头相同,用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
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
req_url = '/api/datalist/financiallist'
req_data = {
"keyNo": "5dffb644394922f9073544a08f38be9f",
"type": "hk",
"reportType": 1,
"currency": "CAD",
"rate": 1
}
win_tid = 'c5c144235c8441642f9af0413f60588e'


def seeds_generator(s):
seeds = {
"0": "W",
"1": "l",
"2": "k",
"3": "B",
"4": "Q",
"5": "g",
"6": "f",
"7": "i",
"8": "i",
"9": "r",
"10": "v",
"11": "6",
"12": "A",
"13": "K",
"14": "N",
"15": "k",
"16": "4",
"17": "L",
"18": "1",
"19": "8"
}
seeds_n = 20

if not s:
s = "/"
s = s.lower()
s = s + s

res = ''
for i in s:
res += seeds[str(ord(i) % seeds_n)]
return res


def a_default(url: str = '/', data: object = {}):
url = url.lower()
dataJson = json.dumps(data, ensure_ascii=False, separators=(',', ':')).lower()

hash = hmac.new(
bytes(seeds_generator(url), encoding='utf-8'),
bytes(url + dataJson, encoding='utf-8'),
hashlib.sha512
).hexdigest()
return hash.lower()[8:28]


def r_default(url: str = '/', data: object = {}, tid: str = ''):
url = url.lower()
dataJson = json.dumps(data, ensure_ascii=False, separators=(',', ':')).lower()

payload = url + 'pathString' + dataJson + tid
key = seeds_generator(url)

hash = hmac.new(
bytes(key, encoding='utf-8'),
bytes(payload, encoding='utf-8'),
hashlib.sha512
).hexdigest()
return hash.lower()


# 输出
print('key: ' + a_default(req_url, req_data))
print('val: ' + r_default(req_url, req_data, win_tid))