【验证码逆向专栏】某验二代滑块验证码逆向分析
字数 1177 2025-08-11 08:35:55

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

一、验证码概述

某验二代滑块验证码是一种常见的人机验证机制,通过分析用户滑动滑块的行为来区分人类和机器。本文档将详细讲解其逆向分析过程。

二、验证流程分析

1. 请求流程

  1. 主页点击搜索触发验证码
  2. netWebServlet.json请求返回challengegt
  3. get.php请求返回新的challenge(后续操作必须使用此新值)
  4. 获取验证码背景图片和乱序图片地址
  5. ajax.php验证是否通过,返回validate
  6. 再次请求netWebServlet.json获取name字段
  7. 后续搜索请求带上name字段

2. 关键参数

  • challenge: 验证标识,有新旧两个版本
  • gt: 验证标识
  • w: 核心加密参数,由r7z + H7z组成
  • validate: 验证通过标识

三、逆向分析过程

1. 定位加密点

  • 搜索\x77w的16进制编码)定位加密位置
  • w值由两部分组成:r7z + H7z

2. H7z值分析

  • 核心是RSA加密随机字符串
  • 与三代、四代验证码逻辑相似
  • 推荐使用AST还原控制流

3. r7z值分析

由以下代码生成:

q7z = n0B[M9r.R8z(699)](h7B[M9r.C8z(105)](Y7z), V7z[M9r.R8z(818)]())
r7z = p7B[M9r.R8z(260)](q7z)

其中Y7z由五个值组成:

  1. userresponse
  2. passtime
  3. imgload
  4. aa
  5. ep

3.1 userresponse值

  • 由滑动距离和challenge值计算得到
  • 计算方法:
function getUserResponse(L0z, o0z) {
    for (var j0z = o0z.slice(32), c0z = [], X0z = 0; X0z < j0z.length; X0z++){
        var K0z = j0z.charCodeAt(X0z);
        c0z[X0z] = K0z > 57 ? K0z - 87 : K0z - 48;
    }
    j0z = 36 * c0z[0] + c0z[1];
    var k0z = Math.round(L0z) + j0z;
    o0z = o0z.slice(0, 32);
    var n0z, f0z = [[], [], [], [], []], Q0z = {}, N0z = 0;
    X0z = 0;
    for (var i0z = o0z.length; i0z > X0z; X0z++){
        n0z = o0z.charAt(X0z), Q0z[n0z] || (Q0z[n0z] = 1, f0z[N0z].push(n0z), N0z++, N0z = 5 == N0z ? 0 : N0z);
    }
    var y0z, v0z = k0z, B0z = 4, x0z = "", I0z = [1, 2, 5, 10, 50];
    while (v0z > 0) {
        v0z - I0z[B0z] >= 0 ? (y0z = parseInt(Math.random() * f0z[B0z].length, 10), x0z += f0z[B0z][y0z], v0z -= I0z[B0z]) : (f0z.splice(B0z, 1), I0z.splice(B0z, 1), B0z -= 1);
    }
    return x0z;
}

3.2 passtime值

  • 滑动完成所花费的时间
  • 取轨迹最后一个时间值:var passtime = track[track.length - 1][2]

3.3 imgload值

  • 图片加载耗时
  • 可直接写死或使用随机值

3.4 aa值(F7z)

  • 由轨迹数据生成
  • 生成过程分为两步:

第一步生成:

function getF7z(track){
    var o5r = 6;
    for (var N1z, X1z = s6z(track), f1z = [], B1z = [], o1z = [], t1z = 0, j1z = X1z.length; t1z < j1z; t1z++){
        if (o5r * (o5r + 1) % 2 + 8) {
            N1z = u6z(X1z[t1z]), N1z ? B1z.push(N1z) : (f1z.push(O6z(X1z[t1z][0])), B1z.push(O6z(X1z[t1z][1]))), o1z.push(O6z(X1z[t1z][2]));
            o5r = o5r >= 17705 ? o5r / 3 : o5r * 3;
        }
    }
    return f1z.join("") + B1z.join("") + o1z.join("");
}

function s6z(F6z){
    for (var Y6z, g6z, a6z, E6z = [], D6z = 0, P6z = [], J6z = 0, l6z = F6z.length - 1; J6z < l6z; J6z++) {
        Y6z = Math.round(F6z[J6z + 1][0] - F6z[J6z][0]), 
        g6z = Math.round(F6z[J6z + 1][1] - F6z[J6z][1]), 
        a6z = Math.round(F6z[J6z + 1][2] - F6z[J6z][2]), 
        P6z.push([Y6z, g6z, a6z]), 
        0 == Y6z && 0 == g6z && 0 == a6z || (0 == Y6z && 0 == g6z ? D6z += a6z : (E6z.push([Y6z, g6z, a6z + D6z]), D6z = 0));
    }
    return 0 !== D6z && E6z.push([Y6z, g6z, D6z]), E6z;
}

function O6z(r6z){
    var d6z = "0123456789:?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz", 
        m6z = d6z.length, 
        Z6z = "", 
        H6z = Math.abs(r6z), 
        W6z = parseInt(H6z / m6z);
    W6z >= m6z && (W6z = m6z - 1), W6z && (Z6z = d6z.charAt(W6z)), H6z %= m6z;
    var q6z = "";
    return r6z < 0 && (q6z += "!"), q6z + Z6z + d6z.charAt(H6z);
}

function u6z(R6z){
    for (var z6z = [[1, 0], [2, 0], [1, -1], [1, 1], [0, 1], [0, -1], [3, 0], [2, -1], [2, 1]], h6z = 0, C6z = z6z.length; h6z < C6z; h6z++){
        if (R6z[0] == z6z[h6z][0] && R6z[1] == z6z[h6z][1]){
            return "stuvwxyz~"[h6z];
        }
    }
    return 0;
}

第二步处理:

function getF7z2(Q1z, v1z, T1z){
    var i1z, x1z = 0, c1z = Q1z, y1z = v1z[0], k1z = v1z[2], L1z = v1z[4];
    while (1){
        if (i1z = T1z.substr(x1z, 2)){
            x1z += 2;
            var n1z = parseInt(i1z, 16), 
                M1z = String.fromCharCode(n1z), 
                I1z = (y1z * n1z * n1z + k1z * n1z + L1z) % Q1z.length;
            c1z = c1z.substr(0, I1z) + M1z + c1z.substr(I1z);
        } else {
            return c1z;
        }
    }
    return Q1z;
}

3.5 ep值

  • 版本号,可直接写死

3.6 rp值

  • 添加到Y7z中的额外参数
  • 生成方式:md5(gt + challenge.slice(0, 32) + passtime)

4. q7z值生成

  • 使用AES加密
  • 待加密对象:JSON.stringify(Y7z)
  • Key:16位随机字符串(需与H7z使用的随机字符串一致)

5. r7z值生成

  • 对q7z进行处理
  • 处理方法与三代相同:
function $_GJF(e) {
    var t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()";
    return e < 0 || e >= t.length ? "." : t.charAt(e);
}

function $_HBO(e, t) {
    return e >> t & 1;
}

function $_HCX(e, o) {
    var i = this;
    o || (o = i);
    for (var t = function(e, t) {
        for (var n = 0, r = 24 - 1; 0 <= r; r -= 1) 
            1 === $_HBO(t, r) && (n = (n << 1) + $_HBO(e, r));
        return n;
    }, n = "", r = "", s = e.length, a = 0; a < s; a += 3) {
        var c;
        if (a + 2 < s) 
            c = (e[a] << 16) + (e[a + 1] << 8) + e[a + 2], 
            n += $_GJF(t(c, 7274496)) + $_GJF(t(c, 9483264)) + $_GJF(t(c, 19220)) + $_GJF(t(c, 235));
        else {
            var _ = s % 3;
            2 == _ ? 
                (c = (e[a] << 16) + (e[a + 1] << 8), 
                n += $_GJF(t(c, 7274496)) + $_GJF(t(c, 9483264)) + $_GJF(t(c, 19220)), 
                r = "=") : 
                1 == _ && 
                (c = e[a] << 16, 
                n += $_GJF(t(c, 7274496)) + $_GJF(t(c, 9483264)), 
                r = "==");
        }
    }
    return { res: n, end: r };
}

四、总结

  1. 核心参数wr7z + H7z组成
  2. H7z是RSA加密的随机字符串
  3. r7z由轨迹数据经过多层处理生成
  4. 注意challenge有新旧两个版本,必须使用get.php返回的新版本
  5. 轨迹处理是验证的关键,需要准确模拟人类滑动行为

五、验证方法

  1. 构造完整的w参数
  2. 提交到ajax.php验证
  3. 获取validate后完成后续请求

通过以上步骤,可以成功逆向分析并模拟某验二代滑块验证码的验证过程。

某验二代滑块验证码逆向分析教学文档 一、验证码概述 某验二代滑块验证码是一种常见的人机验证机制,通过分析用户滑动滑块的行为来区分人类和机器。本文档将详细讲解其逆向分析过程。 二、验证流程分析 1. 请求流程 主页点击搜索触发验证码 netWebServlet.json 请求返回 challenge 和 gt get.php 请求返回新的 challenge (后续操作必须使用此新值) 获取验证码背景图片和乱序图片地址 ajax.php 验证是否通过,返回 validate 再次请求 netWebServlet.json 获取 name 字段 后续搜索请求带上 name 字段 2. 关键参数 challenge : 验证标识,有新旧两个版本 gt : 验证标识 w : 核心加密参数,由 r7z + H7z 组成 validate : 验证通过标识 三、逆向分析过程 1. 定位加密点 搜索 \x77 ( w 的16进制编码)定位加密位置 w 值由两部分组成: r7z + H7z 2. H7z值分析 核心是RSA加密随机字符串 与三代、四代验证码逻辑相似 推荐使用AST还原控制流 3. r7z值分析 由以下代码生成: 其中 Y7z 由五个值组成: userresponse passtime imgload aa ep 3.1 userresponse值 由滑动距离和 challenge 值计算得到 计算方法: 3.2 passtime值 滑动完成所花费的时间 取轨迹最后一个时间值: var passtime = track[track.length - 1][2] 3.3 imgload值 图片加载耗时 可直接写死或使用随机值 3.4 aa值(F7z) 由轨迹数据生成 生成过程分为两步: 第一步生成: 第二步处理: 3.5 ep值 版本号,可直接写死 3.6 rp值 添加到Y7z中的额外参数 生成方式: md5(gt + challenge.slice(0, 32) + passtime) 4. q7z值生成 使用AES加密 待加密对象: JSON.stringify(Y7z) Key:16位随机字符串(需与H7z使用的随机字符串一致) 5. r7z值生成 对q7z进行处理 处理方法与三代相同: 四、总结 核心参数 w 由 r7z + H7z 组成 H7z 是RSA加密的随机字符串 r7z 由轨迹数据经过多层处理生成 注意 challenge 有新旧两个版本,必须使用 get.php 返回的新版本 轨迹处理是验证的关键,需要准确模拟人类滑动行为 五、验证方法 构造完整的 w 参数 提交到 ajax.php 验证 获取 validate 后完成后续请求 通过以上步骤,可以成功逆向分析并模拟某验二代滑块验证码的验证过程。