[验证码识别]某盾滑块验证码增强版的识别
2024-3-27 16:38:19 Author: mp.weixin.qq.com(查看原文) 阅读量:16 收藏

作者坛账号:s1lencee

本文章所有内容仅供学习和研究使用,本人不提供具体模型和源码。若有侵权,请联系我立即删除!维护网络安全,人人有责。


前言

最近,某盾新推出了增强版验证码,其中滑块的增强版比较新颖(或许是我见识少,我见过百度类似的,但不是滑块)。

与传统滑块不同的是,该滑块的移动轨迹是条弧线,且还会旋转,并且两个缺口的形状相同,这就排除了传统的cv2模板匹配识别缺口的方式。

目录

  • 滑块移动曲线研究

  • 还原滑块移动曲线

  • 缺口识别的方案

  • 匹配缺口

滑块移动曲线研究

和非增强版滑块不同的是,该滑块接口新返回了一个值attrs,并且每次返回的值都不同

 复制代码 隐藏代码
{
    "attrs": [0.20475486292799452],
    ...
}

而且每次滑块旋转角度和偏移位置都不同,因此有理由怀疑滑块的移动轨迹和该值有关。

我们现在开始分析滑块是怎么移动和旋转的,通过控制台给滑块图片的CSS加上边框显示,就可以明显看出滑块的移动。

结合attrs可以发现当attrs小于0时,是以滑块图片的右上角为中心点进行旋转加向右偏移,反之则以右下角为中心点。

为了验证我们的猜想,我们可以查看它的js文件,以下是我经过反混淆后的代码

 复制代码 隐藏代码
function updateJigsawRotateAndLeft() {
    var E = this['$el']["offsetWidth"]
        , w = this["$slider"]["offsetWidth"]
        , Q = this["$jigsaw"]["offsetWidth"]
        , J = this["restrict"](this['$jigsaw'], w - Q);
    if (this['ratio'] = (E / 0x2 - Q) / E,
        this["attrs"]) {
        var g0 = this['attrs'][0x0]
            , g1 = J * this['ratio'];
        this['$jigsaw']['style']['left'] = g1 + 'px',
            this['$jigsaw']['style']['transform'] = 'rotate(' + g0 * g1 + 'deg)',
            this['$jigsaw']['style']['transformOrigin'] = g0 > 0x0 ? "bottom right" : "top right";
    }
}

可以看到当g0也就是attrs大于0时,将滑块dom的style(也就是css)的transformOrigin设置为bottom right,并且还可以得知滑块旋转角度rotate由滑块偏移距离g1与attrs的值g0相乘得到

查资料得知,transformOrigin: bottom right正是设置中心点为右下角

还原滑块移动曲线

再次观察可以发现,滑块的偏移量和下面滑条的偏移量是不相同的,研究上面的js可以发现,滑块的偏移量经过一些算法得到J,再计算就可以得到滑块的偏移量

在控制台上打上日志点,再和还原的算法结果对比

可以看到,结果一样。

缺口识别的方案

我们的目标是获取每个缺口的位置和旋转的角度,才可以判断哪个是符合条件的缺口,例如我得到一个缺口的角度,可以反向计算出滑块的偏移量,然后和该缺口的位置匹配,那么该缺口就是目标。

1.旋转模板匹配

我刚开始采用了旋转模板匹配,也就是将滑块旋转,然后每次旋转都进行一次模板匹配,返回置信度最高的坐标和角度。

但是由于多个缺口的存在,即使取置信度最高的2个值,也不能保证能匹配成功,有时候甚至不能匹配到缺口

于是我弃用了这个方法

2.目标检测 + 旋转模板匹配

在某大佬的建议下,我使用yolov5先将滑块缺口切割出来,再对切割下来的图片进行旋转模板匹配

由于具有针对性,该识别方案的准确率远远高于第一种,但是缺陷是,识别时间较久,且计算量较大

原因很简单,因为需要目标检测再加上匹配每一个角度和多个缺口图片,所以消耗时间高于第一种方案

3.目标检测 + 滑块曲线经过位置 + 置信度比较

最后我想出了另一种识别方案,既然识别缺口角度比较麻烦,那么能不能通过滑块的移动轨迹去匹配缺口呢?

再多次观察可以发现,滑块不是每次都经过两个缺口,能不能只算出经过的缺口就行了

步骤是这样的:

  • 通过attrs计算滑块移动曲线

  • 使用yolo识别缺口位置

  • 再通过三角函数计算去除空白背景的滑块轨迹(每个坐标点和旋转角度)

  • 算出滑块轨迹和每个缺口的最小距离,再比较每个缺口的最小距离,距离最小的就是目标缺口

  • 如果每个缺口的最小距离只差小于一定阈值,则使用距离每个缺口最小轨迹点的旋转角度去目标匹配得到置信度

  • 置信度最高的缺口就是目标缺口

为了方便,我画了一张图表示怎么算出滑块轨迹点

我总结了以下内容,需要三角函数的知识

  • 首先算出去除空白背景滑块的中心点,再得到α

  • 然后通过βα算出γ

  • 通过γ算出x2y

  • 滑块轨迹点 = (滑块宽度 + x1 + x2, y)

 复制代码 隐藏代码
import cv2

def get_slide_center(image_path):
    """获取滑块中心点坐标, 不包含透明背景"""
    # 读取图片
    image = cv2.imread(image_path, cv2.IMREAD_UNCHANGED)
    # 提取Alpha通道
    alpha_channel = image[:, :, 3]
    # 寻找非零Alpha值的最小边界框
    _, thresh = cv2.threshold(alpha_channel, 1, 255, cv2.THRESH_BINARY)
    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    x, y, w, h = cv2.boundingRect(contours[0])
    # 裁剪图片
    return [int(w / 2 + x), int(h / 2 + y)]

得到所有轨迹点后,绘制到背景图上查看结果

接下来就是计算缺口图片中心点到轨迹线的最小距离,然后比较就行了

如果轨迹线经过了2个缺口的中心点,那么就可以根据轨迹点去旋转滑块图片再去匹配缺口图片,取置信度最高的即可

总结

训练该缺口的目标检测我使用了500张图片的数据集,不过我认为300张就够了,具体怎么训练可以参考我之前的文章。

另外,我不是什么大佬,我只是站在了巨人的肩膀上

最后,如果大家有个更好的方法欢迎大家讨论!

-官方论坛

www.52pojie.cn

👆👆👆

公众号设置“星标”,不会错过新的消息通知
开放注册、精华文章和周边活动等公告


文章来源: https://mp.weixin.qq.com/s?__biz=MjM5Mjc3MDM2Mw==&mid=2651140373&idx=1&sn=83e93cad7c5a97819f3ba2cf98f4ea03&chksm=bd50a1418a2728571c78c36f8f36dbf500fb45939cfaa1e1c9c5e7b22d8fb8556abe3f5ed890&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh