极验4滑动验证码参数 w 逆向分析
免责声明:本文章中所有内容仅供学习交流使用,不用于其他任何目的。抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!
前言
极验(Geetest)验证码是当前使用最广泛的验证码方案之一,其第四代版本(极验4)在请求参数中引入了 w 和 td 等加密参数,用于防止自动化脚本的直接调用。本文将以学习交流为目的,从抓包分析入手,逐步还原 w 参数的完整生成逻辑,涵盖 c、u、s 等子参数的逆向过程。
一、逆向目标
目标网址(Base64 脱敏): aHR0cHM6Ly9ndDQuZ2VldGVzdC5jb20v
打开浏览器开发者工具,多次抓包后不难发现需要逆向的接口,主要有两个:
-
load:验证码请求接口,用于初始化验证码
-
verify:验证接口,用于提交滑动结果进行校验

二、接口参数分析
2.1 load 接口请求参数
load 接口相对简单,参数均为明文,主要用于初始化验证码会话:
| callback | 格式为 geetest_时间戳,JSONP 回调函数名 |
| captcha_id | 54088bb07d2df3c46b79f80300b0abbe,滑动验证码 ID(固定值) |
| challenge | UUID4 格式,每次请求唯一标识 |
| client_type | 客户端类型,固定为 web |
| risk_type | 验证码类型,滑动验证码固定为 slide |
| lang | 语言,zh |
2.2 verify 接口请求参数
verify 接口是本次逆向的核心,其中 w 和 td 为需要逆向的加密参数:
| callback | geetest_时间戳 | 自行生成 |
| captcha_id | 与 load 接口一致 | 固定值 |
| client_type | 客户端类型 | 固定 web |
| lot_number | 流水号 | load 返回数据 |
| risk_type | 验证码类型 | load 返回的 captcha_type |
| payload | 载荷 | load 返回数据 |
| process_token | 流程令牌 | load 返回数据 |
| payload_protocol | 载荷协议 | load 返回数据 |
| pt | 时间戳参数 | load 返回数据 |
| w | 加密参数(需逆向) | 本文中逆向生成 |
| td | 加密参数(需逆向) | 本文中逆向生成 |
三、参数逆向
3.1 定位加密位置
在开发者工具的 网络(Network) 栏中找到 verify 接口,点击 发起程序(Initiator),可以看到所有请求均来自同一个 JS 文件。点击该文件即可跳转到源代码面板中进行查看。

3.2 w 参数逆向分析
通过关键字 w: 搜索,即可定位到 w 参数的加密赋值位置:

由于代码经过了混淆,变量名形如 _ᕺᖈᕴᖁ 这类字符难以识别。可以借助 AST(抽象语法树) 对其进行重命名和内容替换,使代码更易读:

同时,可以将代码中形如 var_2057(582) 的调用进行字符串还原替换:

替换完成后,在 c 处打断点进行分析,可以看到 c 即为 w 的值:

在 c 处打断点后,观察到 arg_657 是 w 加密的参数内容,var_1833[var_2059(13)] 是加密函数。点击跳转到该加密函数:

发现函数中只有一个 return,在此处打断点,运行到该位置即可确认这里是 w 参数值的生成处:


观察 return 上文,可以找到 u 和 c 的生成位置:

arg_884 是传进来的参数,也就是上文提到的 arg_657。继续向上观察,可以看到 s 的生成位置:

至此,w 的大致生成过程已分析完毕。w 由 c 和 u 两个值拼接得到,下面分别对 c 和 u 的生成过程进行具体分析。
3.2.1 c 参数逆向分析
将代码中的字符串还原后,可以清晰看到 c 的生成逻辑:

可以看到,c 是传入参数 arg_884 和 s,通过 encrypt 函数加密后,再由 arrayToHex 函数处理得到的十六进制字符串。其核心流程为:
c = arrayToHex(encrypt(arg_884, s))
因此,需要先还原 s 参数,再分析 encrypt 加密函数。
s 参数逆向分析
打断点跳转到 s 的生成位置:

点击进入函数后跳转到 return function。去掉用于解密的干扰代码,核心逻辑仅剩下一行:
return e() + e() + e() + e();
其中 e 函数的原始混淆形式为:
function e() {
return (65536 * (1 + Math[var_228(158)]()) | 0)[var_230(165)](16)[var_230(74)](1);
}
还原混淆后即为标准的随机十六进制生成函数:
// 生成 4 位随机十六进制字符串
function e() {
// 65536 * (1 + Math.random()) 生成 [65536, 131072) 的数
// | 0 转为整数,toString(16) 转十六进制,substring(1) 截取后 4 位
return (65536 * (1 + Math.random()) | 0).toString(16).substring(1);
}
四个 e() 调用拼接后即得到长度为 16 的随机字符串 s。运行验证如下:

encrypt 加密函数分析
断点回到 c 的加密位置,进入 encrypt 加密函数:

继续深入函数内部:


进入 v[var_3113(913)]:

将 return 的内容交给 AI 分析,可以推测出所使用的加密算法:

确认算法后,可以让 AI 编写实现该加密算法的代码,完成 c 参数的还原。
3.2.2 u 参数逆向分析
u 是对 s 进行加密后的结果:

u 的加密函数位于 r 对象中的 asymmetric 方法(从方法名 asymmetric 即可推断为非对称加密):

将该截图交给 AI 分析,可推测出具体使用的非对称加密算法:

确定加密算法后,还需要找到对应的公钥。从代码中可以看出 setPublic 是设置公钥的函数:

点击跳转到该函数内部,在函数中打断点,函数的两个参数即为公钥的相关组成部分(模数和指数):

至此,w 参数值的完整生成过程已全部还原。
四、总结
本文以极验4滑动验证码为分析对象,完整梳理了 w 参数的生成链路,整体流程可归纳如下:
关键经验:
-
AST 反混淆是分析高强度混淆 JS 的有效手段,能大幅降低阅读成本
-
对于不认识的加密算法,合理利用 AI 辅助识别可以显著提高效率
-
非对称加密的密钥通常通过 setPublic / setPrivateKey 等显式函数设置,断点拦截即可获取
再次声明:本文内容仅限学习交流,请勿用于任何非法用途。
网硕互联帮助中心





评论前必须登录!
注册