1. 极验空间推理验证码技术背景
第一次接触极验空间推理验证码是在一个电商爬虫项目中。当时目标网站升级了验证系统,传统的滑动验证码被替换成了需要点击特定物体的新型验证方式。这种验证码会显示一张包含多个物体的图片,并提示"请点击图中的红色汽车"之类的指令,用户需要在正确位置点击才能通过验证。
与滑动验证码相比,空间推理验证码的破解难度明显更高。它不仅需要识别图片中的物体,还要模拟人类点击行为,生成加密的验证参数。经过两周的逆向分析,我发现这类验证码的核心防护机制主要依赖三个层面:
- 动态密钥体系:每次验证会生成唯一的challenge参数,配合gt值形成会话标识
- 多层参数加密:关键参数w的生成涉及多个加密环节,包括AES、自定义算法等
- 行为特征检测:会记录鼠标移动轨迹、点击时间间隔等行为特征
在实际破解过程中,最关键的突破口在于分析get.php接口返回的数据结构。这个接口不仅提供了验证图片URL,还包含了后续加密所需的c和s参数。有趣的是,这些参数看似随机,实则与图片内容存在特定关联,这也是极验验证码设计的精妙之处。
2. 接口请求链深度解析
2.1 初始注册接口分析
register-space接口是整个验证流程的起点。通过抓包分析,我发现这个接口主要有两个关键返回值:
- gt:网站标识符,通常固定不变。例如某电商网站的gt值为"b46d1900d562245eeb4e8a5e8d11a8d5"
- challenge:动态生成的会话ID,格式为32位MD5字符串,有效期约5分钟
这两个参数会贯穿整个验证流程。特别需要注意的是,challenge具有严格的单次使用限制。在测试中发现,即使同一IP重复使用相同challenge,也会触发验证失败。更棘手的是,极验服务器会记录IP与challenge的绑定关系,简单的更换IP并不能绕过这个限制。
2.2 图片获取接口关键参数
get.php接口返回的JSON数据结构中,这几个参数需要特别关注:
{ "pic": "/nerualpic/space_l1_zh_2023.05.21/space/58741...jpg", "c": [12, 58, 98, 36, 43, 95, 62, 15, 12], "s": "514c622c", "sign": "请点击图中的红色消防栓" }经过多次测试验证,我总结出这些参数的作用规律:
- pic:图片路径看似随机,实则包含日期信息(如2023.05.21),可能用于版本控制
- c数组:9个0-100之间的整数,与图片中目标物体的位置存在数学关系
- s值:固定8位十六进制字符串,参与后续的坐标加密计算
- sign:验证指令文本,不同语言环境会返回相应语言的提示
2.3 验证提交接口加密逻辑
ajax.php接口接收的核心参数w是一个复合加密字符串,其生成过程可以分解为:
w = p + u p = YQee( AES_encrypt( stringify(o), gCdf() ) ) u = fTbG()其中对象o的结构尤为关键:
var o = { "lang": "zh-cn", "passtime": 1568, "a": "326_415", "pic": "/nerualpic/space...jpg", "tt": pe(s, c, s), "ep": {} }在具体实现时,passtime建议取800-2000ms之间的随机值,模拟真人操作耗时。坐标参数a的格式为"X_Y",需要将点击位置的像素坐标转换为百分比值。例如在400x400的图片上点击(120,200),则对应"30_50"。
3. JS反混淆实战技巧
3.1 AST还原基本流程
面对极验高度混淆的JS代码,AST(抽象语法树)还原是最有效的反混淆手段。具体操作流程如下:
- 使用Chrome开发者工具定位关键JS文件(通常为click.*.js)
- 通过Pretty-print功能格式化压缩代码
- 使用Babel解析生成AST语法树
- 编写转换规则处理特定混淆模式
- 生成可读性更高的新代码
一个典型的数组混淆还原示例:
// 混淆代码 var _0xad3b = ["\x47\x65\x74", "\x75\x73\x65\x72\x41\x67\x65\x6E\x74"]; function _0x45ac() { return navigator[_0xad3b[1]]; } // 还原后 function getUserAgent() { return navigator["userAgent"]; }3.2 关键函数定位方法
在反混淆过程中,如何快速定位加密函数是个技术活。我的经验是:
- 特征字符串搜索:在混淆代码中搜索"encrypt"、"decode"等关键词
- 参数追踪法:从ajax.php的w参数反向追踪调用链
- 断点调试:在Chrome DevTools中对Function.prototype.call设置断点
特别提醒:极验的加密函数通常会伪装成数组操作,比如将AES加密实现为array5的形式。这时需要结合上下文和参数类型来判断真实功能。
4. w参数生成全解析
4.1 坐标转换算法
点击坐标需要经过三层处理才能用于加密:
像素坐标转百分比:
def pixel_to_percent(x, y, img_width, img_height): return f"{round(x/img_width*100)}_{round(y/img_height*100)}"加入随机扰动: 实测发现坐标值±3%范围内都能通过验证,建议添加1-2%的随机偏移
历史轨迹生成: 极验会验证移动轨迹的自然性,建议模拟如下模式:
- 初始位置随机偏移10-15%
- 包含2-3次方向微调
- 最后阶段减速接近目标
4.2 tt参数生成细节
tt参数是w加密中最复杂的部分,其生成函数pe的伪代码如下:
def pe(s, c_arr, s_key): mixed = [] for i in range(len(c_arr)): mixed.append(c_arr[i] ^ int(s_key[i%4], 16)) return base64_encode(mixed)实际实现时需要注意:
- c_arr长度固定为9
- s_key需要转换为4个十六进制字节
- 异或运算后需要保持数值在0-255范围内
4.3 完整w生成示例
结合Python实现的w参数生成流程:
import hashlib import time import json from Crypto.Cipher import AES def generate_w(gt, challenge, pic_url, c_array, s_key, click_pos): # 生成o对象 o = { "lang": "zh-cn", "passtime": random.randint(800, 1500), "a": click_pos, "pic": pic_url, "tt": generate_tt(c_array, s_key), "ep": {} } # 加密生成p key = generate_gCdf() cipher = AES.new(key, AES.MODE_ECB) p = cipher.encrypt(pad(json.dumps(o).encode())) # 生成u u = generate_fTbG(key) return p.hex() + u.hex()5. 实战注意事项
在具体项目落地时,有几个容易踩坑的细节:
时间戳同步问题:服务器会检查各接口调用时间间隔,建议保持:
- register-space到get.php:200-500ms
- get.php到ajax.php:1-3s
IP质量要求:经过测试,极验会对以下IP特征进行风控:
- 数据中心IP(AWS、阿里云等)
- 高频请求IP(>5次/分钟)
- 代理IP的跳跃式地理位置变化
浏览器指纹模拟:必要的HTTP头包括:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Accept-Language: zh-CN,zh;q=0.9 Sec-GPC: 1验证码识别优化:对于物体识别环节,建议:
- 使用YOLOv5等目标检测模型
- 针对特定场景微调模型(如电商场景)
- 加入图像增强预处理(直方图均衡化等)
这套方案在多个项目中实测通过率可达85%以上,关键是要处理好行为模拟的自然性和参数加密的准确性。对于更高安全等级的极验验证码,可能需要结合更复杂的深度学习方案来提升识别精度。