摘要
分析验证码素材图片混淆原理,并采用selenium模拟人拖动滑块过程,进而破解验证码。
人工验证的过程
1、打开威锋网注册页面
2、移动鼠标至小滑块,一张完整的图片会出现(如下图1)
3、点击鼠标左键,图片中间会出现一个缺块(如下图2)
4、移动小滑块正上方图案至缺块处
5、验证通过
selenium模拟验证的过程
- 加载威锋网注册页面
- 下载图片1和缺块图片2
- 根据两张图片的差异计算平移的距离x
- 模拟鼠标点击事件,点击小滑块向右移动x
- 验证通过
- 详细分析
1、打开chrome浏览器控制台,会发现图1所示的验证码图片并不是极验后台返回的原图。而是由多个div拼接而成(如下图3)
通过图片显示div的style属性可知,极验后台把图片进行切割加错位处理。把素材图片切割成10 * 58大小的52张小图,再进行错位处理。在网页上显示的时候,再通过css的background-position属性对图片进行还原。以上的图1和图2都是经过了这种处理。在这种情况下,使用selenium模拟验证是需要对下载的验证码图片进行还原。如上图3的第一个div.gt_cut_fullbg_slice标签,它的大小为10px * 58px,其中style属性为background-image: url("http://static.geetest.com/pictures/gt/969ffa43c/969ffa43c.webp"); background-position: -157px -58px;会把该属性对应url的图片进行一个平移操作,以左上角为参考,向左平移157px,向上平移58px,图片超出部分不会显示。所以上图1所示图片是由26 * 2个10px * 58px大小的div组成(如下图4)。每一个小方块的大小58 * 10
2、下载图片并还原,上一步骤分析了图片具体的混淆逻辑,具体还原图片的代码实现如下,主要逻辑是把原图裁剪为52张小图,然后拼接成一张完整的图。
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
|
/**
*还原图片
* @param type
*/
private static void restoreimage(string type) throws ioexception {
//把图片裁剪为2 * 26份
for ( int i = 0 ; i < 52 ; i++){
cutpic(basepath + type + ".jpg"
,basepath + "result/" + type + i + ".jpg" , -movearray[i][ 0 ], -movearray[i][ 1 ], 10 , 58 );
}
//拼接图片
string[] b = new string[ 26 ];
for ( int i = 0 ; i < 26 ; i++){
b[i] = string.format(basepath + "result/" + type + "%d.jpg" , i);
}
mergeimage(b, 1 , basepath + "result/" + type + "result1.jpg" );
//拼接图片
string[] c = new string[ 26 ];
for ( int i = 0 ; i < 26 ; i++){
c[i] = string.format(basepath + "result/" + type + "%d.jpg" , i + 26 );
}
mergeimage(c, 1 , basepath + "result/" + type + "result2.jpg" );
mergeimage( new string[]{basepath + "result/" + type + "result1.jpg" ,
basepath + "result/" + type + "result2.jpg" }, 2 , basepath + "result/" + type + "result3.jpg" );
//删除产生的中间图片
for ( int i = 0 ; i < 52 ; i++){
new file(basepath + "result/" + type + i + ".jpg" ).deleteonexit();
}
new file(basepath + "result/" + type + "result1.jpg" ).deleteonexit();
new file(basepath + "result/" + type + "result2.jpg" ).deleteonexit();
}
|
还原过程需要注意的是,后台返回错位的图片是312 * 116大小的。而网页上图片div的大小是260 * 116。
3、计算平移距离,遍历图片的每一个像素点,当两张图的r、g、b之差的和大于255,说明该点的差异过大,很有可能就是需要平移到该位置的那个点,代码如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
bufferedimage fullbi = imageio.read( new file(basepath + "result/" + full_image_name + "result3.jpg" ));
bufferedimage bgbi = imageio.read( new file(basepath + "result/" + bg_image_name + "result3.jpg" ));
for ( int i = 0 ; i < bgbi.getwidth(); i++){
for ( int j = 0 ; j < bgbi.getheight(); j++) {
int [] fullrgb = new int [ 3 ];
fullrgb[ 0 ] = (fullbi.getrgb(i, j) & 0xff0000 ) >> 16 ;
fullrgb[ 1 ] = (fullbi.getrgb(i, j) & 0xff00 ) >> 8 ;
fullrgb[ 2 ] = (fullbi.getrgb(i, j) & 0xff );
int [] bgrgb = new int [ 3 ];
bgrgb[ 0 ] = (bgbi.getrgb(i, j) & 0xff0000 ) >> 16 ;
bgrgb[ 1 ] = (bgbi.getrgb(i, j) & 0xff00 ) >> 8 ;
bgrgb[ 2 ] = (bgbi.getrgb(i, j) & 0xff );
if (difference(fullrgb, bgrgb) > 255 ){
return i;
}
}
}
|
4、模拟鼠标移动事件,这一步骤是最关键的步骤,极验验证码后台正是通过移动滑块的轨迹来判断是否为机器所为。整个移动轨迹的过程越随机越好,我这里提供一种成功率较高的移动算法,代码如下。
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
|
public static void move(webdriver driver, webelement element, int distance) throws interruptedexception {
int xdis = distance + 11 ;
system.out.println( "应平移距离:" + xdis);
int movex = new random().nextint( 8 ) - 5 ;
int movey = 1 ;
actions actions = new actions(driver);
new actions(driver).clickandhold(element).perform();
thread.sleep( 200 );
printlocation(element);
actions.movetoelement(element, movex, movey).perform();
system.out.println(movex + "--" + movey);
printlocation(element);
for ( int i = 0 ; i < 22 ; i++){
int s = 10 ;
if (i % 2 == 0 ){
s = - 10 ;
}
actions.movetoelement(element, s, 1 ).perform();
printlocation(element);
thread.sleep( new random().nextint( 100 ) + 150 );
}
system.out.println(xdis + "--" + 1 );
actions.movebyoffset(xdis, 1 ).perform();
printlocation(element);
thread.sleep( 200 );
actions.release(element).perform();
}
|
完整代码如下
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
214
215
216
217
218
219
220
221
222
223
224
225
226
|