极验滑块验证码破解与研究(二):缺口图片还原

声明

原创文章,请勿转载!

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

本文关联文章超链接:

  1. 极验滑块验证码破解与研究(一):AST还原混淆JS
  2. 极验滑块验证码破解与研究(二):缺口图片还原
  3. 极验滑块验证码破解与研究(三):滑块缺口识别
  4. 极验滑块验证码破解与研究(四):滑块轨迹构造
  5. 极验滑块验证码破解与研究(五):请求分析及加密参数破解

一、缺口图片还原js分析

1. 为什么需要还原

网页打开的图片都是裁剪后重新拼接的乱序图片,所以需要将乱序图片还原
在这里插入图片描述

2. 本篇文章需要用到的小工具

2.1. reres插件

这个chrome插件超级好用哦,网页加载资源文件时,可以将其替换成本地的资源文件,js代码调试时非常方便。

3. 找到图片还原js入口函数

3.1. 通过观察html标签,发现图片是由canvas标签绘制的

在这里插入图片描述

3.2. 打开 极验滑块官方测试网页 分析js

因为图片是由canvas标签绘制的,首先想到在浏览器的开发者工具中,监听Canvas事件,当浏览器使用canvas绘制图片时,触发Canvas事件。刷新时,有没有发现断点处的上下文很熟悉的感觉
在这里插入图片描述

3.3. 背景图还原js源码分析

下面是小编从源码(slide.7.8.4.js)中抠出来的背景图还原函数:

function $e(e, t) {
    var ylK = AaWgt.EeS()[28][34];
    for (; ylK !== AaWgt.EeS()[28][32]; ) {
        switch (ylK) {
        case AaWgt.EeS()[4][34]:
            e = e[XxZM(150)];
            t = t[XxZM(150)];
            var r = e[YcZy(509)];
            var n = e[YcZy(549)];
            var i = h[XxZM(124)](YcZy(106));
            i[YcZy(509)] = r;
            i[YcZy(549)] = n;
            var o = i[YcZy(167)](YcZy(187));
            ylK = AaWgt.EeS()[8][33];
            break;
        case AaWgt.EeS()[0][33]:
            o[XxZM(684)](e, 0, 0);
            var a = t[YcZy(167)](XxZM(187));
            t[YcZy(549)] = n;
            t[XxZM(509)] = Ne;
            var s = n / 2;
            var u = 10;
            for (var c = 0; c < 52; c = c + 1) {
                var _ = Ge[c] % 26 * 12 + 1;
                var f = Ge[c] > 25 ? s : 0;
                var l = o[XxZM(697)](_, f, u, s);
                a[XxZM(621)](l, c % 26 * 10, c > 25 ? s : 0);
            }
            ylK = AaWgt.EeS()[0][32];
            break;
        }
    }
}

为了下面分析方便,将混淆的js还原下,配置chrome插件reres,将网页加载的js文件替换成对应的反混淆后的js文件,还原方式请看上一篇文章 极验滑块验证码破解与研究(一):AST还原混淆JS ,配置如下图:
在这里插入图片描述

下面是还原后的js代码,自己加上了一些注释,有错误的地方还望指出:

function $e(e, t) {
    // e为待还原的背景图对象
    e = e["lKRC"];
    // t为canvas图形容器对象
    t = t["lKRC"];
    // 将原图的宽度赋值给r,312
    var r = e["width"];
    // 将原图的高度赋值给n,160
    var n = e["height"];
    // h为document对象,i为canvas图形容器对象
    var i = h["createElement"]("canvas");
    // 定义canvas图形容器i的宽度为312
    i["width"] = r;
    // 定义canvas图形容器i的高度为160
    i["height"] = n;
    // o为图形容器i的二维绘图环境
    var o = i["getContext"]("2d");
    // 画布o上定位图像e
    o["drawImage"](e, 0, 0);
    // a为图形容器t的二维绘图环境
    var a = t["getContext"]("2d");
    // 定义canvas图形容器t的高度为160
    t["height"] = n;
    // 定义canvas图形容器t的宽度为260
    t["width"] = Ne;
    // s = 80
    var s = n / 2;
    var u = 10;
    // Ge为数组对象,定值,其中为原图的还原顺序,共52个值,为0-51的整数。因此原图被切割成52块拼图,每块拼图大小为12*80。
    // Ge = [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]
    for (var c = 0; c < 52; c = c + 1) {
        // 每个小块在原图宽度上的相对位置, 注意每个小块的间隔是12
        var _ = Ge[c] % 26 * 12 + 1;
        // 每个小块在原图高度上的相对位置
        var f = Ge[c] > 25 ? s : 0;
        // 从原图中裁剪出对应的小块, 注意裁剪图片的宽度是10
        var l = o["getImageData"](_, f, u, s);
        // 将裁剪的小块l, 画入二维绘图环境a
        a["putImageData"](l, c % 26 * 10, c > 25 ? s : 0);
    }
    // 注意原图为312*160的图片分割成52个大小为12*80的小块,最后由52个10*80的小块拼接成260*160完整图  
}

4. 背景图还原js改写成python语法

这个js逻辑比较简单,所以改写成python代码啦

# -*- coding: utf-8 -*-
import io
from pathlib import Path

from PIL import Image


def parse_bg_captcha(img, im_show=False, save_path=None):
    """
    滑块乱序背景图还原
    :param img: 图片路径str/图片路径Path对象/图片二进制
        eg: 'assets/bg.webp'
            Path('assets/bg.webp')
    :param im_show: 是否显示还原结果, <type 'bool'>; default: False
    :param save_path: 保存路径, <type 'str'>/<type 'Path'>; default: None
    :return: 还原后背景图 RGB图片格式
    """
    if isinstance(img, (str, Path)):
        _img = Image.open(img)
    elif isinstance(img, bytes):
        _img = Image.open(io.BytesIO(img))
    else:
        raise ValueError(f'输入图片类型错误, 必须是<type str>/<type Path>/<type bytes>: {type(img)}')
    # 图片还原顺序, 定值
    _Ge = [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]
    w_sep, h_sep = 10, 80

    # 还原后的背景图
    new_img = Image.new('RGB', (260, 160))

    for idx in range(len(_Ge)):
        x = _Ge[idx] % 26 * 12 + 1
        y = h_sep if _Ge[idx] > 25 else 0
        # 从背景图中裁剪出对应位置的小块
        img_cut = _img.crop((x, y, x + w_sep, y + h_sep))
        # 将小块拼接到新图中
        new_x = idx % 26 * 10
        new_y = h_sep if idx > 25 else 0
        new_img.paste(img_cut, (new_x, new_y))

    if im_show:
        new_img.show()
    if save_path is not None:
        save_path = Path(save_path).resolve().__str__()
        new_img.save(save_path)
    return new_img


if __name__ == '__main__':
    parse_bg_captcha("bg.webp", im_show=True, save_path='bg.jpg')

二、结语

友情链接:极验滑块验证码破解与研究(三):滑块缺口识别

本期文章结束啦,如果对您有帮助,记得收藏加关注哦,后期文章会持续更新 ~~~

在这里插入图片描述

  • 30
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值