某验滑块验证原理介绍

655 阅读8分钟

极验验证码

目前,许多网站采取各种各样的措施来反爬虫,其中一个措施便是使用验证码。随着技术的发展,验证码的花样越来越多。验证码最初是几个数字组合的简单的图形验证码,后来加入了英文字母和混淆曲线。有的网站还可能看到中文字符的验证码,这使得识别愈发困难。我们今天来介绍极验验证码。

前言

今天,我们就来说说最重要的知识点,就是,3个w是怎么生成的,我们之前说前两个是不可以置空的,3个W的值思路都差不多。接下来,直接看介绍,我这时逆向是两个重要文件名是:

fullpage.9.1.8-bfget5.js

slide.7.9.2.js

极验后面会更新,如果代码失效了,在评论区评论,我也会及时更新。 

第一个W

不清楚流程的可以回顾一下,我发的极验一的文章,我们来逆向这里的w,我们之前说,全局搜索w,肯定不现实啊,我这里就教大家一个简单的方法,直接搜索"\u0077" ,这个最简单,大家还可以去跟栈,也能找到。

我们看到有三处,我们一处一处来定位,我们来看第一处,一看就不是。

我们下面看第二处,一看,感觉有点像,打个断点,刷新下网页,发现就断点了,同理,第三处,没有断点,就也排除了。我们重点来分析第二处的w。

var r = t[$_CEFDY(1196)](),
    o = $_BEH()[$_CEFCV(1127)](fe[$_CEFDY(431)](t[$_CEFCV(370)]), t[$_CEFDY(1143)]()) ,
    i = R[$_CEFDY(1197)](o)

w = i + r

我们基本的框架就拿到了,接下来就是分别去扣这些代码,这里的r是随机的,网上有人说这是什么什么加密,用自己的方法来写,我这里什么都不管,要什么补什么。

r 的值

这里的r,我会说详细一点,后面都是一样的,我就直接带过了。我们先看看这个值是什么。

我们看到这里的值是256位,我们通过js模拟生成的值也是256位就说明我们代码没有问题。我们开始扣代码,我们定位进去之后,可以看到这样的代码,你们可能变量名不一样,但是,加密都是一样的。

我们可以看出来,这个t的值就是我们r的值,我们把这行代码扣出来,是这样的。

var r = new G()[$_CGHDO(93)](this[$_CGHDO(1143)](e))

我们看到里面的参数是随机数,我们同样的方法定位到里面去,我们上面的代码可以改为:

//Ot = rt()//先注释掉

Ot = 'a9346ff09bcf3a83'
var r = new G()['encrypt'](Ot)

我们思路就清晰了,扣生成随机数rt()的代码,还有去扣G()的代码。这里,直接定位,全部扣下来就可以了,我这里放几张代码位置的图片。

我们这里的随机值可以写死,不影响我们后面的加密,这里的随机值就相当于密钥。

这里不够直观,我们在第三个w的时候会直观一点。我们还要把最前的属性函数也要扣下来,就是下面这一块。

另外两个w也是一样的,宁愿多扣也不要少抠代码。我们看看自己生成的r是不是256位。

到这里,我们的r的值就生成了,这里的G函数代码很长,一定要完整扣下来,第三个w也可以用这个生成,只是函数名不一样。到这里,没有问题的话,我们就扣下一个值。

o的值

我们接下来,就去扣这个o的值,我们先看看源代码怎么写的。

 o = $_BEH()[$_CEFCV(1127)](fe[$_CEFDY(431)](t[$_CEFCV(370)]), t[$_CEFDY(1143)]())

我们看到这里就很明确了,我们把刚刚的o的值简单修改一下,是这样的。

 o = $_BEH()['encrypt1'](fe['stringify'](t[$_CEFCV(370)]), Ot)

我这里简单解释一下,t$_CEFDY(1143) 我们发现实际上就是我们刚刚生成的随机数,这里,传入的两个随机数要一致,所以前面我们为什么要写成

Ot = rt()

这个rt()函数我们后面会讲到,这里先写固定值,fe['stringify'] 大概率就是json数据格式化,这个我们可以用现成的方法JSON.parse,我们这里还是直接扣代码,t[$_CEFCV(370)] 我们发现这个对象包含了我们的gt和challenge的值。接下来,就是抠代码:

  1. $_BEH()函数,//后面的w也用到了这个函数,只是函数名字不一样。
  2. fe函数,// 后面的w也用到了这个函数,只是函数名字不一样。
  3. t[$_CEFCV(370)] 的值扣下来,现在,先把gt和challenge的值固定

这三个部分很容易就拿到了,我这里给大家看下截图:

我们这里把这个对面命名位nt,大概有一下内容,这里的gt和challenge先固定,等我们代码没有问题,再把gt和challenge的值传进来。

{
    "gt": "019924a82c70bb123aae90d483087f94",
    "challenge": "7178a48de3923230de74008295402041",
    "offline": false,
    "new_captcha": true,
    "product": "float",
    "width": "300px",
    "https": true,
    "api_server": "apiv6.geetest.com",
    "protocol": "https://",
    "type": "fullpage",
    "static_servers": [
        "static.geetest.com/",
        "static.geevisit.com/"
    ],
    "beeline": "/static/js/beeline.1.0.1.js",
    "voice": "/static/js/voice.1.2.4.js",
    "click": "/static/js/click.3.1.0.js",
    "fullpage": "/static/js/fullpage.9.1.8-bfget5.js",
    "slide": "/static/js/slide.7.9.2.js",
    "geetest": "/static/js/geetest.6.0.9.js",
    "aspect_radio": {
        "slide": 103,
        "click": 128,
        "voice": 128,
        "beeline": 50
    },
    "cc": 4,
    "ww": true,
    "i": "-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!"
}

我们看看扣完的效果,如果,这里的o是一样的,我们代码就没有问题了。

我们可以看到我们的o的值和网页生成的一模一样,我们接下来就是去搞i的值。

i的值

我们接下来,就去扣这个i 的值,我们先看看源代码怎么写的。

i = R[$_CEFDY(1197)](o)

我们发现这个特别简单,我们老规矩,先看看$_CEFDY(1197)是什么,我们在简单修改一下。

i = R['$_HDZ'](o)

我们发现o,我们得到了,现在就是去拿这个R()函数,这个,我们直接给大家了。很好找的。

我们把这个R拿下来,因为太长了,我就不贴代码了,大家自己去扣,我们看看最后的效果。

我们看到这里的i,我们也生成出来了,最后的w肯定也没有问题。

w的值

我们知道第一个w是i + r,到这里,我们第一个w就解决了,我们来看看效果,你有什么问题可以在评论区留言。

第二个W

w的值

我们这里的w和其他地方不大一样,不过通过跟栈的方式也很容易找到,如下图所示:

我们定位到了w的位置,我们接下来就是仔细分析分别用了哪些加密方法。

W2 =  R[$_CFHIs(1197)](c[$_CFHIs(93)](r, i[$_CFHIs(1143)]()));

我们这里简单修改下代码,现在是这个样子的。

 w2 = R['$_HDZ'](c['encrypt'](r,Ot));

我们发现这个w2要简单一点,前面的R()函数,我们之前就拿到了,我们这里直接就用了,后面的Ot就是我们之前生成的随机数,这里要和前面生成w1的时候要一样,不然会报错。我们这里的c'encrypt' 实际上就是我们前面的 $_BEH()['encrypt'](r, Ot). 到这里,问题就简单了。

 w2 = R['$_HDZ']($_BEH()['encrypt'](r,Ot));

我们接下来,就是去看这个r是什么。

我们这里直接复制出来,大家可以自己往前找,能找到每个参数怎么生成的。我这里主要来说rp参数是怎么生成的,因为这个还是比较重要的,其他的可以写固定。

nr = {
    "lang": "zh-cn",
    "type": "fullpage",
    "tt": "",
    "light": "SPAN_0",
    "s": "c7c3e21112fe4f741921cb3e4ff9f7cb",
    "h": "321f9af1e098233dbd03f250fd2b5e21",
    "hh": "39bd9cad9e425c3a8f51610fd506e3b3",
    "hi": "09eb21b3ae9542a9bc1e8b63b3d9a467",
    "vip_order": -1,
    "ct": -1,
    "ep": {},
    "passtime": 5365,
    "rp": "0d51406b2c658811294a91e9ea533bed",
    "captcha_token": "541381339",
    "gdyf": "kqy8o0w7"
}

其中 ep 里面的 venren 是显卡相关信息,fplp 是取了两个鼠标移动的位置信息,直接写死为 null 也可以,tm 就是 window.performance.timing 的一些东西,自己随便伪造一下就行了,或者固定不改都行。

我们这里要注意下,r参数还要JSON数据格式,我们直接模仿前面的写法就可以。

 nr = {"自行复制"}

 w2 = R['$_HDZ']($_BEH()['encrypt'](fe['stringify'](nr), Ot))

我们来看看效果:

我们这里要注意一下,那个Ot的值用网页生成的随机数,这样可以验证我们扣的代码对不对,后面,我们自己在调用的时候可以写随机。 

rp的值

我们这里先把这个rp参数抠出来,第三个生成w的时候,也用到了rp,加密方式都是一样的。

我在图片里面标注很清楚了,这个是MD5加密,我们直接用现成的库,不会安装的,自行百度。唯一要注意的一点是这里的pass time的值要和r参数里面的pass time要一样,这个pass time可以写固定,第三个w就要传值进来。

 var CryptoJS = require("crypto-js");
    gtt = '019924a82c70bb123aae90d483087f94'
    challenge = '7d59427b8c64734df3d8aa8585311fac'
    var rp = CryptoJS.MD5(gtt + challenge + 1986).toString()

我们到这里,就成功实现了两个w的模拟生成,这时候,我们可以把我们刚刚写的封装成函数,把challenge传进来就可以了。gt每个网页的值不一样,相当于产品的ID,由于,我们在拿这个网站在做测试,我们就不去改这个了,还有就是把r参数里面的rp传进去。

第三个W

我们到这里,就成功80%了,因为这个w的思路和第一个差不多。我们先定位位置,和前面一样。

我们这时是不是感觉似曾相识,这个就是和第一次一模一样。

            var u = r[$_CAHJS(737)](), 
            l = V[$_CAHJS(392)](gt[$_CAIAK(254)](o), r[$_CAIAK(744)]()),
            h = m[$_CAIAK(792)](l)

            w3 = h + u

我们基本的框架就拿到了,接下来就是分别去扣这些代码,这里的r是随机的,网上有人说这是什么什么加密,用自己的方法来写,我这里什么都不管,要什么补什么。

u 的值

我们定位到里面去,加密方式一样的,这里用的参数是U,我们这里直接用之前的方法来加密,这里同样会有个随机数,前面说,这里会教大家扣这个rt(),我们肯定先在这里断点,定位到这个随机函数。

    Ot = rt()

    var u = new U()['encrypt'](Ot)

我们这里rt()自己去扣,U用之前的就可以了。

l的值

我们接下来,就去扣这个l 的值,我们先看看源代码怎么写的。

l = V[$_CAHJS(392)](gt[$_CAIAK(254)](o), r[$_CAIAK(744)]())

 l = V['encrypt'](gt['stringify'](o), Ot)

o的值(含轨迹aa加密)

我们这里和前面一样,V可以自己扣,也可以用前面的,我们接下来看看这个o是啥。里面包含了我们的轨迹等等。

{
    "lang": "zh-cn",
    "userresponse": "6c4667a3",
    "passtime": 467,
    "imgload": 367,
    "aa": "P(!!Rssstostsztstszztuyststsbtttsststsz(!!(YE81:111911111111111111102020:8QR$)UD",
    "ep": {
        "v": "7.9.2",
        "$_BIE": false,
        "me": true,
        "tm": {},
        "td": -1
    },
    "h9s9": "1816378497",
    "rp": "b121b8e4e23b32bc6da9ef189266267e"
}

可以看到o对象里面有众多参数

  • aa 是轨迹加密
  • ep h9s9 imgload lang 可固定
  • userresponse 滑动距离 + challenge 加密结果
  • passtime 拖动时间
  • rp 是 gt +challenge + passtime 加密结果

我们主要就是自己生成user response,aa,rp。rp就是我们第二个W说到的rp,我们可以用那个代码。

 var CryptoJS = require("crypto-js");
    gtt = '019924a82c70bb123aae90d483087f94'
    challenge = '7d59427b8c64734df3d8aa8585311fac'
    var rp = CryptoJS.MD5(gtt + challenge + 476).toString()

我们在l的地方,往上面翻一点点,可以看到o对象生成的地方,我们在user response地方断点。

这个H函数自己去扣,传进来了两个参数,一个是距离,还有一个是最新的challenge,我第一篇文章说到过,我们会拿到新的challenge和S的值。

这里前面的属性函数和环境变量直接去扣,这个贴上去太长了,trace是我们生成的轨迹,我们先固定,C的值不变,我们也固定,那个S的值,是我们最新得到的S,我们把这个S的值传进来就能得到我们的轨迹。

h的值

我们接下来,就去扣这个h 的值,我们先看看源代码怎么写的。

h = m[$_CAIAK(792)](l)

我们发现这个特别简单,我们可以选择去扣这个m,或者去用第一次的R函数。到这里,我们的h也搞出来了,自然,我们的w也出来了。

总结

我们今天花了很多内容去解释了三个w的生成,想要源码的可以评论区留言,我们看看最后的效果吧。

我还去测试了某平台手机发送验证码的滑块,这个网站只要最后一个w就可以,等大家学完这个官网的逆向,其他js基本上简单修改就可以使用了。


严正声明:本文仅供交流学习,勿用于非法用途