某红书旋转滑块验证码分析与协议算法实现(高通过率)

文章目录

  • 1. 写在前面
  • 2. 接口分析
  • 3. 验证轨迹
  • 4. 算法还原

【🏠作者主页】:吴秋霖
【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究与开发工作!
【🌟作者推荐】:对爬虫领域以及JS逆向分析感兴趣的朋友可以关注《爬虫JS逆向实战》《深耕爬虫领域》
未来作者会持续更新所用到、学到、看到的技术知识!包括但不限于:各类验证码突防、爬虫APP与JS逆向分析、RPA自动化、分布式爬虫、Python领域等相关文章

作者声明:文章仅供学习交流与参考!严禁用于任何商业与非法用途!否则由此产生的一切后果均与作者无关!如有侵权,请联系作者本人进行删除!

1. 写在前面

  作者在使用红薯的时候,经常会选择通过手机验证的方式去登录。但是,天公不作美!我甚至有时候第一次登录,就给我弹出一个验证码…有风控固然是好的,但是略微的影响到了用户的交互体验,一般用户只能选择是手动拖动滑块进行验证…

在这里插入图片描述

但是!作为一名科技行业的程序员。肯定是不会屈服的,于是带着对技术的好奇心在想过这个旋转的验证码,是否可以自动化呢?当然自动化没有挑战!作者选择通过协议+算法的方式去通过这个验证码~

2. 接口分析

这里我们浅拉一下旋转的滑块,然后监测register这个接口的发包,如下所示:

在这里插入图片描述

这几个参数中verifyUuid是重要的,它在每一次生成弹出验证码的时候,给出的一个新且唯一的验证ID,在后续的验证接口同样需要携带!获取方式如下所示:

在这里插入图片描述

在输入手机号点击发送短信验证码的时候,假设失败被风控了。短信接口会正常给到你成功的响应,如下所示:

{"code":0,"success":true,"msg":"成功","data":{}}

但是如果你光通过接口去检验,是不知道出验证的。得看请求状态,失败出现验证码则是471,这个时候再去头部分析,拿到验证码的UID

通过register的接口,获取到验证码提交所需要的ridcaptchaInfo字段信息

请求同样是需要头部带X-s、X-s-common参数的

第二个我们需要分析的接口则是check,这个是提交验证检测的。如下所示:

在这里插入图片描述

可以看到提交的参数中captchaInfo是最重要的,通过字段信息能够看到提交的鼠标轨迹相关的一些东西,而且看这样子应该还是加密的!另外的rid、uid在前面环节都能够获取到,checkCount参数则是验证次数,通不过就会自增

3. 验证轨迹

接下来如果没有解决头部X系列的两个参数加密,建议先去研究这个两个参数,再来研究滑块!当然如果你不知道怎么还原可以去看作者以前的文章!现在开始还原captchaInfo这个参数

JS调试发现轨迹验证参数的值采用了DES加密,可以拿浏览器内的加密轨迹来解密看看,如下所示:

在这里插入图片描述

轨迹分析后开始实现算法,如下所示:

function generate_Track(slideDistance) {
    var trackList = [];
    var x = 0;
    while (x < slideDistance) {
        x += 2;
        var y = -(Math.floor(x / 10));
        var z = 2 * (x - 1) + Math.floor(Math.random() * 7) + 1;
        trackList.push([x, y, z]);
    }
    return JSON.stringify(trackList);
}
function get_mousetrack(distance,time){
    var mousetrack1=get_trace(distance,time);
    var mousetrack2=generate_Track(distance);
    return DES_Encrypt(mousetrack2,"PYrm8rMk")
}
function get_trace(distance,time) {
    distance = Math.floor(distance);
    var trace = [];
    var sy = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0];
    var st = [15, 16, 17, 18, 15, 16, 17, 18, 15, 16, 17, 18, 15, 16, 17, 18, 15, 16, 17, 18, 15, 16, 17, 18, 15, 16, 17,
        18, 15, 16, 17, 18, 15, 16, 17, 18, 15, 16, 17, 18, 14, 16, 17, 18, 16, 17, 18, 19, 20, 17];

    if (distance < 95) {
        var sx = [1, 2, 1, 2, 1, 2, 1, 1, 2, 1];
    }else{
        var sx = [1, 2, 1, 2, 1, 2, 2, 2, 3, 4];
    }
    var zt = RandomNum(10, 100);
    var zx = 0,
        zy = 0;
    var random_x = RandomNum(9, 14);
    var n = 0, x = 0, y = 0, t = 0;
    while (true){
        n += 1;
        if (n < 5){
            x = 1;
        }else{
            x = RandomChoice(sx)
        }
        if (distance > 125 && random_x === n){
            x = RandomNum(14, 18)
        }
        y = RandomChoice(sy);
        t = RandomChoice(st);
        zx += x;
        zy += y;
        zt += t;
        trace.push([zx, zy, zt]);
        if (distance - zx < 6){
            break;
        }
    }
    var value = distance - zx;
    for (var i = 0; i < value; i++){
        t = RandomChoice(st);

        if (value === i + 1){
            t = RandomNum(42, 56)
        }
        if (value === i + 2){
            t = RandomNum(32, 38)
        }
        if (value === i + 3){
            t = RandomNum(30, 36)
        }
        x = 1;
        zx += x;
        zt += t;
        trace.push([zx, zy, zt]);
    }
    let csz=RandomNum(1, 10)
    let elementToInsert0 = [0, 0, csz];
    let elementToInsert1 = [0, 0, csz+2];
    trace.unshift(elementToInsert1);
    trace.unshift(elementToInsert0);
	return JSON.stringify(trace);
}

4. 算法还原

首先需要封装register接口的协议请求,核心请求提交封参如下所示:

json_data = {
  "secretId": "000",
  "verifyType": "102",
  "verifyUuid": v_id,
  "verifyBiz": "471",
  "sourceSite": "",
  "captchaVersion": "1.1.0"
}
jmurl='url=/api/redcaptcha/v2/captcha/register'+json.dumps(json_data).replace(" ","")

a1=ck['a1']
xts = self.ctx.call('get_x_s',jmurl,a1)
xtscommon = self.ctx.call('get_x_s_common',xts,a1)
self.headers['x-s'] = xts['X-s']
self.headers['x-s-common']=xtscommon
self.headers['x-t']=str(xts['X-t'])

data=json.dumps(json_data,separators=(',',':'))
response = requests.post(url, headers=self.headers, cookies=ck, data=data)

check验证接口的提交核心封参请求如下所示:

chainfo={
		"mouseEnd":self.ctx.call('DES_Encrypt',mouseend,"WquqhEkd"),
		"time":self.ctx.call('DES_Encrypt',time,"vPMvCY4K"),
		"track":self.ctx.call('get_mousetrack',mouseend,time),
		"width":self.ctx.call('DES_Encrypt',width,"WquqhEkd")
	}
	json_data={
		"rid":rid,
		"verifyType":"102",
		"verifyBiz":"471",
		"verifyUuid":v_id,
		"sourceSite":"",
		"captchaVersion":"1.1.0",
		"checkCount":str(check_count),
		"captchaInfo":json.dumps(chainfo)
	}

当然,请求完成后的过程中我们还需要对旋转图片角度的分析与图像处理(包括裁剪)!主要就是通过对两个图像进行分析处理来找出最佳的角度。使得合并后的图像在梯度上的差异最小,这里我们采用了CV2,通过核心Py。源码如下所示:

def perform_angle_analysis(self,query_image_path, background_image_path):
    def calculate_gradient_difference(image, cx, cy, circle_radius):
        circle_inner_mask = np.zeros_like(image, dtype=np.uint8)
        cv2.circle(circle_inner_mask, (cx, cy), circle_radius, 255, -1)
        circle_outer_mask = np.zeros_like(image, dtype=np.uint8)
        cv2.circle(circle_outer_mask, (cx, cy), circle_radius + 30, 255, -1)
        inner_pixels = cv2.bitwise_and(image, circle_inner_mask)
        outer_pixels = cv2.bitwise_and(image, circle_outer_mask)
        inner_sobel_x = cv2.Sobel(inner_pixels, cv2.CV_64F, 1, 0)
        inner_sobel_y = cv2.Sobel(inner_pixels, cv2.CV_64F, 0, 1)
        inner_gradient_magnitude = cv2.magnitude(inner_sobel_x, inner_sobel_y)
        outer_sobel_x = cv2.Sobel(outer_pixels, cv2.CV_64F, 1, 0)
        outer_sobel_y = cv2.Sobel(outer_pixels, cv2.CV_64F, 0, 1)
        outer_gradient_magnitude = cv2.magnitude(outer_sobel_x, outer_sobel_y)
        gradient_diff = np.sum(outer_gradient_magnitude) - np.sum(inner_gradient_magnitude)
        return gradient_diff

    def merge_images(query_result, bg_image, radius, angle):
        query_height, query_width = query_result.shape[:2]
        rotation_matrix = cv2.getRotationMatrix2D((query_width / 2, query_height / 2), angle, 1)
        rotated_result = cv2.warpAffine(query_result, rotation_matrix, (query_width, query_height))
        center = (bg_image.shape[1] // 2, bg_image.shape[0] // 2)
        cv2.circle(bg_image, center, radius, (0, 0, 0), -1)
        bg_height, bg_width = bg_image.shape[:2]
        circle_height, circle_width = rotated_result.shape[:2]
        x = (bg_width - circle_width) // 2
        y = (bg_height - circle_height) // 2
        overlay = np.zeros_like(bg_image)
        overlay[y:y + circle_height, x:x + circle_width] = rotated_result
        result = cv2.bitwise_or(bg_image, overlay)
        return result

    def split_circular_region(image, radius):
        height, width, _ = image.shape
        center = (width // 2, height // 2)
        mask = np.zeros_like(image)
        cv2.circle(mask, center, radius, (255, 255, 255), -1)
        result = cv2.bitwise_and(image, mask)
        return result

    def enlarge_image(image, scale_factor):
        circle_height, circle_width = image.shape[:2]
        new_height = int(circle_height * scale_factor)
        new_width = int(circle_width * scale_factor)
        result = cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_LINEAR)
        return result

    query_image = cv2.imread(query_image_path)
    bg_image = cv2.imread(background_image_path)

    query_result = split_circular_region(query_image, 89)
    query_result = enlarge_image(query_result, 1.1)
    min_difference = float('inf')
    min_angle = 0
    for angle in range(0, 360, 5):
        result = merge_images(query_result, bg_image, 89, angle)
        gradient_difference = calculate_gradient_difference(result, bg_image.shape[1] // 2, bg_image.shape[0] // 2, 70)
        if gradient_difference < min_difference:
            min_difference = gradient_difference
            min_angle = angle
    result = merge_images(query_result, bg_image, 89, min_angle)
    cv2.imwrite('./jpg/result.png', result)
    return min_angle

在这里插入图片描述

最后完成所有的编码后,把滑块验证部署成一个API服务,这样的话更加方便调用,如下:

在这里插入图片描述

本地直接通过检测471验证码,拿到uid、cookie调用纯协议滑块验证服务,效果如下:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/674230.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C2M商业模式分析与运营平台建设解决方案(52页PPT)

方案介绍&#xff1a; C2M商业模式通过直接连接消费者与制造商&#xff0c;实现了个性化定制和高效生产。运营平台建设解决方案则注重技术选型、数据驱动、用户体验和供应链管理等方面&#xff0c;为C2M模式的顺利实施提供了有力支持。随着数字化时代的到来&#xff0c;C2M模式…

解决git status提示error bad signature 0x00000000

问题描述&#xff1a; 操作git的时候电脑卡了&#xff0c;重启电脑后git status就提示bad signature 0x00000000&#xff0c;index file corrupt错误&#xff0c;如下&#xff1a; 解决办法&#xff1a; rm -f .git/index git reset

计网期末复习指南(三):数据链路层(CRC冗余校验码计算、PPP协议、CSMA/CD协议、交换机的自学习能力、VLAN)

前言&#xff1a;本系列文章旨在通过TCP/IP协议簇自下而上的梳理大致的知识点&#xff0c;从计算机网络体系结构出发到应用层&#xff0c;每一个协议层通过一篇文章进行总结&#xff0c;本系列正在持续更新中... 计网期末复习指南&#xff08;一&#xff09;&#xff1a;计算…

【wiki知识库】04.SpringBoot后端实现电子书的增删改查以及前端界面的展示

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 一、&#x1f525;今日内容 二、&#x1f30f;前端页面的改造 2.1新增电子书管理页面 2.2新增路由规则 2.3修改the-header代码 三、&#x1f697;SpringBoot后端Ebook模块改造 3.1增加电子书增/改接口 3.1.…

Cacti EZ中文版 12.2.27 ISO 下载安装

简介 修改了yum源为中国高校联合镜像源 github改为gitee。 系统增加中文语言包。 修改时区为东八区。 增加了常用的软件包。 PS&#xff1a;CactiEZ是一个自动化安装cacti和插件的ISO镜像&#xff0c;本教程的ISO是基于官方的IOS针对国内网络做了修改。 可按照目前最新的Ca…

[AI Google] 新的生成媒体模型和工具,专为创作者设计和构建

我们推出了 Veo&#xff0c;我们最强大的高清晰度视频生成模型&#xff0c;以及 Imagen 3&#xff0c;我们质量最高的文本生成图像模型。我们还分享了一些使用我们的 Music AI Sandbox 创作的新演示录音。 在过去的一年里&#xff0c;我们在提升生成媒体技术质量方面取得了令人…

智能售货机的小投入大回报创业机遇

智能售货机的小投入大回报创业机遇 在当今这个快速进化的数字时代&#xff0c;智能售货机作为零售领域的新秀&#xff0c;正以其独特的便捷性和创新性逐步重塑传统零售格局。24小时不间断服务与自动化管理的结合&#xff0c;大幅度削减人力成本&#xff0c;使得智能售货机成为…

生信算法7 - 核酸序列Fasta和蛋白PDB文件读写与检索

python 3.9实现以下算法。 1. 简单的写文件和读文件 # 写 file1 open(count.txt,w) file1.write(this is a test) file1.close()# 读 file2 open(my_file) print(file2.read())2. 将列表内容写入文本文件 # 生成100-500数字列表 data [i * 100 for i in range(1, 6)] pri…

AI大模型,正在排队寻求“卖身”!请保持冷静!

AI独角兽卖身大潮&#xff0c;再添一员 就在上周&#xff0c;备受瞩目的明星企业Stability AI&#xff0c;这家估值接近300亿的大模型领域的佼佼者&#xff0c;**突然传出资金链断裂的严峻消息&#xff0c;并正积极寻求合并的可能性。**与此同时&#xff0c;媒体也透露&#x…

RetroMAE-文本embedding算法

1)输入文本经掩码操作后由编码器&#xff08;Encoder&#xff09;映射为隐空间中的语义向量&#xff1b;而后解码器&#xff08;Decoder&#xff09;借助语义向量将另一段独立掩码的输入文本还原为原始的输入文本 2)编码器的掩码率为15%-30%&#xff1b;解码器的掩码率为50%-70…

HMM地图匹配算法库Barefoot环境搭建

1.引入gps路径匹配开源项目barefoot 克隆仓库 git clone https://github.com/bmwcarit/barefoot.git打开项目执行mvn命令将项目打包到maven仓库 mvn install -DskipTests在自己的maven项目中引入barefoot依赖 <dependency><groupId>com.bmw-carit</groupId&g…

k8s 1.28.x 配置nfs

1.安装nfs&#xff0c;在每个节点上安装 yum install -y nfs-utils 2.创建共享目录(主节点上操作) mkdir -p /opt/nfs/k8s 3.编写NFS的共享配置 /opt/nfs/k8s *(rw,no_root_squash) #*代表对所有IP都开放此目录&#xff0c;rw是读写 4.启动nfs systemctl enable nfs-ser…

Flutter基础 -- Dart 语言 -- 进阶使用

目录 1. 泛型 generics 1.1 泛型使用 1.2 泛型函数 1.3 构造函数泛型 1.4 泛型限制 2. 异步 async 2.1 异步回调 then 2.2 异步等待 await 2.3 异步返回值 3. 生成器 generate &#xff08;了解&#xff09; 3.1 同步生成器 sync* 使用 sync* 的场景 总结 3.2 异…

CRM系统主要是干什么?CRM系统主要功能和作用

什么是CRM 系统&#xff1f;CRM系统到底是干什么的&#xff1f;不同的企业人员该如何利用CRM去解决他们的问题等等&#xff0c;问题太多了&#xff0c;今天来为大家详细介绍。 干货满满&#xff0c;建议收藏&#xff01;&#xff01; 首先第一个问题&#xff0c;什么是CRM系统…

Tween.js在Three.js中的应用:为3D动画添加流畅过渡

前言 在Web开发领域&#xff0c;Three.js已经成为构建精彩3D内容的首选库之一。它让开发者能够轻松地在浏览器中创建和展示复杂的3D场景。然而&#xff0c;要让这些场景栩栩如生&#xff0c;平滑的动画效果是必不可少的。这就引入了Tween.js——一个轻量级但功能强大的JavaScr…

MyBatis核心对象

MyBatis核心类对象主要有俩个&#xff1a; 1&#xff1a;对相关配置文件信息进行封装的Configuration对象 2&#xff1a;用来执行数据库操作的Executor对象。 核心对象----存储类对象Configuration Configuration对象主要有三个作用&#xff1a; 1&#xff1a;封装MyBatis…

linux进程加载和启动过程分析

我们的源代码通过预处理,编译,汇编,链接后形成可执行文件,那么当我们在终端敲下指令$ ./a.out argv1 argv2 后,操作系统是怎么将我们的可执行文件加载并运行的呢? 首先知道,计算机的操作系统的启动程序是写死在硬件上的,每次计算机上电时,都将自动加载启动程序,之后…

R语言数据分析-针对芬兰污染指数的分析与考察

1. 研究背景及意义 近年来&#xff0c;随着我国科技和经济高速发展&#xff0c;人们生活质量也随之显著提高。但是&#xff0c; 环境污染问题也日趋严重&#xff0c;给人们的生活质量和社会生产的各个方面都造成了许多不 利的影响。空气污染作为环境污染主要方面&#xff0c;更…

重生之我要精通JAVA--第七周笔记

文章目录 IO流字符流字符流原理解析flush和close方法 文件拷贝代码文件加密解密修改文件中的数据 缓冲流字节缓冲流字符缓冲流例题 转换流序列化流序列化流/对象操作输出流 反序列化流序列化流/反序列化流的细节汇总打印流字节打印流字符打印流 解压缩流压缩流Commons-io常见方…

代码随想录--哈希表--两数之和

题目 给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目标值的那 两个 整数&#xff0c;并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素不能使用两遍。 示例: 给定 nums [2, 7, 11, 15], t…