首页 > 其他分享 >验证码识别与处理细节总结

验证码识别与处理细节总结

时间:2025-01-10 21:10:47浏览次数:1  
标签:function return pow 验证码 细节 gct var 识别 buf

验证码的破解虽然整体难度不大,但某些细节处理不当可能会导致各种错误。在本文中,我们总结了一些常见问题及其解决方法,包括验证码识别方案和轨迹处理等。

关于 w 值
在某些验证码系统(如第三代系统)中,有几个请求接口会包含 w 值。需要特别注意的是,除了最后一个校验接口 ajax.php 外,其他接口的 w 值可以为空,但在某些模式下,如无感验证模式,在请求 get.php 接口获取 c 和 s 值时,也会校验 w 值。

常见错误:

json

{'status': 'error', 'error': 'param decrypt error', 'user_error': '网络不给力', 'error_code': 'error_03'}
关于时间间隔
验证码系统通常要求请求之间有一定的时间间隔。如果请求太快,验证会失败。例如,在第三代系统中,如果生成 w 值后没有随机停留 2 秒左右,验证可能会失败。

常见错误:

json

{'status': 'success', 'data': {'result': 'fail', 'msg': ['duration short']}}
关于 challenge
在第三代系统中,challenge 值会参与多次请求。第一次获取到一个 challenge,后续的 get.php 请求返回的数据中会包含一个新的 challenge,新 challenge 比第一次多了两位数。所有后续请求都必须使用新的 challenge。

常见错误:

json

{'success': 0, 'message': 'fail'}
关于 c 和 s
在第三代系统中,c 和 s 值会参与 w 的计算。点选和滑块验证码类型中,第一次 get.php 请求返回的 c 和 s 值,第二次 get.php 请求返回的 s 值会变化。生成 w 时需要使用第二次返回的 s 值。

常见错误:

json

{'success': 0, 'message': 'forbidden'}
关于两次 get.php 和 ajax.php 请求
在第三代系统中,点选和滑块验证码会有两次以 get.php 和 ajax.php 结尾的请求。第一次 get.php 返回主题、域名、提示文字等信息,第一次 ajax.php 返回验证码类型。这两次请求返回的数据虽然对我们没太大用处,但仍需发起请求,否则后续请求将失败。

关于智能组合验证
智能组合验证可以处理多种验证码类型。四代系统更为简洁,通过 load 接口的 captcha_type 字段直接告诉你验证码类型,如滑块、点选(及其子类型)、五子棋或九宫格等。

关于 w 值的算法
w 值生成算法中涉及一些细节,包括 passtime、pow_sign 和 pow_msg。

passtime
passtime 值在生成 w 时参与计算。对于滑块验证码,passtime 是滑动花费的时间,直接取轨迹的最后一个时间值。其他情况下,该值可设为一个随机值。

pow_sign 和 pow_msg
这两个参数是四代系统独有的。pow_msg 的格式如下:

text

1|0|md5|datetime|captcha_id|lot_number||随机字符串
pow_sign 是 pow_msg 经 MD5 加密后的值。需要注意,pow_sign 的生成必须符合特定条件,否则会导致验证失败。下面是一个处理示例:

javascript

var CryptoJS = require("crypto-js");

function getRandomString(){
    function e(){
        return (65536 * (1 + Math.random()) | 0).toString(16).substring(1);
    }
    return e() + e() + e() + e();
}

function get_pow(pow_detail, captcha_id, lot_number) {
    var n = pow_detail.hashfunc;
    var i = pow_detail.version;
    var r = pow_detail.bits;
    var s = pow_detail.datetime;
    var o = "";

var a = r % 4;
    var u = parseInt(r / 4, 10);
    var c = function g(e, t) {
        return new Array(t + 1).join(e);
    }("0", u);
    var _ = i + "|" + r + "|" + n + "|" + s + "|" + captcha_id + "|" + lot_number + "|" + o + "|";

while (1) {
        var h = getRandomString()
          , l = _ + h
          , p = void 0;
        switch (n) {
            case "md5":
            p = CryptoJS.MD5(l).toString();
            break;
        case "sha1":
            p = CryptoJS.SHA1(l).toString();
            break;
        case "sha256":
            p = CryptoJS.SHA256(l).toString();
        }
        if (0 == a) {
            if (0 === p.indexOf(c))
                return {
                    "pow_msg": _ + h,
                    "pow_sign": p
                };
        } else if (0 === p.indexOf(c)) {
            var f = void 0
              , d = p[u];
            switch (a) {
            case 1:
                f = 7;
                break;
            case 2:
                f = 3;
                break;
            case 3:
                f = 1;
            }
            if (d <= f)
                return {
                    "pow_msg": _ + h,
                    "pow_sign": p
                };
        }
    }
}
随机变化的字符串
在验证码生成过程中,通常会有一个 16 位随机字符串参与 w 的加密计算。这个字符串一般会用到两次,且两次必须相同。

常见错误:

json

{'status': 'error', 'error': 'param decrypt error', 'user_error': '网络不给力', 'error_code': 'error_03'}
随机变化的键值对
在三代和四代系统中,w 值的生成过程中会有一个随机键值对。以三代滑块为例,以下是一个动态获取该键值对的示例:

python

import re
import execjs
import requests

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36",
}

gct_path = "https://static.geetest.com/static/js/gct.b71a9027509bc6bcfef9fc6a196424f5.js"
gct_js = requests.get(gct_path, headers=headers).text
function_name = re.findall(r")){return (.*?)(", gct_js)[0]
break_position = gct_js.find("return function(t){")
gct_js_new = gct_js[:break_position] + "window.gct=" + function_name + ";" + gct_js[break_position:]
gct_js_new = "window = global;" + gct_js_new + """
function getGct(){
    var e = {"lang": "zh", "ep": "test data"};
    window.gct(e);
    delete e["lang"];
    delete e["ep"];
    return e;
}"""
gct = execjs.compile(gct_js_new).call("getGct")
print(gct)

补环境中可能用到的方法
window.crypto.getRandomValues
在某些情况下,如三代滑块验证中,可能会用到 window.crypto.getRandomValues() 方法。

javascript

window = global;
window.crypto = {
    getRandomValues: getRandomValues_
}

function randoms(min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min)
}

function getRandomValues_(buf) {
    var min = 0,
    max = 255;
    if (buf.length > 65536) {
        var e = new Error();
        e.code = 22;
        e.message = 'Failed to execute 'getRandomValues' : The ' + 'ArrayBufferView's byte length (' + buf.length + ') exceeds the ' + 'number of bytes of entropy available via this API (65536).';
        e.name = 'QuotaExceededError';
        throw e;
    }
    if (buf instanceof Uint16Array) {
        max = 65535;
    } else if (buf instanceof Uint32Array) {
        max = 4294967295;
    }
    for (var element in buf) {
        buf[element] = randoms(min, max);
    }
    return buf;
}

// 测试
// var a = new Uint32Array(256);
// console.log(window.crypto.getRandomValues(a))
window.performance.timing
某些性能指标需要 window.performance.timing 方法来获取。例如:

javascript

window = global;
window.performance = {
    timing: {
        navigationStart: Date.parse(new Date()),
        unloadEventStart: 0,
        unloadEventEnd: 0,
        redirectStart: 0,
        redirectEnd: 0,
        fetchStart: 0,
        domainLookupStart: 0,
        domainLookupEnd: 0,
        connectStart: 0,
        connectEnd: 0,
        secureConnectionStart: 0,
        requestStart: 0,
        responseStart: 0,
        responseEnd: 0,
        domLoading: 0,
        domInteractive: 0,
        domContentLoadedEventStart: 0,
        domContentLoadedEventEnd: 0,
        domComplete: 0,
        loadEventStart: 0,
        loadEventEnd: 0,
    }
}
完整的环境搭建代码示例
javascript

const { v4: uuidv4 } = require('uuid');
const axios = require('axios');
const CryptoJS = require('crypto-js');

function getRandomString(){
    function e(){
        return (65536 * (1 + Math.random()) | 0).toString(16).substring(1);
    }
    return e() + e() + e() + e();
}

function get_pow(pow_detail, captcha_id, lot_number) {
    var n = pow_detail.hashfunc;
    var i = pow_detail.version;
    var r = pow_detail.bits;
    var s = pow_detail.datetime;
    var o = "";

var a = r % 4;
    var u = parseInt(r / 4, 10);
    var c = function g(e, t) {
        return new Array(t + 1).join(e);
    }("0", u);
    var _ = i + "|" + r + "|" + n + "|" + s + "|" + captcha_id + "|" + lot_number + "|" + o + "|";

while (1) {
        var h = getRandomString()
          , l = _ + h
          , p = void 0;
        switch (n) {
            case "md5":
            p = CryptoJS.MD5(l).toString();
            break;
        case "sha1":
            p = CryptoJS.SHA1(l).toString();
            break;
        case "sha256":
            p = CryptoJS.SHA256(l).toString();
        }
        if (0 == a) {
            if (0 === p.indexOf(c))
                return {
                    "pow_msg": _ + h,
                    "pow_sign": p
                };
        } else if (0 === p.indexOf(c)) {
            var f = void 0
              , d = p[u];
            switch (a) {
            case 1:
                f = 7;
                break;
            case 2:
                f = 3;
                break;
            case 3:
                f = 1;
            }
            if (d <= f)
                return {
                    "pow_msg": _ + h,
                    "pow_sign": p
                };
        }
    }
}

window = global;
window.crypto = {
    getRandomValues: getRandomValues_
}

function randoms(min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min)
}

function getRandomValues_(buf) {
    var min = 0,
    max = 255;
    if (buf.length > 65536) {
        var e = new Error();
        e.code = 22;
        e.message = 'Failed to execute 'getRandomValues' : The ' + 'ArrayBufferView's byte length (' + buf.length + ') exceeds the ' + 'number of bytes of entropy available via this API (65536).';
        e.name = 'QuotaExceededError';
        throw e;
    }
    if (buf instanceof Uint16Array) {
        max = 65535;
    } else if (buf instanceof Uint32Array) {
        max = 4294967295;
    }
    for (var element in buf) {
        buf[element] = randoms(min, max);
    }
    return buf;
}

window.performance = {
    timing: {
        navigationStart: Date.parse(new Date()),
        unloadEventStart: 0,
        unloadEventEnd: 0,
        redirectStart: 0,
        redirectEnd: 0,
        fetchStart: 0,
        domainLookupStart: 0,
        domainLookupEnd: 0,
        connectStart: 0,
        connectEnd: 0,
        secureConnectionStart: 0,
        requestStart: 0,
        responseStart: 0,
        responseEnd: 0,
        domLoading: 0,更多内容联系1436423940
        domInteractive: 0,更多内容访问ttocr.com或联系1436423940
        domContentLoadedEventStart: 0,
        domContentLoadedEventEnd: 0,
        domComplete: 0,
        loadEventStart: 0,
        loadEventEnd: 0,
    }
}

async function getCaptchaData() {
    const response = await axios.get('https://api.example.com/captcha');
    const captchaData = response.data;
    return captchaData;
}

(async () => {
    try {
        const captchaData = await getCaptchaData();
        const powResult = get_pow(captchaData.pow_detail, captchaData.captcha_id, captchaData.lot_number);
        console.log('POW Result:', powResult);
    } catch (error) {
        console.error('Error fetching captcha data:', error);
    }
})();

标签:function,return,pow,验证码,细节,gct,var,识别,buf
From: https://www.cnblogs.com/ocr12/p/18664716

相关文章

  • 潮汐指纹识别工具 : 在线网站识别利器
    最近发现了一个免费在线收集网站信息的工具,感觉挺好用的,给各位推荐下。潮汐在线指纹识别是山东新潮信息技术有限公司安全团队提供的一个免费开源在线网站信息收集工具。功能亮点:全面扫描只需输入目标网站的URL或IP地址,即可获取该网站的标题、中间件、操作系统、域名信息等关......
  • java对象方法使用细节
    返回数据类型:一个方法最多只能有一个返回值;如果有要求返回数据类型,则最后执行语句必须为:return值当方法为void的时候,方法体中可以没有return,或者只写return;方法的形参和实参的类型要一致或兼容,个数,顺序必须一致;方法体内不能嵌套定义方法;方法调用:同一个类中的方法......
  • M5Stack 发布全双工通信语音识别硬件;雷蛇发布 AI 游戏伴侣 Project AVA,实时指导复盘
      开发者朋友们大家好: 这里是「RTE开发者日报」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享RTE(Real-TimeEngagement)领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编辑......
  • 网安知识系列:Nmap识别目标机器服务指纹
    Nmap识别目标机器服务指纹Nmap识别目标机器服务指纹Nmap端口探测——识别目标主机的服务和版本服务指纹:识别服务的参数Nmap识别服务指纹(-sV)Nmap侵略性的探测使用命令1:使用命令2:使用nmap-sC-sV-OIP地址来探测目标机器的操作系统、服务等信息。......
  • 图标点选验证码识别及分割
    图标点选验证码是一种防止自动化攻击的手段,要求用户点击指定的图标进行验证。本文介绍如何使用Swift结合ONNX模型和Siamese神经网络来实现图标点选验证码的识别和分割。一、技术背景图标点选验证码的破解分为两部分:图标分割和相似度对比。图标分割用于检测并裁剪出验证码图片中......
  • 使用Crystal语言实现极验滑动验证码识别
    我们将展示如何使用Crystal语言实现自动识别极验滑动验证码的全过程,从模拟点击到识别滑动缺口、计算位移并模拟拖动滑块。如果认证失败,则重复调用直到成功。识别思路模拟点击切换为滑动验证,并显示验证界面。识别滑动缺口的位置,计算位移。更多内容联系1436423940模拟拖动滑块。......
  • 自动识别点触验证码
    目标本节的目标是使用C#语言通过程序自动识别并通过点触验证码。准备工作我们将使用C#的Selenium库和Chrome浏览器。请确保已经安装好了SeleniumWebDriver和Chrome浏览器,并配置好了ChromeDriver。相关的安装和配置可以参考Selenium官方文档。了解点触验......
  • python 代码实现了从NetCDF格式的气象数据文件中提取亮温(TBB)数据,识别中尺度对流系统(MC
    importnumpyasnpimportnetCDF4asncimportosimportcv2fromskimageimportmeasureimportmatplotlib.pyplotasplt#定义常量和参数DATA_DIR=r'E:\Data\FY4-TBB_ALL'TRACK_OUTPUT=r'E:\Data\mcs_tracks.txt'OVERLAP_THRESHOLD=0.3......
  • PDF如何提取文字?OCR技术快速识别提取PDF中的文字内容!这种简单方法一定要知道!
    在日常工作中,我们常常会遇到PDF文档和图纸中的文字无法直接复制粘贴的问题,尤其是那些文字呈现为打散线条或扫描图片形式的文件,给我们的工作带来诸多不便。不过别担心,PDF快速看图软件的“提取文字”功能(基于OCR技术)就能轻松解决这个难题,下面就为大家详细介绍其使用教程。一......
  • wqs二分的一些性质和细节
    wqs二分共线情况的处理在我们进行\(wqs\)二分时,需要要求函数是具有凸性的,但是有时候最终所求的点在函数上可能和前后的几个点共线,这时我们在应该如何更新答案呢?此时的取值方式和你二分的\(check\)写法有关。我们以上凸壳为例:\(check\)会对每个斜率求出一个转移的次数。......