【验证码逆向专栏】某验三代滑块验证码逆向分析
字数 1688 2025-08-11 17:40:05

某验三代滑块验证码逆向分析教学文档

一、验证码概述

某验三代滑块验证码是一种常见的反爬机制,主要包含以下特点:

  • 采用RSA、AES、MD5等多种加密算法
  • 包含乱序背景图还原机制
  • 使用复杂的w参数加密验证

二、验证码流程分析

1. 初始请求阶段

register-slide接口

  • 请求参数:t=时间戳
  • 响应关键字段:
    • gt:固定值,不同网页对应不同的gt值
    • challenge:每次刷新页面都会变化的值

gettype.php接口

  • 请求参数:
    • gt:register-slide返回的gt值
    • callbackgeetest_ + 时间戳
  • 响应返回js文件及版本号

2. 验证阶段

第一个get.php接口

  • 请求参数:
    • gt:register-slide返回的gt值
    • challenge:register-slide返回的challenge值
    • w:首次可为空
    • callbackgeetest_ + 时间戳

ajax.php接口

  • 请求参数同上
  • 响应返回验证码模式(slide或click)

第二个get.php接口

  • 响应关键内容:
    • bg:乱序带缺口背景图
    • fullbg:乱序完整背景图
    • slice:滑块图片
    • c:关键参数,与aa参数相关
    • s:关键参数,与aa参数相关

第二个ajax.php接口

  • 请求参数:
    • gt:register-slide返回的gt值
    • challenge:register-slide返回的challenge值+两位字符串
    • w:关键加密参数(需逆向)
    • callbackgeetest_ + 时间戳

三、w参数逆向分析

w参数由h和u相加组成:w = h + u

1. u参数生成

u参数生成流程:

  1. 生成16位随机字符串:
    function random() {
        var random_str = "";
        for (var index = 0; index < 4; index++) {
            random_str += (65536 * (1 + Math["random"]()) | 0)["toString"](16)["substring"](1);
        }
        return random_str;
    }
    
  2. 使用RSA加密:
    • 公钥值:00C1E3934D1614465B33053E7F48EE4EC87B14B95EF88947713D25EECBFF7E74C7977D02DC1D9451F79DD5D1C10C29ACB6A9B4D6FB7D0A0279B6719E1772565F09AF627715919221AEF91899CAE08C0D686D748B20A3603BE2318CA6BC2B59706592A9219D0BF05C9F65023A21D2330807252AE0066D59CEEFA5F2748EA80BAB81
    • 公钥模数:10001

2. h参数生成

h参数由l参数经过加密处理得到:h = m[$_CAIAt(782)](l)

l参数生成:

l = V["encrypt"](gt["stringify"](o), r["$_CCEc"]())

其中:

  • r["$_CCEc"]():16位随机字符串(同u参数生成)
  • gt["stringify"](o):JSON格式数据,包含以下关键字段:

o参数结构分析

var o = {
    "lang": "zh-cn",
    "userresponse": H(t, i["challenge"]), // 滑动距离+challenge
    "passtime": n, // 滑块滑动时间
    "imgload": r["$_CAIAt(750)"], // 图片加载时间
    "aa": e, // 轨迹加密结果
    "ep": r["$_CAHJd(714)]() // 性能相关
};

userresponse

function H(t, e) {
    return t + e
}

passtime
滑动结束时间 - 开始时间

aa参数
由三部分加密得到:

  1. 轨迹加密结果
  2. c值(从第二个get.php响应中获取)
  3. s值(从第二个get.php响应中获取)

轨迹加密算法:

function getAA(t, e, n) {
    if (!e || !n) return t;
    var r, i = 0, o = t, s = e[0], a = e[2], _ = e[4];
    while (r = n.substr(i, 2)) {
        i += 2;
        var c = parseInt(r, 16),
            u = String.fromCharCode(c),
            l = (s * c * c + a * c + _) % t.length;
        o = o.substr(0, l) + u + o.substr(l);
    }
    return o;
}

rp参数

o["rp"] = X(i["gt"] + i["challenge"].slice(0, 32) + o["passtime"]);

其中X为MD5加密函数

ep参数
包含每天变化的键值对,从gct.xxxxxxxx.js文件中获取

3. l参数加密

使用AES加密:

  • 密钥:16位随机字符串
  • 初始向量iv:"0000000000000000"
  • 加密模式:CBC
  • 填充方式:Pkcs7

JavaScript实现:

function aesV(o_text, random_str) {
    var key = CryptoJS.enc.Utf8.parse(random_str);
    var iv = CryptoJS.enc.Utf8.parse("0000000000000000");
    var srcs = CryptoJS.enc.Utf8.parse(o_text);
    var encrypted = CryptoJS.AES.encrypt(srcs, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    for (var r = encrypted, o = r.ciphertext.words, i = r.ciphertext.sigBytes, s = [], a = 0; a < i; a++) {
        var c = o[a >>> 2] >>> 24 - a % 4 * 8 & 255;
        s.push(c);
    }
    return s;
}

4. h参数加密

将l参数加密后得到:

function encryptH(l) {
    var e = [];
    for (var t = 0; t < l.length; t++) {
        var n = l[t].toString(16);
        1 == n.length && (n = "0" + n), e.push(n);
    }
    return e.join("");
}

四、底图还原算法

乱序背景图还原顺序:

[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]

Python还原实现:

def restore_picture():
    img_list = ["./乱序缺口背景图.png", "./乱序背景图.png"]
    for index, img in enumerate(img_list):
        image = Image.open(img)
        s = Image.new("RGBA", (260, 160))
        ut = [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]
        height_half = 80
        for inx in range(52):
            c = ut[inx] % 26 * 12 + 1
            u = height_half if ut[inx] > 25 else 0
            l_ = image.crop(box=(c, u, c + 10, u + 80))
            s.paste(l_, box=(inx % 26 * 10, 80 if inx > 25 else 0))
        if index == 0:
            s.save("./缺口背景图片.png")
        else:
            s.save("./背景图片.png")

五、常见错误

  1. challenge不正确:
{"status": "error", "error": "illegal challenge", "user_error": "网络不给力", "error_code": "error_23"}
  1. w参数不正确:
{"status": "error", "error": "param decrypt error", "user_error": "网络不给力", "error_code": "error_03"}
  1. 无轨迹数据:
{"status": "error", "error": "not proof", "user_error": "网络不给力", "error_code": "error_21"}
  1. 轨迹、缺口距离或参数问题:
{"success": 0, "message": "fail"}
{"success": 0, "message": "forbidden"}

六、总结

  1. 验证码破解成功率约95%

  2. 关键点:

    • w参数的正确生成
    • 轨迹算法的准确实现
    • 背景图的正确还原
    • 各加密算法的准确实现
  3. 注意事项:

    • 部分参数每天会变化(如mocq)
    • 注意challenge值的变化(第二个ajax.php比注册请求时多两位)
    • 各加密环节的顺序和参数传递要准确
某验三代滑块验证码逆向分析教学文档 一、验证码概述 某验三代滑块验证码是一种常见的反爬机制,主要包含以下特点: 采用RSA、AES、MD5等多种加密算法 包含乱序背景图还原机制 使用复杂的w参数加密验证 二、验证码流程分析 1. 初始请求阶段 register-slide接口 : 请求参数: t=时间戳 响应关键字段: gt :固定值,不同网页对应不同的gt值 challenge :每次刷新页面都会变化的值 gettype.php接口 : 请求参数: gt :register-slide返回的gt值 callback : geetest_ + 时间戳 响应返回js文件及版本号 2. 验证阶段 第一个get.php接口 : 请求参数: gt :register-slide返回的gt值 challenge :register-slide返回的challenge值 w :首次可为空 callback : geetest_ + 时间戳 ajax.php接口 : 请求参数同上 响应返回验证码模式(slide或click) 第二个get.php接口 : 响应关键内容: bg :乱序带缺口背景图 fullbg :乱序完整背景图 slice :滑块图片 c :关键参数,与aa参数相关 s :关键参数,与aa参数相关 第二个ajax.php接口 : 请求参数: gt :register-slide返回的gt值 challenge :register-slide返回的challenge值+两位字符串 w :关键加密参数(需逆向) callback : geetest_ + 时间戳 三、w参数逆向分析 w参数由h和u相加组成: w = h + u 1. u参数生成 u参数生成流程: 生成16位随机字符串: 使用RSA加密: 公钥值: 00C1E3934D1614465B33053E7F48EE4EC87B14B95EF88947713D25EECBFF7E74C7977D02DC1D9451F79DD5D1C10C29ACB6A9B4D6FB7D0A0279B6719E1772565F09AF627715919221AEF91899CAE08C0D686D748B20A3603BE2318CA6BC2B59706592A9219D0BF05C9F65023A21D2330807252AE0066D59CEEFA5F2748EA80BAB81 公钥模数: 10001 2. h参数生成 h参数由l参数经过加密处理得到: h = m[$_CAIAt(782)](l) l参数生成: 其中: r["$_CCEc"]() :16位随机字符串(同u参数生成) gt["stringify"](o) :JSON格式数据,包含以下关键字段: o参数结构分析 userresponse : passtime : 滑动结束时间 - 开始时间 aa参数 : 由三部分加密得到: 轨迹加密结果 c值(从第二个get.php响应中获取) s值(从第二个get.php响应中获取) 轨迹加密算法: rp参数 : 其中X为MD5加密函数 ep参数 : 包含每天变化的键值对,从gct.xxxxxxxx.js文件中获取 3. l参数加密 使用AES加密: 密钥:16位随机字符串 初始向量iv: "0000000000000000" 加密模式:CBC 填充方式:Pkcs7 JavaScript实现: 4. h参数加密 将l参数加密后得到: 四、底图还原算法 乱序背景图还原顺序: Python还原实现: 五、常见错误 challenge不正确: w参数不正确: 无轨迹数据: 轨迹、缺口距离或参数问题: 六、总结 验证码破解成功率约95% 关键点: w参数的正确生成 轨迹算法的准确实现 背景图的正确还原 各加密算法的准确实现 注意事项: 部分参数每天会变化(如mocq) 注意challenge值的变化(第二个ajax.php比注册请求时多两位) 各加密环节的顺序和参数传递要准确