本文提供的意见和建议仅代表个人观点,不代表任何组织或机构的立场。本人不对任何因使用技术探讨中的信息而导致的任何直接或间接损失负责。在实施任何技术方案或建议时,请遵守当地法律法规。请在参与技术探讨时谨慎行事,如有任何疑问或需要进一步帮助,请随时向我提问。祝您探讨技术的过程愉快顺利!
先看看全流程的python效果图,主要涉及python与js,如果你有兴趣的话,那么就可以往下继续看了。
极验滑块介绍
在爬虫的过程最常见的滑块应该就是极验了吧,本次交流就以极验为案例,分析在其中的重要参数与破解思路。
抓包分析
我们对一个正常的极验流程进行抓包,分析其中有哪些重要请求与参数,废话不多说,直接上图:
1. 获取challenge
根据你要过极验的网站可以抓包分析到获取challenge的请求,相信对于屏幕面前的你,这并非难事;
我抓取这个网站的请求很简单带个时间戳就会返回一个json,重要参数是challenge ,其次是gt ,gt是组织码,极验根据组织码可以确定是哪个客户。
2. w1
在你点击开始验证后第一个请求
携带的重要参数包含1.获取的challenge与w,由于是第一个w值,在本文就称这个w值为w1,challenge与gt的获取在1.都可以得到,w1值,经过本人测试可以为空字符串(不要像我一样傻傻的去破解了)
3. w2
第二个请求
告诉你个好消息,请求中必要的参数还是1.获取的challenge与w,此处的w值称为w2,而且这里的w2同样可以为空字符串。(这个我同样也破解了,太蠢了,如果你想学习w1与w2的破解,可以在下面留言,呼声高的话,我会出一章续篇将如何破解w1与w2)
4. 获取图片路径
接下来需要一个请求获取滑块与背景图片的地址路径。
这个请求携带的参数challenge在1.已经获取,直接发送,接下来我们看看响应结果。
请求回来的结果包含红色方框的重要信息,bg对应缺少滑块的背景,fullbg完整的背景图片,slice对应滑块的图片路径,c与s是一会破解w值需要使用的变量。
关于获取图片的路径需要加上url的域名https://static.geetest.com/
,比如滑块的完整url 为: https://static.geetest.com/pictures/gt/cd0bbb6fe/slice/387108189.png
值的一提的是获取到的背景图片为乱序的,如下:
恢复正常的算法在slide.js如下位置:
将代码翻译为python之后,恢复完的图片为
那么如何计算滑块要滑动的距离呢,相信知道图片的数据格式的已经知道如何计算了,将上面两个恢复好的图片进行灰度上做差,可以得到一个差值矩阵,图片的缺口位置对应矩阵缺口位置的水平索引值。获取到了需要滑动的距离了,那么我们看看哪个请求将轨迹进行提交的。
5. w3
发送轨迹的请求如下:
没错,又是我们的老朋友1.获取的challenge与w,此处的w值称为w3,很遗憾的告诉你w3包含轨迹数据,不能为空。那么w3是如何获取的呢,在slide.js的"\u0077": h + u
,
"\u0077":
翻译过来就w。那么我们就要获取h与u的值。
从上图中的代码 可以看到h = m[$_CAIAK(792)](l)
与u = r[$_CAHJS(737)]()
,先看u是如何生成的,进入这个函数看看内部,下图中红框就是这个函数的实现。
u值:
看来最重要的是这句var e = new U()[$_CBFJN(392)](this[$_CBGAK(744)](t));
那我们解混淆一下var e = new U()["encrypt"](this["$_CCEc"](t));
,看来扣出U()
这个类之后调用了一下加密函数就能复现,我们跟一下这个函数this["$_CCEc"](t)
看来重要的是Ot = rt()
,那就跟一下rt()
,
那就是返回值这行了,return t() + t() + t() + t();
,那再看看t()
,
看来翻译一下返回值这行就行了return (65536 * (1 + Math[$_BFBFC(21)]()) | 0)[$_BFBFC(213)](16)[$_BFBFC(415)](1);
解混淆的结果是return (65536 * (1 + Math['random']()) | 0)["toString"](16)["substring"](1);
,那就是65536到2*65536的随机整数转16进制去掉第一个字符的结果,到此,只需要把上面流程复现一下,那么 u
值就破解完了。
h值:
h的值是由函数m[$_CAIAK(792)](l)
生成,入参为l
, 然而l = V[$_CAHJS(392)](gt[$_CAIAK(254)](o), r[$_CAIAK(744)]())
,解混淆一下, V["encrypt"](gt["stringify"](o), r["$_CCEc"]())
,明显又是一次加密,关键参数是o
与r["$_CCEc"]()
,先看看函数r["$_CCEc"]()
内部
好巧,这是我们在u值时候分析过的函数,直接拿过来用就行了,接下来我们看看o
是如何得到。
o值:
我们先看看o
都包含哪些内容,
其中aa
是你滑动的轨迹,ep
内部的值可以模拟,把时间戳进行以相同的规律进行模拟即可。h9s9
的值需要破解,imgload
是图片加载的时间,passtime
是你滑块阶段使用的时间。rp
与userresponse
都是需要破解的参数。这是一个objest类,所以我们只需要破解完这些参数后自己构建一个object就可以通过验证。
aa值
往上跟o
值,可以看到o
值是在下图位置创建的。
翻译一下就可一直aa
对应着e
,往上翻可以看到e
对应下图的l
,
那么我们解混淆一下l = n[$_DAAAU(985)][$_CJJJU(1075)](n[$_CJJJU(985)][$_CJJJU(1073)](), n[$_CJJJU(67)][$_CJJJU(1033)], n[$_DAAAU(67)][$_CJJJU(345)]);
的值。
解混淆的结果为:l = n['$_CICO']['$_BBED'](n['$_CICO']['$_FD_'](), n['$_CJk']['c'], n['$_CJk']['s']);
,
其中n['$_CJk']['c']
与n['$_CJk']['s']
的分别对应4. 获取图片路径中的c
值与s
值。
其中的函数n['$_CICO']['$_FD_']()
对应下图的函数
这个函数运行的结果就是轨迹的加密值"T00--/(!!Hy((ys(ssss(ts!)sssssstsssstyssss(!!($)_A@:)89)8:$,/)7?9(9:Ne999?:9:9?)r$)f"
这个函数使用很简单,将n
这个对应的属性值n['$_CICO']['$_HCb']
设置为轨迹矩阵后直接执行这个函数就可以拿到加密轨迹值,轨迹矩阵的可以直接模拟,第一列是x
轴的坐标变化,第二列是坐标y
轴的变化,第三列是时间轴t
的变化,有了滑块划动的距离后,模拟这个矩阵很容易,可以使用tanh
函数模拟,注意矩阵第一行需要特殊处理一下。如下图:
userresponse值
接下来我们看userresponse值如何生成,
"\u0075\u0073\u0065\u0072\u0072\u0065\u0073\u0070\u006f\u006e\u0073\u0065": H(t, i['challenge']),
,解混淆一下,结果是:userresponse:H(t, i['challenge'])
,t
是鼠标轨迹矩阵最后一行的x
值,i['challenge']
大家很熟悉了。对应下面这个函数
h9s9值
h9s9
的获取实在一个外部js的函数进行的入口在下图的方框位置。
入参是一个json,分别是s
与ep
,这两个值在前面已经说了怎么模拟了。这个外部函数的实现是下面这张图的n
这个函数。把json数据传入这个函数,返回值就会包含h9s9
。
rp值
rp
的获取比较简单,入口在这个位置。
让我们来翻译一下这行代码:
- 源文:
o[$_CAIAK(793)] = X(i[$_CAIAK(122)] + i[$_CAIAK(134)][$_CAIAK(187)](0, 32) + o[$_CAHJS(725)]);
- 解混淆:
o['rp'] = X(i['gt'] + i["challenge"]["slice"](0, 32) + o["passtime"]);
解完混淆就很明朗了,入参是全部都有,由已知的参数拼合一个字符串作为入参。
那么我们看看这个函数的定义:
把这个X
函数抠出来就可以完美复原rp
的值。
总结
到此为止,所有的参数都已经破解完毕,把各个参数放在对应的位置,按照流程模拟一遍就可以破解这个极验滑块流程。最后贴一张全流程的结果图。使用最后一个请求获取的"validate"
就可以继续进行你的后续业务了。