免责声明:本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!

逆向目标

逆向过程

抓包分析有2个接口,一个是获取验证码的接口https://gcaptcha4.geetest.com/load,一个是进行验证的接口https://gcaptcha4.geetest.com/verify

获取验证码接口

入参

参数如下:

1
2
3
4
5
6
7
8
{
"captcha_id": "54088bb07d2df3c46b79f80300b0abbe",
"challenge": "10cea755-08d2-4c7f-900f-d30d81301aa5",
"client_type": "web",
"risk_type": "winlinze",
"lang": "zh",
"callback": "geetest_1684505012579"
}

入参除了risk_type与消消乐不同外,其它都一样,消消乐的risk_type为match,这里为winlinze。消消乐验证码逆向分析见JS逆向案例——极验消消乐验证码逆向分析

接口返回值

1
2
3
4
5
6
{
"lot_number": "5a1ad5b0399c4a55b416f81d94e112e5",
"payload": "11-UPJ-Jb2g3IpmYoaJlOw5fEieqchiSh9mIS5Ifj...",
"process_token": "50e908f0ea51c1a16ac0f8a1af6270903d45a4c68572760378125e308c5d8727",
"ques": [[0, 0, 3, 4, 3], [1, 2, 4, 4, 4], [1, 2, 4, 3, 4], [1, 2, 4, 2, 0], [0, 2, 4, 0, 3]]
}

接口返回与五子棋基本一致,只是ques数组第二维里面的元素个数不一样,代表的含义也不一样。

image-20230523103653587

如上图,0代表空格,1~4代表4种棋子。

验证码验证接口

入参

参数如下:

1
2
3
4
5
6
7
8
9
10
11
{
"lot_number": "224a2186c59f470cb73897f377843df5",
"payload": "11-UPJ-Jb2g3IpmYoaJlOw5fEieqchiSh9mIS5Ifj...",
"process_token": "d4a636b32cee705e5314b90bce43f71ead1f2b6a0b5cb44c50b71bf28f6f9423",
"w": "73bfc2bde060aac064f99128586dc53c9ee05cc25840aa1dc77445727e2e86c342b8cde...",
"callback": "geetest_1684505905348",
"client_type": "web",
"risk_type": "winlinze",
"payload_protocol": 1,
"pt": 1
}

其中入参与消消乐的都一模一样,同样只是risk_type不是match而是winlinze。

另外所有加密方法与对象都与消消乐一致,就连对象e都一模一样,对比消消乐e结构和五子棋的e结构:

五子棋的:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"passtime":450,
"userresponse": [[1,3], [0,3]],
"device_id":"9f5faf6dc7a77e1d394c8634f0893812",
"lot_number":"5553a2835b7046d2abd595e82fc62703",
"pow_msg":"1|0|md5|2023-05-23T10:41:08.568519+08:00|54088bb07d2df3c46b79f80300b0abbe|5553a2835b7046d2abd595e82fc62703||a19a8f9a8bdc0db7",
"pow_sign":"ab3742f987977542c73a36692fdd5a08",
"geetest":"captcha",
"lang":"zh",
"ep":"123",
"e0vm":"2135175515",
"em":{"ph":0,"cp":0,"ek":"11","wd":1,"nt":0,"si":0,"sc":0}
}

消消乐的:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"passtime": 550,
"userresponse": [[1, 0], [2, 0]],
"device_id": "9f5faf6dc7a77e1d394c8634f0893812",
"lot_number": "224a2186c59f470cb73897f377843df5",
"pow_msg": "1|0|md5|2023-05-22T11:10:02.686802+08:00|54088bb07d2df3c46b79f80300b0abbe|224a2186c59f470cb73897f377843df5||62b052493785e2b7",
"pow_sign": "506fe742ff81d4bb3bf34892714fa2fc",
"geetest": "captcha",
"lang": "zh",
"ep": "123",
"e0vm": "915661778",
"em": {"ph": 0, "cp": 0, "ek": "11", "wd": 1, "nt": 0, "si": 0, "sc": 0}
}

两者结构虽然一致,但是userresponse的逻辑含义有区别,五子棋是将一个棋子移动到空格位置的坐标信息,而消消乐则是要交换的两个图案信息。

五子棋算法

由于是5x5的五子棋棋盘,并且只需要交换一对棋子就可完成五子连珠,所以直接采取暴力穷举即可。算法代码如下:

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
function winlinze_by_row(ques) {
// 统计每一个数字出现的次数
let count = function (arr, target) {
let c = 0;
for (let j = 0; j < arr.length; j++) {
if (arr[j] === target)
c++;
}
return c;
}

// 查找除指定行之外相同元素的位置
let checkRow = function (arr, besides, target) {
for (let i = 0; i < arr.length; i++) {
if (i === besides)
continue;
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] === target)
return [i, j]
}
}
}

// 查找指定行的空格位置
let checkEmpty = function (arr, row) {
for (let i = 0; i < arr[row].length; i++) {
if (arr[row][i] === 0)
return [row, i]
}
}

// 看每一行是否存在四颗一样的棋子
for (let i = 0; i < ques.length; i ++){
let c = [];
let emptySite = 0;
// 统计1-4号棋子以及空格的个数
for (let m = 0; m < ques[i].length; m++)
c[m] = count(ques[i], m);
for (let m = 0; m < ques[i].length; m++) {
// 该行上有四颗颜色一样的棋子,并且有空格
if (c[m] === 4 && c[0] === 1) {
// 查找指定
let t = checkRow(ques, i, m);
if (t.length !== 0)
return [t, checkEmpty(ques, i)]
}
}
}
}

function winlinze_by_diagonal(ques) {
let leftSites = [[0, 0], [1, 1], [2, 2], [3, 3], [4, 4]];
let rightSites = [[0, 4], [1, 3], [2, 2], [3, 1], [4, 0]];
let checkEmpty = function (ques, sites) {
for (let i = 0; i < sites.length; i++) {
if (ques[sites[i][0]][sites[i][1]] === 0)
return [i, sites[i]]
}
}

let count = function (ques, sites, target) {
let c = 0;
for (let j = 0; j < sites.length; j++) {
if (ques[sites[j][0]][sites[j][1]] === target)
c++;
}
return c;
}

let indexOf = function (sites, i, j) {
for (let k = 0; k < sites.length; k++) {
if (sites[k][0] === i && sites[k][1] === j)
return true;
}
return false
}

let search = function (ques, sites, target) {
for (let i = 0; i < ques.length; i++) {
for (let j = 0; j < ques[i].length; j++) {
if (ques[i][j] === target && !indexOf(sites,i, j))
return [i, j]
}
}
}

let sites = [leftSites, rightSites];
for (let i = 0; i < sites.length; i++) {
let e = checkEmpty(ques, sites[i]);
let s = new Set();
for (let j = 0; j < sites[i].length; j++)
s.add(ques[sites[i][j][0]][sites[i][j][1]]);
if (s.size === 2 && count(ques, sites[i], ques[e[1][0]][e[1][1]]) === 1) {
let rand = (e[0]+1) % 5;
let w = search(ques, sites[i], ques[sites[i][rand][0]][sites[i][rand][1]]);
if (w && w.length > 0)
return [e[1], w]
}
}
}


function get_userresponse(ques) {
// 根据行去判断是否可以五子连线
let arr = winlinze_by_row(ques);
if (arr && arr.length > 0)
return arr;

// 如果按行不行,则按列
if (arr === undefined || arr.length === 0) {
// 行列互换
let new_ques = [];
for (let index = 0; index < ques.length; index++)
new_ques[index] = [ques[0][index], ques[1][index], ques[2][index], ques[3][index], ques[4][index]];
arr = winlinze_by_row(new_ques);
// 得到的结果再将列转化为行
let new_arr = [];
for (let index = 0; arr && index < arr.length; index++)
new_arr[index] = [arr[index][1], arr[index][0]]
if (new_arr.length > 0)
return new_arr;

// 按列也不行,查找对角线是否可以五子连线
return winlinze_by_diagonal(ques)
}
}

运行与测试

运行结果如下:

image-20230523140001088

同样的,只要五子棋算法没问题,五子棋验证的通过率就是百分百。

若需要完整代码,扫描加微信。

image-20230517010053227