某红书旋转滑块验证码分析与协议算法实现(高通过率)
文章目录
- 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的接口,获取到验证码提交所需要的rid跟captchaInfo字段信息
请求同样是需要头部带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_diffdef 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) // 2y = (bg_height - circle_height) // 2overlay = np.zeros_like(bg_image)overlay[y:y + circle_height, x:x + circle_width] = rotated_resultresult = cv2.bitwise_or(bg_image, overlay)return resultdef split_circular_region(image, radius):height, width, _ = image.shapecenter = (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 resultdef 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 resultquery_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 = 0for 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_differencemin_angle = angleresult = merge_images(query_result, bg_image, 89, min_angle)cv2.imwrite('./jpg/result.png', result)return min_angle

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

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

相关文章:
某红书旋转滑块验证码分析与协议算法实现(高通过率)
文章目录 1. 写在前面2. 接口分析3. 验证轨迹4. 算法还原 【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致…...
Gin的快速入门和搭建
文章目录 Go的工程工程架构技术选型 Gin入门 Go的工程 基于Go生态,构建一个支持内容管理,内容加工、内容分发的内容库系统。 内容管理:增删改查内容加工:例如内容审核、推荐等内容分发:将内容可以推到不同的业务线 …...
react-native运行程序 出现 Application XXX is waiting for the debugger
1.重启adb: adb kill-server、 adb start-server. 2、确定USB调试模式是否开启,如果已经开启了,关闭了重新打开一下 3.选择调试模式并关闭等待调试程序...
什么文档加密软件好用?迅软DSE加密软件你不会还不知道吧?
一、什么文档加密软件好用? 其中有迅软DSE文档加密软件等。 迅软DSE加密软件:让企业的创意成果、招投标文件、生产工艺、流程配方、研发成果、公司计划、员工信息等核心数据更安全。 多方面加密模式,有效防止数据泄密 透明无感知加密&…...
【kubernetes】关于k8s集群的污点、容忍、驱逐以及k8s集群故障排查思路
目录 一、污点(Taint) 1.1污点介绍 1.2污点的组成格式 1.3当前 taint effect 支持如下三个选项: 1.4污点的增删改查 1.4.1验证污点的作用——NoExecute 1.4.2验证污点的作用——NoSchedule 1.4.3 验证污点的作用——PreferNoSchedule 1.5污点的配置与管理…...
linux进程加载和启动过程分析
我们的源代码通过预处理,编译,汇编,链接后形成可执行文件,那么当我们在终端敲下指令$ ./a.out argv1 argv2 后,操作系统是怎么将我们的可执行文件加载并运行的呢? 首先知道,计算机的操作系统的启动程序是写死在硬件上的,每次计算机上电时,都将自动加载启动程序,之后…...
WLAN组网模型探究
目录 一、WLAN基本概念二、WLAN组网方式三、WLAN转发模型 随着信息技术的飞速发展,无线局域网(WLAN)已逐渐成为企业网络架构中不可或缺的一部分。不同的企业组织因其业务特性、规模大小及安全需求的不同,对WLAN的要求也各有侧重。…...
操作系统基础知识
一. 进程 进程是正在运行中的程序,是动态的 进程是资源分配的最小单位 进程的基本特征:动态性,并发性,独立性,异步性 二. 线程 线程在执行过程中的每一个任务就是一个线程 进程是由一个或多个线程组成࿰…...
Kompas AI:智能生活的开启者
引言 在现代社会,**人工智能(AI)**已经深刻地影响了我们的生活和工作。无论是智能家居、自动驾驶,还是医疗诊断,AI的应用无处不在。而在众多AI平台中,Kompas AI 作为一个先进的对话式AI平台,通过…...
Java——二进制原码、反码和补码
一、简要介绍 原码、反码和补码只是三种二进制不同的表示形式,每个二进制数都有这三个形式。 1、原码 原码是将一个数的符号位和数值位分别表示的方法。 最高位为符号位,0表示正,1表示负,其余位表示数值的绝对值。 例如&…...
git使用流程
1.下载git 搜索下载 2.注册github账号(打开爬墙工具) 创建一个仓库 3.配置邮箱和密码 4.所以找一个文件夹 鼠标右键 选择 open Git Bash here(当前文件夹下打开命令行) 输入命令 配置用户名和邮箱 5.将建的仓库克隆下来 …...
C++设计模式|结构型 代理模式
1.什么是代理模式? 代理模式Proxy Pattern是一种结构型设计模式,用于控制对其他对象的访问。 在代理模式中,允许一个对象(代理)充当另一个对象(真实对象)的接口,以控制对这个对象的…...
C语言 带头双向循环链表的基本操作
带头双向循环链表的基本操作 结构体定义初始化创建新节点头插头删尾插尾删查找在指定位置之后插入删除指定位置的值打印 结构体定义 typedef int DataType; typedef struct LinkNode {DataType data;struct LinkNode* prev;struct LinkNode* next; }LNode;初始化 有两种初始化…...
MATLAB中扩展卡尔曼滤波误差估计的关键点
在MATLAB中,对于扩展卡尔曼滤波(EKF)的误差估计,主要涉及对系统状态估计的准确性和精度的评估。EKF是一种适用于非线性系统的状态估计方法,它通过递归的方式,结合系统的动态模型和观测模型,来预…...
SpringBoot温习
1.1 Spring Boot Spring Boot是一个开源的Java框架,由Pivotal团队(现在是VMware的一部分)开发,它是Spring框架的一个模块,旨在简化Spring应用程序的初始搭建以及开发过程。 Spring Boot的核心目标是让开发者尽可能…...
Spring Cloud:构建高可用分布式系统的利器
摘要:本文将介绍Spring Cloud,一个基于Spring Boot的开源微服务架构工具集。我们将探讨Spring Cloud的核心组件、特性以及如何使用Spring Cloud构建高可用、分布式系统。通过本文,读者将了解到Spring Cloud在实现微服务架构中的应用和优势。 …...
IT技术 | 电脑蓝屏修复记录DRIVER_IRQL_NOT_LESS_OR_EQUAL
我的台式机是iMac 2015年的,硬盘是机械的,时间久了运行越来越慢。后来对苹果系统失去了兴趣,想换回windows,且想换固态硬盘,就使用winToGo 搞了双系统,在USB外接移动固态硬盘上安装了win10系统。 最近&…...
windows 下编译 TessRact+leptonica 识别图片文字
目录 1、下载 2. 编译基础依赖库 1.1 zlib 1.2 jpegsr9f 1.3 lpng1643 1.4 libgif 3. 编译tifflib 4. 配置nasm到系统环境中 5. 编译 libjpeg-turbo 6 编译leptonica 7. 编译tesseract 8. 测试验证 1、下载 下载tesseract5.3.2 下载leptonica1.83.1 下载l…...
如何把docker里的内容拷贝出来
如何把docker里的内容拷贝出来 要从Docker容器中复制文件或目录出来,可以使用docker cp命令。以下是基本的命令格式和示例: 命令格式: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH示例: 假设你有一个名为my_container的…...
OpenAI开始训练新的前沿模型——但GPT-5至少在90天内不会推出
ChatGPT 制造商 OpenAI 今早宣布,已开始训练其新的“前沿模型”,并成立了一个新的安全委员会,由现任董事会成员 Bret Taylor(OpenAI 董事会主席兼客户服务初创公司 Sierra AI 联合创始人、前谷歌地图负责人和前 Facebook 首席技术…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
