某红书旋转滑块验证码分析与协议算法实现(高通过率)
文章目录
- 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 首席技术…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...
