声明

原创文章,请勿转载!

本文内容仅限于安全研究,不公开具体源码。维护网络安全,人人有责。

环节概述

首先我们还是需要使用请求转发工具,把目标代码替换为我们处理过的代码。

  1. 观察验证过程中触发了哪些请求
  2. 破解 w参数
  3. 根据参数构造请求

验证过程中触发的请求

  1. 请求总览

    请求里有两个参数:gt 和 challenge,这两个参数非常重要,后续的请求也都会携带他们,极验通过这两个参数来标识你在做什么操作,以及后续还需什么流程。

    其中 gt 是定值,这个是和极验申请的 ID。

    challenge 是一个行为的 ID,上一步的操作会返回你新操作的 challenge,然后下一个操作带上这个新 challenge 即可。

    同时每个请求返回的都是 JSONP,我们自己解析返回值的时候注意处理下格式即可(比如用正则匹配出来结果)

    请求中另外一个最重要的参数是 w。它是被加密过的一段数据,是校验通过与否的核心,我们这次的目的就是破解这个 w 参数。

  2. gettype.php:获取核心 JS 文件链接

  3. get.php:无感验证的一部分,收集浏览器信息并上报。其中 c 和 s 比较关键,后续的请求会用到它

  4. ajax.php:执行无感验证。如果验证失败会返回验证类型,比如滑块,点选等。

  5. slide.x.x.x.js:正式进入滑动验证的部分,这里是在加载相关 JS 文件

  6. get.php:获取滑动验证的一些基本数据,需要关注的有 bg, c, challenge, fullbg, gt, slice, s

  7. ajax.php:执行滑动验证,成功后返回 validate

破解 w 参数

因为本次介绍的内容是滑动验证,所以 fullpage.js 发起的无感验证的相关请求,里面加密的 w 参数随便填,其他的参数看着填即可。这样最后就会触发滑动验证。

因为我们破解的关键在于 w 参数,所以先在本地代码搜索下它,然后在那里写一个 debugger 进去,这样我们可以在它执行时随意调试了。

  1. 观察 w 是怎么来的

    #mermaid-svg-vPxs4qz1ocXS2K3p {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-vPxs4qz1ocXS2K3p .error-icon{fill:#552222;}#mermaid-svg-vPxs4qz1ocXS2K3p .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vPxs4qz1ocXS2K3p .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-vPxs4qz1ocXS2K3p .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vPxs4qz1ocXS2K3p .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vPxs4qz1ocXS2K3p .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vPxs4qz1ocXS2K3p .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vPxs4qz1ocXS2K3p .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vPxs4qz1ocXS2K3p .marker.cross{stroke:#333333;}#mermaid-svg-vPxs4qz1ocXS2K3p svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vPxs4qz1ocXS2K3p .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-vPxs4qz1ocXS2K3p .cluster-label text{fill:#333;}#mermaid-svg-vPxs4qz1ocXS2K3p .cluster-label span{color:#333;}#mermaid-svg-vPxs4qz1ocXS2K3p .label text,#mermaid-svg-vPxs4qz1ocXS2K3p span{fill:#333;color:#333;}#mermaid-svg-vPxs4qz1ocXS2K3p .node rect,#mermaid-svg-vPxs4qz1ocXS2K3p .node circle,#mermaid-svg-vPxs4qz1ocXS2K3p .node ellipse,#mermaid-svg-vPxs4qz1ocXS2K3p .node polygon,#mermaid-svg-vPxs4qz1ocXS2K3p .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vPxs4qz1ocXS2K3p .node .label{text-align:center;}#mermaid-svg-vPxs4qz1ocXS2K3p .node.clickable{cursor:pointer;}#mermaid-svg-vPxs4qz1ocXS2K3p .arrowheadPath{fill:#333333;}#mermaid-svg-vPxs4qz1ocXS2K3p .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vPxs4qz1ocXS2K3p .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vPxs4qz1ocXS2K3p .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-vPxs4qz1ocXS2K3p .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-vPxs4qz1ocXS2K3p .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vPxs4qz1ocXS2K3p .cluster text{fill:#333;}#mermaid-svg-vPxs4qz1ocXS2K3p .cluster span{color:#333;}#mermaid-svg-vPxs4qz1ocXS2K3p div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vPxs4qz1ocXS2K3p :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

    l 来自
    w
    h
    u
    r.$_CCDv()
    m.$_GGc(l)
    V.encrypt(pt.stringify(o), r.$_CCEB())

    可以看出 w 参数有两个部分组成,其中每个部分有自己独特的构造逻辑。我们要做的就是把不会变的逻辑单独拿出来,然后会变动的部分想办法做破解。

  2. 破解 u 参数

    我们进入 r.$_CCDv() 这个函数,他是这样的:

    里面首先有一个 U 对象,并且调用了它内部的一个函数。我们不太需要关心这个对象具体的逻辑,把他复制出来直接调用即可。

    然后它还会调用上方的一个 $_CCEB 函数。这个函数的逻辑其实很简单,里面的 rt 函数点击去是这样的。

    可以看出它的功能只是生成一个随机值。

    这些代码我们都复制出来,u 参数已经破解好了。

    function getRandomTextHelper() {const helper = () => ((65536 * (1 + Math.random())) | 0).toString(16).substring(1)return helper() + helper() + helper() + helper()
    }
    // 随机值的缓存
    var oldRandomText = getRandomTextHelper()
    // 这个就是刚才生成随机值的函数
    function getRandomText(needRefresh) {if (needRefresh) {oldRandomText = getRandomTextHelper()}return oldRandomText
    }// 获取 u 参数
    function getU() {// U 对象自己复制出来即可,太长了var e = new U().encrypt(getRandomText())while (!e || 256 !== e.length) e = new U().encrypt(getRandomText(true))return e
    }// 自行把这个对象复制过来
    var U = ...
    
  3. 破解 h 参数

    这个 h 参数的生成相对复杂一些。从刚才的代码我们可以看出,h来自于ll又来自于o

    其中 hl 的逻辑比较简单,只是简单的复制工作。

    1. h 参数:var h = m.$_GGc(l)

      这个 $_GGc 函数其实也是固定内容,复制下来即可。

    2. l 参数:var l = V.encrypt(pt.stringify(o), r.$_CCEB())

      V 这个对象和上面的 U 差不多,复制出来即可。

      pt.stringify 这个函数也是固定的函数,复制出来即可。

      r.$_CCEB() 就是刚才的生成随机数的函数。

    3. o 参数

      这个参数是最复杂的一个部分。我们先看下这个参数是在哪里创建的。

      从这里我们已经可以确定一些字段了。

      • lang 是语言,我们可以直接设为 zh-cn
      • userresponse:H 是一个固定的函数,可以复制出来,t 具体是什么暂时不确定,i.challenge 看起来是接口返回的 challenge ,我们一会儿可以确认一下。
      • passtime:验证的通过时间,来自函数入参 n
      • imgload:验证码图片的加载时间,搞个 30 - 100ms 的随机值即可
      • aa:暂时还不确定是什么,来自函数入参 e
      • ep:点进去是这样的

      里面的内容可以简单填写为这样:

      现在我们需要继续研究 ten 三个参数的生成逻辑,但是目前不好通过分析代码来获得更多内容了,所以我们根据刚才的 debugger 断点,去页面上具体研究。

    4. ten 参数

      进入断点之后,我们可以看到变量的具体内容。先确定先找个函数的入参 t e n 分别是数字,奇怪的字符串,数字。

      因为这三个值是函数的入参,所以我们根据调用栈,前往它的上层函数看看。

      同时这个函数具体的代码是这样的:

      对于 passtime 对应的 n 参数:

      我们根据代码可以确定,它就是整个滑动验证中,鼠标从摁下到抬起经过的时间。

      对于 userresponse 对应的 t 参数,也就是这里的 u 参数,我们添加额外的 debugger,结合上述操作步骤,我们发现它其实是滑块的滑动距离,同时challenge字段确实就是接口返回到的challenge 字段。

      对于 aa 对应的 e 参数,也就是这里的 l 参数,我们通过观察代码,结合 debugger 数据可以发现,里面 cs是来自于接口的cs字段,_BBES 是固定的函数,同样也是复制下来即可。不过里面的$_GFJ() 部分有些特殊,通过断点我们发现里面涉及到一个大数组。

      这个大数组其实是对鼠标拖动滑块的轨迹的记录。

      我们观察一下发现:

      • 大数组有多个小数组构成,小数组的定义是:[x, y, time]

      • 第一行的 x y 是负数,并非从 0 开始,第二项所有的值均为 0

      • 每次记录的耗时大约在 10ms

      根据这个结论,我们大致实现一个函数来构造轨迹

      function generateSlideTrace(distance: number) {// 前两行按照刚才的观察来构造const trace = [[random(-50, -10), random(-50, -10), 0],[0, 0, 0],]// 轨迹记录数量const count = 30 + Math.floor(distance / 2)// 耗时let t = random(50, 100)// 记录上一个轨迹let lastX = 0let lastY = 0let lastYCount = 0for (let i = 0; i < count; i++) {// 已滑动的距离const x = Math.round(i == count ? 1 : (1 - Math.pow(2, (-10 * i) / count)) * distance)// 耗时t += random(10, 20)if (x === lastX) {// 不合理continue}lastYCount += 1if (lastYCount > random(5, 10)) {// y 的变动不太大,连续多个 y 之后再考虑更新lastYCount = 0lastY = random(-2, 2)}lastX = xtrace.push([x, lastY, t])}return trace
      }
      
  4. 合并 uh

    至此,我们已经完成了所有的待破解元素。接下来把两个参数合并就是最后的 w 参数了。整体的代码是这样的(变量名做了点优化):

    // 计算 w 参数,props 里是 c、s、trace(滑动轨迹数组)、challenge
    export function getSlideW(props) {return getSlideLeft(props) + getRight()
    }function getSlideLeft(props) {// encodeLeft 是扣出来的代码,getL 同理return encodeLeft(getL(props))
    }function getL({ c, s, trace, challenge }) {const o = {lang: 'zh-cn',userresponse: H(trace.at(-1)[0], challenge),passtime: trace.at(-1)[2],imgload: Math.floor(Math.random() * 50 + 30),// getAA 是抠出来的代码,encodeTrace 同理aa: getAA(encodeTrace(trace), c, s),ep: {v: '7.8.8',$_BIQ: false,me: true,tm: -1,td: -1,},}// 都是抠出来的代码return V.encrypt(stringify(o), getRandomText())
    }function getRight() {var e = new U().encrypt(getRandomText())while (!e || 256 !== e.length) e = new U().encrypt(getRandomText(true))return e
    }function getRandomTextHelper() {const helper = () => ((65536 * (1 + Math.random())) | 0).toString(16).substring(1)return helper() + helper() + helper() + helper()
    }
    var oldRandomText = getRandomTextHelper()
    function getRandomText(needRefresh) {if (needRefresh) {oldRandomText = getRandomTextHelper()}return oldRandomText
    }// 下面的是从 slide 文件里抠出来的逻辑
    function stringify(t, e, n) { ... }
    function H(t, e) { ... }
    function getAA(t, e, n) { ... }
    function encodeTrace(arr) { ... }
    function encodeLeft(l) { ... }var U = ...
    var V = ...

构造请求

构造请求的过程其实和真是进行验证时的过程相同,按照上面对请求过程的分析,使用合适的参数发出对应的请求即可。

大致的顺序为:ajax.php -> get.php -> 得到基本数据,计算参数 -> ajax.php -> 验证成功!

总结

这一节内容里,我们分析了网络请求和代码逻辑,理清了请求的顺序、作用,并得到了核心参数 w 的计算逻辑,最后成功根据参数通过了验证。

至此极验三代滑动验证码的分析已结束,之后我会更新其他验证方案的分析过程,感兴趣的朋友欢迎和我交流。


本期文章到这里就结束了,如果对您有帮助,记得收藏关注,有什么想法也可以联系我哦。

后续内容持续更新中。。。

破解极验三代滑动验证,成功率百分之百(三):构造参数,发起请求相关推荐

  1. 网络爬虫-破解极验三代滑动验证码

    什么是"极验"? 如果你是从事爬虫相关工作的,那么一定对这两个字不会陌生的. 极验是首家「行为式验证」安全技术服务提供商,并以提供验证码服务而闻名.我们日常会登录一些网站,有的网站 ...

  2. Python Selenium 破解极验(GeeTest)滑动验证

    ArmourGeeTestArmourGeeTestArmourGeeTest [TOS] 本项目仅供交流学习,有疑问请在issue中提出: 本项目不提供面向任何商业需求的版本迭代: 关于本项目源码的 ...

  3. 极验三代滑块验证分析

    声明 原创文章,请勿转载! 本文内容仅限于安全研究,不公开具体源码.维护网络安全,人人有责. w值生成逆向分析 目标链接:aHR0cHM6Ly93d3cuZ2VldGVzdC5jb20vZGVtby9 ...

  4. 爬虫入门经典(十九) | 难度提升,破解极验验证码

      大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语-不温不火,本意是希望自己性情温和.作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己 ...

  5. 如何破解极验滑动验证码?成功率 100%!

    注:已对文章中所涉及的敏感内容,如图片/文字/URL 进行脱敏处理. 什么是"极验"? 或许你没听说过极验[1],但你很大可能使用过极验的产品.极验是首家「行为式验证」安全技术服务 ...

  6. Day06,selenium的剩余用法、万能登录破解和爬取京东商品信息,及破解极验滑动验证码...

    一.自动登录抽屉新热榜 from selenium import webdriver import timedriver = webdriver.Chrome(r'D:\BaiduNetdiskDow ...

  7. 【JavaScript 逆向】极验三代无感验证码逆向分析

    相关文章 [JavaScript 逆向]极验三代滑块验证码逆向分析 [JavaScript 逆向]极验四代无感验证码逆向分析 [JavaScript 逆向]极验四代滑块验证码逆向分析 声明 本文章中所 ...

  8. 极验系列文章一:极验三代 极验验证码整体流程分析

    警告与声明: 作为一位js逆向爱好者,写本篇文章在于纯技术分析.无任何不良商业目的.旨在提高大家的网络安全意识,共同维护网络安全环境!请不要做任何有损国家或其他集体或个人的事情, 否者后果自负!本文如 ...

  9. 艺赛旗RPA验证码处理系列(三):破解极验滑动验证码

    目前艺赛旗RPA已经更新到8.0版本,可以让所有用户免费下载试用http://www.i-search.com.cn/index.html?from=line1 (复制链接下载) 一,介绍 一些网站会 ...

最新文章

  1. linux dd 截文件,Linux使用dd命令快速生成大文件(转)
  2. Nginx+Keepalived实现双机热备
  3. 网易云助力云音乐短视频功能快速上线
  4. .Net程序员安卓学习之路5:使用xutils注入View和事件以及图片的显示
  5. 信息学奥赛一本通 1021:打印字符 | OpenJudge NOI 1.2 08
  6. MethodInterceptor拦截器
  7. Android Google Map APIKey申请
  8. 美国航空航天局(NASA)高度集成WebFOCUS和SharePoint
  9. 大明龙权登录服务器信息解析失败,Steam第三方授权登录异常 《绝地求生》国服绑定中招...
  10. 简历模板百度网盘自取
  11. 【自定义WPS插件xlam】
  12. 【渝粤题库】国家开放大学2021春2251团体工作题目
  13. 认识网络通信中的 ACK、NACK 和 REX
  14. Xposed环境安装
  15. python生词本查单词译文_GitHub - To-knowledge/Wudao-dict: 有道词典的命令行版本,支持英汉互查和在线查询。...
  16. Proe Creo 二次开发之模型装配--在指定位置插入模型
  17. Python中的模块2
  18. 构建一个透明的activity
  19. 深入理解计算机系统-之-数值存储(二)--C程序打印变量的每一字节或者位
  20. 基于VLC的本地视频播放器

热门文章

  1. DJI Mobile SDK初步开发
  2. NTP时钟服务器(PTP服务器)无法同步的排查方法
  3. 原生js选择器或者选择元素或者选择方式
  4. 如何将mac桌面上的文件移到文件夹?
  5. redis存取list集合
  6. DataWhale_python训练营task7
  7. JS 中的Math方法向上取整、向下取整、保留整数、绝对值、取最大值、最小值等
  8. python 小说爬虫_小说爬虫python
  9. 解决ubuntu20.04网络图标消失,连不上网问题
  10. tarjan算法笔记