破解极验三代滑动验证,成功率百分之百(二):分析图片得到滑动距离

声明

原创文章,请勿转载!

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

环节概述

  1. 使用任意请求转发工具,将页面原本的代码文件的请求转发到本地文件上,也就是我们上一节内容中通过反混淆得到的可阅读代码文件
  2. 分析请求和代码,找到合适的验证码相关的图片
  3. 使用 opencv 分析图片,计算滑动距离

环境准备

  1. 准备 python 环境

    我们这次需要准备 python 的环境。可以通过百度搜索下如何安装 python,然后再安装下下面几个库:pip install numpy requests opencv-python numpy ,这些库是用来帮助我们做一些图像处理的操作。

    安装 python 依赖的方式推荐使用 pipenv,这个工具可以独立每一个开发环境,而不是把依赖通通安装到全局,来避免全局被污染。

  2. 准备请求转发工具。

    能做请求转发的软件有很多,比如抓包软件:whistle、fiddler、charles,或者浏览器的插件:modheader、reres 等。

    挑一个喜欢的即可。

请求转发

使用准备好的转发工具,把链接 static.geetest.com/static/js/slide.7.8.8.js 转发到本地的文件地址即可(例如 file:///xxxx),具体链接的版本号可以根据实际情况做下修改,或者直接通过通配符略过版本号。

分析请求和代码

  1. 找到图片文件链接

    在官网的在线测试页面中尝试触发滑动验证可以发现,页面会发起一个请求 https://api.geetest.com/get.php,里面的返回结果是这样的。

    getphp

    对照浏览器发起的图片请求我们发现,验证码图片涉及到的是图中箭头所指的四个字段。其中:

    • static_servers 是图片地址的可选域名,实际上采用是内部的第一个值
    • bg 是验证码的背景图,并且内部含有灰色空缺滑块
    • fullbg 也是验证码的背景图,但是内部不含有灰色空缺滑块
    • slice 是滑块图
  2. 还原验证码背景图

    观察验证码背景图,我们可以发现它其实是原本的的图片乱序打乱后的结果。

    bg

    所以我们需要先还原这张图。观察页面,这张图是通过 canvas 画出来的:

    canvas​

    所以我们打开 devtolls,先在 canvas 事件上打个断点看看。

    debug

    一眼可得,这个函数内的很多变量就是刚才我们看到的图片的链接,看来就是这里了。我们简单分析下这里的代码:

      function $_BEr(t, e) {
          t = t.$_CGQ
          e = e.$_CGQ
          // 312
          var n = t.width
          // 160
          var r = t.height
          // h 就是 document,i 是创建的 canvas 对象
          var i = h.createElement('canvas')
          // 设置 canvas 宽高
          i.width = n
          i.height = r
          // 新创建的 i 和原本的 e 是两个 canvas 对象,目的是对图像做一些操作
          // 一个用来把图片裁剪出来,一个用来把裁剪出来的图片拼接起来
          var o = i.getContext('2d')
          o.drawImage(t, 0, 0)
          var s = e.getContext('2d')
          e.height = r // 160
          e.width = 260
          var a = r / 2 // 80
    
          for (var _ = 0; _ < 52; _ += 1) {
            // Ut 是一个数组,里面包含 52 个值
            // 也就是说图片被切分为了 52 块,这 52 块会按照下面的方式去还原
            // 也就是说原本 312x160 的图被切分为 52块 10x80,最后一共拼成一个 260x160 的图
            // 宽度的相对位置
            var c = (Ut[_] % 26) * 12 + 1
            // 高度的相对位置
            var u = 25 < Ut[_] ? a : 0
            // 把对应位置裁剪下来
            var l = o.getImageData(c, u, 10, a)
            // 把裁剪下来的部分画到另一个 canvas 内
            s.putImageData(l, (_ % 26) * 10, 25 < _ ? a : 0)
          }
        }
    

    为了方便逻辑处理,以及和后面使用 opencv 的逻辑对齐,这里选择使用 python 来处理图像。那么刚才还原图片的逻辑可以简单改写为:

    from PIL import Image
    import requests
    
    # 刚才的数组扣过来
    IMG_SHUFFLE_ORDER = [
        39, 38, 48, 49, 41, 40, 46, 47, 35, 34, 50, 51, 33, 32, 28, 29, 27, 26, 36, 37, 31, 30, 44, 45, 43, 42, 12, 13, 23,
        22, 14, 15, 21, 20, 8, 9, 25, 24, 6, 7, 3, 2, 0, 1, 11, 10, 4, 5, 19, 18, 16, 17,
    ]
    # 图片会被切分为 10x80 的小图
    IMG_SHUFFLE_X_STEP = 10
    IMG_SHUFFLE_Y_STEP = 80
    
    # 最后图片的宽高
    IMG_WIDTH = 260
    IMG_HEIGHT = 160
    
    # 根据链接下载图片
    def downloadImg(url: str):
        r = requests.get(url)
        return Image.open(io.BytesIO(r.content))
    
    def spliceImg(img: Image.Image):
        # 创建一个图对象片
        newImg = Image.new('RGB', (IMG_WIDTH, IMG_HEIGHT))
        # 按照顺序循环 52 次
        for i in range(len(IMG_SHUFFLE_ORDER)):
            x = IMG_SHUFFLE_ORDER[i] % 26 * 12 + 1
            y = IMG_SHUFFLE_Y_STEP if IMG_SHUFFLE_ORDER[i] > 25 else 0
            # 根据刚才 JS 的逻辑,把图片裁剪出一小块儿
            cut = img.crop((x, y, x + IMG_SHUFFLE_X_STEP, y + IMG_SHUFFLE_Y_STEP))
            # 根据刚才的逻辑,确定新图片的位置
            newX = i % 26 * 10
            newY = IMG_SHUFFLE_Y_STEP if i > 25 else 0
            # 把新图片拼接过去
            newImg.paste(cut, (newX, newY))
        return newImg
    
    if __name__ == '__main__':
      img = sliceImg(downloadImg('img url'))
      img.show()
    

    效果:

    show

分析滑动距离

我们通过前面的操作可以得到两张图片,一张是被还原的背景图,一张是滑块本身的图片(slice)。现在我们要通过一些操作,来找到缺口位置。

整个匹配逻辑是这样的:

  1. 将图片置灰,减少干扰

    gray

  2. 对图片做边缘检测,进一步降低干扰

    canny

  3. 做模板匹配,找到缺口位置

    match

  4. 得出滑动距离

    import io
    from PIL import Image
    import cv2
    import numpy as np
    
    # 将 Image 转换为 Mat,通过 flag 可以控制颜色
    def pilImgToCv2(img: Image.Image, flag=cv2.COLOR_RGB2BGR):
        return cv2.cvtColor(np.asarray(img), flag)
    
    # 弹窗查看图片
    def showImg(bg: cv2.Mat, name='test', delay=0):
        cv2.imshow(name, bg)
        cv2.waitKey(delay)
        cv2.destroyAllWindows()
    
    
    def getDistance(img: Image.Image, slice: Image.Image):
        # 通过 pilImgToCv2 将图片置灰
        # 背景图和滑块图都需要做相同处理
        grayImg = pilImgToCv2(img, cv2.COLOR_BGR2GRAY)
        # showImg(grayImg) # 可以通过它来看处理后的图片效果
        graySlice = pilImgToCv2(slice, cv2.COLOR_BGR2GRAY)
        # 做边缘检测进一步降低干扰,阈值可以自行调整
        grayImg = cv2.Canny(grayImg, 255, 255)
        # showImg(grayImg) # 可以通过它来看处理后的图片效果
        graySlice = cv2.Canny(graySlice, 255, 255)
        # 通过模板匹配两张图片,找出缺口的位置
        result = cv2.matchTemplate(grayImg, graySlice, cv2.TM_CCOEFF_NORMED)
        maxLoc = cv2.minMaxLoc(result)[3]
        # 匹配出来的滑动距离
        distance = maxLoc[0]
        # 下面的逻辑是在图片画出一个矩形框来标记匹配到的位置,可以直观的看到匹配结果,去掉也可以的
        sliceHeight, sliceWidth = graySlice.shape[:2]
        # 左上角
        x, y = maxLoc
        # 右下角
        x2, y2 = x + sliceWidth, y + sliceHeight
        resultBg = pilImgToCv2(img, cv2.COLOR_RGB2BGR)
        cv2.rectangle(resultBg, (x, y), (x2, y2), (0, 0, 255), 2)
        # showImg(resultBg) # 可以通过它来看处理后的图片效果
        return (distance, resultBg)
    

总结

这一节内容里,我们简单分析了下网络请求和代码逻辑,搭建了 python 环境并通过 opencv 处理图片得到了所需的滑动距离。

下一节我们将继续分析代码和请求的逻辑,来自己构造请求通过验证


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

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

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
3.0滑动拼图验证是一种常用的人机验证方式,可以有效防止机器恶意攻击,保障网站安全。在Java中,可以通过调用的API来实现滑动验证功能。下面是一个简单的使用示例: 1. 在官网申请账号,并创建一个验证项目,获得验证ID和密钥。 2. 下载的Java SDK,解压后将其中的geetest-lib.jar文件添加到项目的classpath中。 3. 在Java代码中调用API实现验证功能,示例代码如下: ```java import com.geetest.sdk.GTConfig; import com.geetest.sdk.GeetestLib; public class GeetestVerify { private static final String GEETEST_ID = "your_geetest_id"; // 验证ID private static final String GEETEST_KEY = "your_geetest_key"; // 验证密钥 public static boolean verify(String challenge, String validate, String seccode) { GeetestLib gtSdk = new GeetestLib(GEETEST_ID, GEETEST_KEY); GTConfig config = new GTConfig(); config.setCaptchaId(GEETEST_ID); config.setPrivateKey(GEETEST_KEY); gtSdk.setConfig(config); // 自定义参数,可选择添加 // Map<String, String> paramMap = new HashMap<>(); // paramMap.put("user_id", "your_user_id"); // paramMap.put("client_type", "web"); // paramMap.put("ip_address", "127.0.0.1"); // 调用验证接口 int result = gtSdk.enhencedValidateRequest(challenge, validate, seccode, null); // 验证结果,0表示成功,1表示失败 return result == 0; } } ``` 4. 在前端页面中嵌入验证组件,具体实现方式可参考官网提供的相关文档和示例代码。在用户完成验证后,将验证结果传递给后台Java程序进行验证,通过调用上述示例代码实现验证功能即可。 总的来说,Java实现滑动验证相对较为简单,只需要调用提供的Java SDK即可。需要注意的是,官网提供的Java SDK版本可能会更新,需要及时更新SDK文件以保证验证功能的正常运作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值