当前位置: 首页 > news >正文

某网站极验4滑块验证码逆向分析

文章目录

  • 1. 写在前面
  • 2. 接口分析
  • 3. w逆向分析
  • 4. JSON参数分析
  • 5. 距离识别
  • 6. RSA纯算还原
  • 7. AES纯算还原

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

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

1. 写在前面

   极验相关的验证码网上公开的教程很多,这也是每一位爬虫工程师职业生涯中几乎都会遇到的(就跟瑞数一样总有一天你会在职场与其打交道)也是很多学习Web逆向协议过验证的小伙伴必攻克练手的必经之路。前段时间作者也是看了一眼比较抵触的多个验证码系列,写的验证码相关的文章比较少。类型可以说是五花八门,复杂的要去训练,没有时间去折腾(难的也不会)。看也就是看下JS层面的一些加密,这里我们也来分析一下它的流程(适合新手小伙伴参考练习


分析网站

6Ieq5bex5om+5LiA5Liq77yM5b2T5L2g5bCd6K+V6Kej56CB55qE6L+Z5LiA5Yi744CC5oOz5ZGK6K+J5L2g5Yir5Y235LqG

2. 接口分析

整个验证的流程比较简洁,两个接口,一个load一个verify。先看一下load接口请求参数与响应数据如下:

在这里插入图片描述

{"status": "success","data": {"lot_number": "80ff732c046e471286a596376f23e6ba","captcha_type": "slide","slice": "pictures/v4_pic/slide_2024_09_02/e9d1dec400/slide/da4cb40154354b98b0aabc59a516407b.png","bg": "pictures/v4_pic/slide_2024_09_02/e9d1dec400/bg/da4cb40154354b98b0aabc59a516407b.png","ypos": 88,"arrow": "arrow_1","js": "/js/gcaptcha4.js","css": "/css/gcaptcha4.css","static_path": "/v4/static/v1.8.9-2c5e49","gct_path": "/v4/gct/gct4.5a2e755576738ba0499d714db4f1c9e0.js","show_voice": false,"feedback": "","logo": false,"pt": "1","captcha_mode": "adaptive","guard": false,"check_device": true,"language": "en-us","lang_reverse": false,"custom_theme": {"_style": "flat","_color": "hsla(166, 100%, 35%, 1)","_gradient": "linear-gradient(180deg, hsla(166, 100%, 35%, 1) 0%, hsla(166, 100%, 35%, 1) 100%)","_hover": "linear-gradient(180deg, hsla(166,  100%,  30%,  1) 0%, hsla(166,  100%,  30%,  1) 100% )","_brightness": "system","_radius": "4px"},"pow_detail": {"version": "1","bits": 0,"datetime": "2025-06-14T14:46:04.908506+08:00","hashfunc": "md5"},"payload": "AgFD8gWUUuHFx-XvpP7J2eXmFGG988RJA9XWIifIhVfD_3urF6TwX10q6TrWNlmoLrmnDZXhh-Ds0tvYuF6iz5alWQDqnpl0rqqdGpTnlPBV0BX8BWJ5g0YFxJt1IOoQVcRgUKRcBVWhr05ylkkJZXmzCjWL1dDhSlKM126f2CZbUhZx485twyTTIgg6TxkHp6RFiEexFFTfAtnhmMzgKU23kd_SmUIpkhKKF4bwPjaDya1ARBt-LMTEJSFl0XZKUXBONNi2GkE0BIbNVEDSLi4QK7Zj55XdDCTUuBkmYr5YxPXUERlbVg3UZyx0Y9EXEHMgaUL7CySS6wrF3_lx4x_5wMrC7FQY9RMZ_mIGUpjk3HIc5OQIQlOZEVDlvEIm6dwESxLJZha5UI92v7w-w9ceoaQGo1oBJ1uqRmPxQsHpmDS77OCNf8r2ymn4nt-mtL4ee2U0yyMX1py5BM1gNWR8kAEVvFWcwwWObMFjMtWSuP4yT193BgbmfCwK_N1dnpCcMCVppkdkfgUQ_Eay_oiTfpR17q7G1gGG52U-NLWM5wgGVTNzmw83Js2pPfl9zQB3By9VIzmwvNqJzsQUg3H_2WyII9YZ5BPAxqe6j3W3-uL1UCyrx4UoYY-Pp5JugjrxQ26vBWE7B5cWc3poPHwTa5nXmyiS3QbZYc_qw3K_YyF96yTL2AVq2TzR6DOiqM1cb6HloK2rVD8mRquqbXXA7rvdKTlYswSxJXSDD6K-bg8CMQ_br4AnxmfC1U_blfAwWSZnqSyoHb9g8X3ejeeW1qxkEYIAcG6bmKhb8gMWTSV1I3WtU7sBLqc5o4O4Qm4q3Xl3gN8bPsh4RSQXJ5M8QudVdBWid0iR5afT2-aL0ZAGOb7a1ooFhrpFndEkT7cHFPG-mMp-HHjY8giZwK8minfPqGKxdOfsQbUqnP8=","process_token": "233085ee7f960fae79d07dcd40515833e0367c2e4edc1ba4bc5b530dc5e7600b","payload_protocol": 1}
}

上面JSON数据是load接口的响应,包含了一些图片的信息跟后续验证接口二次携带请求的参数字段。然后看一下verify验证接口提交的参数,如下所示:

在这里插入图片描述

标记出来的基本都是load接口响应的参数,都是后续提交验证过程中要拿来使用的,唯一要逆向解决的参数就是w,所以我们需要知道这个w的明文数据是什么然后通过什么加密方式出来的

3. w逆向分析

首先需要定位这个w生成的位置(搜索w:、从下往上看栈两三个、搜其他特征明显的请求参数)均可以帮助我们定位到相关位置处,如下所示:

在这里插入图片描述

现在都这么抽象了么,关键的一些变量、函数、参数那些看起来使用了Unicode字符来替代。这种如果觉得硬看费劲的话可以使用AST来辅助还原,还原流程大致如下所示:

在这里插入图片描述

还原这个混淆JS的关键策略就是构建映射表根据实际的分析情况去补充跟过滤

接下来我们来看w参数是怎么生成的,把生成这个参数的这一行代码拿下来,如下所示:

_ᖆᕶᖙᖁ = (0,_ᕴᖁᕹᖄ[_ᖃᕾᕶᖂ(67)])(_ᖁᖉᕿᖈ[_ᕹᖃᕶᕿ(67)][_ᕹᖃᕶᕿ(559)](_ᖘᖄᖁᕿ), _ᕴᖙᖄᖘ)

_ᖆᕶᖙᖁ就是加密之后的结果,_ᖘᖄᖁᕿ是加密的明文JSON数据,然后做了一个JSON.stringify的操作,如下所示:

在这里插入图片描述

这里我们核心看_ᕴᖁᕹᖄ[_ᖃᕾᕶᖂ(67)],这个函数我们直接跟进去看看是什么,通过调用它传递了JSON数据生成的w

在这里插入图片描述

这里我们把上面跳转到的核心JS代码拿下来,再联动网页调试来分析一下流程,如下所示:

_ᖘᖄᖁᕿ[_ᖃᕾᕶᖂ(67)] = function _ᖆᕶᖙᖁ(_ᖘᖄᖁᕿ, _ᖁᖆᕸᕸ) {var _ᖃᕾᕶᖂ = _ᖘᖈᖙᖃ.$_CL, _ᖁᕷᕹᖄ = ["$_DCAAk"].concat(_ᖃᕾᕶᖂ), _ᕹᖃᕶᕿ = _ᖁᕷᕹᖄ[1];_ᖁᕷᕹᖄ.shift();var _ᖃᕹᖄᖚ = _ᖁᕷᕹᖄ[0];var _ᖆᖘᕶᕹ = _ᖁᖆᕸᕸ[_ᖃᕾᕶᖂ(439)];if (!_ᖆᖘᕶᕹ[_ᖃᕾᕶᖂ(604)] || _ᖃᕾᕶᖂ(183) === _ᖆᖘᕶᕹ[_ᕹᖃᕶᕿ(604)])return _ᕴᖙᖄᖘ[_ᕹᖃᕶᕿ(67)][_ᖃᕾᕶᖂ(921)](_ᖘᖄᖁᕿ);var _ᖀᕷᖚᖉ = (0,_ᕷᕸᖉᕷ[_ᕹᖃᕶᕿ(93)])(), _ᖂᖗᕿᖁ = new (_ᕷᕸᖉᕷ[_ᕹᖃᕶᕿ(30)])([_ᖃᕾᕶᖂ(873), _ᕹᖃᕶᕿ(898)]), _ᖄᖈᕸᖃ = {1: {symmetrical: _ᕿᕶᖆᖃ[_ᕹᖃᕶᕿ(67)],asymmetric: new (_ᖂᕿᕷᖀ[_ᖃᕾᕶᖂ(67)])},2: {symmetrical: new (_ᖄᕵᕸᖁ[_ᖃᕾᕶᖂ(67)])({key: _ᖀᕷᖚᖉ,mode: _ᕹᖃᕶᕿ(926),iv: _ᕹᖃᕶᕿ(981)}),asymmetric: _ᖂᕸᖄᕿ[_ᕹᖃᕶᕿ(67)]}};if (_ᖂᖗᕿᖁ[_ᖃᕾᕶᖂ(123)](_ᖆᖘᕶᕹ[_ᖃᕾᕶᖂ(604)])) {var o = _ᖃᕾᕶᖂ(873) === _ᖆᖘᕶᕹ[_ᖃᕾᕶᖂ(604)], a = _ᖆᖘᕶᕹ[_ᖃᕾᕶᖂ(604)], _ = _ᖄᖈᕸᖃ[a][_ᕹᖃᕶᕿ(938)][_ᖃᕾᕶᖂ(911)](_ᖀᕷᖚᖉ);while (o && (!_ || 256 !== _[_ᖃᕾᕶᖂ(64)]))_ᖀᕷᖚᖉ = (0,_ᕷᕸᖉᕷ[_ᖃᕾᕶᖂ(93)])(),_ = (new (_ᖂᕿᕷᖀ[_ᕹᖃᕶᕿ(67)]))[_ᖃᕾᕶᖂ(911)](_ᖀᕷᖚᖉ);var u = _ᖄᖈᕸᖃ[a][_ᖃᕾᕶᖂ(934)][_ᖃᕾᕶᖂ(911)](_ᖘᖄᖁᕿ, _ᖀᕷᖚᖉ);return (0,_ᕷᕸᖉᕷ[_ᖃᕾᕶᖂ(5)])(u) + _}}}

它这个w的值由两段密文拼接组成的,先看_ᖄᖈᕸᖃ[a][_ᕹᖃᕶᕿ(938)][_ᖃᕾᕶᖂ(911)](_ᖀᕷᖚᖉ)这个位置的代码,生成的是第一段。通过对一个长度16位的字符串进行了一个encrypt操作得到的,如下所示:

在这里插入图片描述

好,这里看看encrypt对应的JS,先解决第一段的密文。再去往下进行分析,跳转后直接拿下来,代码如下所示:

...
_ᖂᖗᕿᖁ[_ᖁᖆᕸᕸ(55)][_ᖁᖆᕸᕸ(1028)] = function _ᖆᕶᖙᖁ(_ᖘᖄᖁᕿ, _ᖁᖆᕸᕸ) {var _ᖃᕾᕶᖂ = _ᖘᖈᖙᖃ.$_CL, _ᖁᕷᕹᖄ = ["$_DGHAO"].concat(_ᖃᕾᕶᖂ), _ᕹᖃᕶᕿ = _ᖁᕷᕹᖄ[1];_ᖁᕷᕹᖄ.shift();var _ᖃᕹᖄᖚ = _ᖁᕷᕹᖄ[0];null != _ᖘᖄᖁᕿ && null != _ᖁᖆᕸᕸ && 0 < _ᖘᖄᖁᕿ[_ᖃᕾᕶᖂ(64)] && 0 < _ᖁᖆᕸᕸ[_ᕹᖃᕶᕿ(64)] ? (this[_ᖃᕾᕶᖂ(96)] = function _ᖆᕶᖙᖁ(_ᖘᖄᖁᕿ, _ᖁᖆᕸᕸ) {var _ᖃᕾᕶᖂ = _ᖘᖈᖙᖃ.$_CL, _ᖁᕷᕹᖄ = ["$_DGHFu"].concat(_ᖃᕾᕶᖂ), _ᕹᖃᕶᕿ = _ᖁᕷᕹᖄ[1];_ᖁᕷᕹᖄ.shift();var _ᖃᕹᖄᖚ = _ᖁᕷᕹᖄ[0];return new b(_ᖘᖄᖁᕿ,_ᖁᖆᕸᕸ)}(_ᖘᖄᖁᕿ, 16),this[_ᖃᕾᕶᖂ(943)] = parseInt(_ᖁᖆᕸᕸ, 16)) : console && console[_ᖃᕾᕶᖂ(370)] && console[_ᕹᖃᕶᕿ(370)](_ᕹᖃᕶᕿ(1130))
}...省略

下一个断刷新后可以看到上面函数先是接受了一个16位的那个密文然后_ᖘᖄᖁᕿ参数的值是一个很长的十六进制字符串(256字节2048位)直接丢给GPT把参数值一并提交它会提示我们这通常是一个RSA公钥的模数(n

_ᖁᖆᕸᕸ参数的值10001十进制公钥指数,就算我们不进行AST还原通过作用域结合控制台甚至是鼠标查值的方式也都是也可以看到一些特征的,JS通过new b(_ᖘᖄᖁᕿ, _ᖁᖆᕸᕸ)创建了一个加密对象,b可能是RSA的构造函数,接着parseInt(_ᖁᖆᕸᕸ, 16)将公钥指数转换为数值

看到有console相关的信息输出,鼠标扫了一下更加证实了上面的加密方式猜测,如下所示:

在这里插入图片描述
在这里插入图片描述

另外说一下这个16位的key如何生成的,返回的4e()相加,跟进去看看e是什么,如下所示:

在这里插入图片描述
在这里插入图片描述

上面e方法实现了返回一个随机生成四位16进制字符串,.toString(16)将整数转为16进制字符串,substring(1)再截取字符串的第二个字符到末尾,得到一个四位16进制字符串,65536相当于16^4即四位16进制数的最大值(FFFF)+1

return (65536 * (1 + Math.random()) | 0).toString(16).substring(1);# 示例
Math.random()           // 0.74321
1 + 0.74321            // 1.74321
65536 * 1.74321       // 114245.12056
114245 | 0            // 114245 (十进制)
(114245).toString(16) // "1bdc5"
"1bdc5".substring(1)  // "bdc5"

第一段密文分析完可以成功拿到_的值,接下来根据最初贴出来的JS继续往下分析u这个大数组是怎么来的,原始代码如下:

var u = _ᖄᖈᕸᖃ[a][_ᖃᕾᕶᖂ(934)][_ᖃᕾᕶᖂ(911)](_ᖘᖄᖁᕿ, _ᖀᕷᖚᖉ);

u这里通过调用了_ᖃᕾᕶᖂ(911)encrypt传了两个参数,_ᖘᖄᖁᕿ是文章开始的那个转成字符串的大JSON_ᖀᕷᖚᖉ则是上面复现的16key,跟进去发现特征跟前面cbc一样并且iv也是一样。走了一个AES的加密操作,如下所示:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

可以看到这个流程它走完AES后返回的是一个长数组(即u),然后往下再做了一个16进制的字符串转换操作得到最后w参数的另一段值,然后把RSA加密得到的那一段短值拼接到u出来这串长值后面得到完整的一个w加密值,如下所示:

在这里插入图片描述

4. JSON参数分析

至此,上面关于w参数的整体加密计算流程就分析梳理出来了,然后接下来回过头来需要分析一下参与加密的那个大JSON,因为貌似涉及的字段看起来不少,这里我们将它拿出来分析一下,如下所示:

{"pow_sign" : "a689bc86ae4eee78c2cf11a946b1b741","ep" : "123","passtime" : 796,"biht" : "1426265548","pow_msg" : "1|0|md5|2025-06-14T19:18:12.048835+08:00|4f70e8a42240f8f809bea8382e738e53|df5ed6e3f65e49709e9dcbd4d595f199||a6ae0baf4ca6c7d1","lot_number" : "df5ed6e3f65e49709e9dcbd4d595f199","em" : {"wd" : 1,"sc" : 0,"ek" : "11","nt" : 0,"ph" : 0,"cp" : 0,"si" : 0},"geetest" : "captcha","setLeft" : 146,"5ed6e3f6" : "e9dcbd","userresponse" : 147.1369191209607,"device_id" : "","lang" : "zh","w22T" : "72PZ"
}

这里主要分析一下pow_signpow_msguserresponsesetLeft以及那个5ed6e3f6:e9dcbd键值对参数,先来看pow_msg它由两部分拼接,如下所示:

在这里插入图片描述

前面的那个长字符串用拼接的可以全局搜索这个参数下一个断找初始化的地方,很明显还是拿的load接口请求的参数加响应的参数拼起来的,如下所示:

在这里插入图片描述

在这里插入图片描述

上面三张图就是整个一次滑块加载出来的参数值拼接出来的

_ᖀᖙᕵᖀ第一个大长串,|0|md5|2025-06-14T22:48:45.549309+08:00|取自于loiad接口的响应参数pow_detail中四个参数,后面追第一个32位字符串取值于请求参数的captcha_id字段,第二个32字符串取值与响应参数内的lot_number字段

再看第二部分的h是怎么来的,往上看定义的地方直接点进去又来到了上面我们分析的16key生成的e函数处,如下所示:

在这里插入图片描述

那么看样子走的同样的逻辑,至此pow_msg参数分析完毕。接着来看pow_sign参数,一样的32字符跟进去看到md5的信息。直接在线工具验证证实就是对pow_msg的值做了一个md5得到了pow_sign,如下所示:

在这里插入图片描述
在这里插入图片描述

接下来我们先不看那两个数字结果相关的字段,先分析那个key value的字段,这个也是动态生成的。回到最开始我们分析w位置的地方,往上一点点就能看到这个动态参数的生成,这里多刷新了几次发现也不是加密生成的,还是对参数字段的值做的索引取值拿到的,如下所示:

在这里插入图片描述
在这里插入图片描述

如上取的是load接口中返回的lot_number字段的值,索引的规则目前看是下面这样子来对应的(它这个取下标的规则挂到了window下面,最好动态获取

在这里插入图片描述

在这里插入图片描述

最后剩下三个数字相关的参数字段,来看看如何来的。setLeft是滑块的距离,userresponse在滑块距离的数值上进一步做了一个运算。如下所示:

在这里插入图片描述

5. 距离识别

最后我们只需要对滑块的缺口的距离进行识别拿到setLeft参数的值基本就完成了,滑块识别代码实现如下(仅供参考):

import cv2
import numpy as npdef get_slider_offset(background_img_bytes, slider_img_bytes):"""识别滑块缺口在背景图中的X坐标。:param background_img_bytes: 背景图片的二进制数据:param slider_img_bytes: 滑块缺口图片的二进制数据:return: 缺口的X坐标"""# 解码图像为灰度图bg_gray = cv2.imdecode(np.frombuffer(background_img_bytes, np.uint8), cv2.IMREAD_GRAYSCALE)slider_gray = cv2.imdecode(np.frombuffer(slider_img_bytes, np.uint8), cv2.IMREAD_GRAYSCALE)# 裁剪滑块图像:只保留有效区域(像素值 < 200)ys, xs = np.where(slider_gray < 200)slider_crop = slider_gray[min(ys):max(ys), min(xs):max(xs)]# 边缘检测bg_edge = cv2.Canny(bg_gray, 100, 200)slider_edge = cv2.Canny(slider_crop, 100, 200)result = cv2.matchTemplate(cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB),cv2.cvtColor(slider_edge, cv2.COLOR_GRAY2RGB),cv2.TM_CCOEFF_NORMED)_, _, _, top_left = cv2.minMaxLoc(result)h, w = slider_crop.shapecv2.rectangle(bg_gray, top_left, (top_left[0] + w, top_left[1] + h), (0, 0, 255), 2)cv2.imwrite('distinguish.jpg', bg_gray)return top_left[0]

6. RSA纯算还原

这里我们根据上面的分析先对第一部分的16keyRSA加密使用Python进行还原,还原实现代码如下所示:

import base64
import binascii
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5, PKCS1_OAEPdef load_public_key(pem_key=None, modulus=None, exponent=None):if pem_key:cleaned = pem_key.replace("\n", "").replace(" ", "")if "-----" in cleaned:cleaned = [part for part in cleaned.split("-----") if len(part) > 25][0]key_bytes = base64.b64decode(cleaned)return RSA.importKey(key_bytes)elif modulus and exponent:n = int(modulus, 16) if isinstance(modulus, str) else moduluse = int(exponent, 16) if isinstance(exponent, str) else exponentreturn RSA.construct((n, e))raise ValueError("必须提供 PEM 公钥或 modulus + exponent")def get_cipher(key_obj, padding_mode: int):scheme = {1: PKCS1_OAEP.new,2: PKCS1_v1_5.new}if padding_mode not in scheme:raise ValueError("padding_mode 只支持 1(OAEP)或 2(v1_5)")return scheme[padding_mode](key_obj)def get_chunk_size(key_obj):return int(key_obj.size_in_bits() / 1024 * 100)def encrypt_bytes(plaintext: str, *, pem_key=None, modulus=None, exponent=None, padding_mode=1) -> bytes:key_obj = load_public_key(pem_key=pem_key, modulus=modulus, exponent=exponent)cipher = get_cipher(key_obj, padding_mode)chunk_size = get_chunk_size(key_obj)encrypted_data = b""for offset in range(0, len(plaintext), chunk_size):segment = plaintext[offset:offset + chunk_size].encode()encrypted_data += cipher.encrypt(segment)return encrypted_datadef encrypt_to_base64(plaintext: str, **kwargs) -> str:return base64.b64encode(encrypt_bytes(plaintext, **kwargs)).decode()def encrypt_to_hex(plaintext: str, **kwargs) -> str:return binascii.hexlify(encrypt_bytes(plaintext, **kwargs)).decode()def encrypt_to_utf8(plaintext: str, **kwargs) -> str:return encrypt_bytes(plaintext, **kwargs).decode("utf-8", errors="ignore")modulus = ("00C1E3934D1614465B33053E7F48EE4EC87B14B95EF88947713D25EECBFF7E74""C7977D02DC1D9451F79DD5D1C10C29ACB6A9B4D6FB7D0A0279B6719E1772565F""09AF627715919221AEF91899CAE08C0D686D748B20A3603BE2318CA6BC2B5970""6592A9219D0BF05C9F65023A21D2330807252AE0066D59CEEFA5F2748EA80BAB81"
)
exponent = "10001"# key动态传递
ciphertext = encrypt_to_hex("189c7043fd718369", modulus=modulus, exponent=exponent, padding_mode=2)
print(ciphertext)

7. AES纯算还原

这里我们根据上面对u的分析进行AES加密算法还原,采用的CBC模式,然后iv上面几个0固定的,key的话跟参与RSA加密的时候用的一致,算法实现如下所示:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import binascii
import secrets
import stringdef encrypt_aes_cbc(plaintext: str, key_str: str, iv_str: str = "0000000000000000") -> str:"""使用 AES-CBC 模式对字符串加密,并返回 hex 字符串。:param plaintext: 原始明文字符串:param key_str: 16 字节长度的密钥字符串:param iv_str: 16 字节长度的初始向量(默认全0):return: 加密后的十六进制字符串"""key = key_str.encode('utf-8')iv = iv_str.encode('utf-8')# 初始化加密器cipher = AES.new(key, AES.MODE_CBC, iv)# 对明文进行 PKCS7 填充padded = pad(plaintext.encode('utf-8'), AES.block_size)# 加密并转换为 hex 字符串返回encrypted_bytes = cipher.encrypt(padded)return binascii.hexlify(encrypted_bytes).decode('utf-8')# 示例调用
data_to_encrypt = '{"setLeft":146,"passtime":796,"userresponse":147.1369191209607,"device_id":"","lot_number":"df5ed6e3f65e49709e9dcbd4d595f199","pow_msg":"1|0|md5|2025-06-14T19:18:12.048835+08:00|4f70e8a42240f8f809bea8382e738e53|df5ed6e3f65e49709e9dcbd4d595f199||a6ae0baf4ca6c7d1","pow_sign":"a689bc86ae4eee78c2cf11a946b1b741","geetest":"captcha","lang":"zh","ep":"123","biht":"1426265548","w22T":"72PZ","5ed6e3f6":"e9dcbd","em":{"ph":0,"cp":0,"ek":"11","wd":1,"nt":0,"si":0,"sc":0}}'
aes_key = "b9acf19ce1a635a9" encrypted_hex = encrypt_aes_cbc(data_to_encrypt, aes_key)
print(encrypted_hex)

最后整个关于极验4滑块的协议验证流程就差不多到这里结束了,找了一个套极验4的网站测试了一下。如下所示:

在这里插入图片描述

http://www.xdnf.cn/news/1044577.html

相关文章:

  • vue2中setTimeout中调用methods方法问题
  • BEV 感知算法评价指标简介
  • 安卓9.0系统修改定制化____安卓 9.0系统修改固件 自动开启USB调试教程 开搞篇 六
  • 【Linux】基于策略模式的简单日志设计
  • Spring Boot Web 应用开发
  • 如何用AI绘画工具创作出属于你的拉布布(泡泡玛特)形象?
  • leetcode146-LRU缓存
  • rv1126+opencv多线程同时对视频进行膨胀和腐蚀
  • java 设计模式_行为型_20中介者模式
  • HTML的最基础入门知识,从零开始逐步讲解,适合为后续爬虫技术打基础:
  • Windows下Docker一键部署Dify教程
  • htmlcss考核
  • WebAssembly 2.0:超越浏览器的全栈计算革命
  • 【Zephyr 系列 26】跨平台测试框架设计:CLI + 自动脚本 + OTA 校验一体化方案
  • NVIDIA Isaac GR00T N1.5 人形机器人强化学习入门教程(四)Lerobot、宇树 G1 等不同形态机器人微调教程
  • Spring Boot的Security安全控制——应用SpringSecurity!
  • Java面试题022:一文深入了解微服务网关Gateway
  • 微软azure抢跑aws和谷歌云的区别
  • SpringMVC系列(一)(介绍,简单应用以及路径位置通配符)
  • 使用Nodejs尝试小程序后端服务编写:简单的待办事项管理demo
  • Java EE与Jakarta EE命名空间区别
  • Appium+python自动化(二十三)- Monkeyrunner与Monkey
  • 基于PPSO与BP神经网络回归模型的特征选择实战(Python实现)
  • Node.js 中常用的异步函数讲解、如何检测异步操作时间和事件
  • NodeJS的yarn和npm作用和区别,为什么建议用yarn
  • AWS 解决方案深度剖析:Amazon QLDB — 构建可信赖、不可变的数据审计基石
  • 智造奇点:AI超级工厂如何重塑制造业DNA
  • nodejs和npm升级
  • 什么是稳定币?
  • windows制作ubuntu系统安装盘