【验证码逆向专栏】数美验证码全家桶逆向分析以及 AST 获取动态参数
字数 2093 2025-08-11 00:08:50
数美验证码全家桶逆向分析与AST动态参数获取教学文档
一、目标概述
本教学文档针对数美验证码全家桶进行逆向分析,包括以下验证码类型:
- 滑块验证码 (slide)
- 文字点选验证码 (select)
- 图标点选验证码 (icon_select)
- 语序点选验证码 (seq_select)
- 空间推理验证码 (spatial_select)
- 无感验证码 (auto_slide)
二、验证码接口分析
1. 验证码体验地址
- 官网体验地址:
aHR0cHM6Ly93d3cuaXNodW1laS5jb20vdHJpYWwvY2FwdGNoYS5odG1s - 官方隐藏地址(包含无感验证):
aHR0cHM6Ly9jYXN0YXRpYy5mZW5na29uZ2Nsb3VkLmNuL3ByL3YxLjAuNC9kZW1vLmh0bWw= - 某红书验证页面:
aHR0cHM6Ly93d3cueGlhb2hvbmdzaHUuY29tL3dlYi1sb2dpbi9jYXB0Y2hh
2. 核心接口分析
(1) conf接口 - 获取配置
请求参数:
| 参数 | 含义 |
|---|---|
| organization | 数美分配的公司标识,每个网站唯一 |
| appId | 应用标识,区分不同应用 |
| callback | 回调参数 |
| lang | 语言(zh-cn/zh-tw/en) |
| model | 验证码模式 |
| sdkver | captcha-sdk.min.js内部写死的版本 |
| channel | 推广渠道 |
| captchaUuid | 32位随机字符串 |
| rversion | captcha-sdk.min.js版本号 |
返回结果:主要获取captcha-sdk.min.js文件地址
(2) register接口 - 注册验证码
返回数据:
bg: 背景图片fg: 滑块图片(滑块验证码)order: 提示信息(文字点选、空间推理)k,l,rid: 后续加密使用的关键参数
(3) fverify接口 - 验证接口
请求参数:12个动态生成的加密参数,包括:
- 类似
ep的长参数(包含轨迹加密) - 其他11个动态参数
返回结果:
code: 状态码(1100成功,1901 QPS超限,1902 参数不合法,1903 服务失败,9101 无权限操作)riskLevel: 处置建议(PASS正常,REJECT违规)
三、核心逆向分析
1. JS混淆与反混淆
- 核心逻辑在
captcha-sdk.min.js中,采用类似OB混淆 - 可使用
v_jstools工具进行解混淆 - 重要提示:替换JS时需注意:
- 解决跨域问题(设置响应头
Access-Control-Allow-Origin) - JS不能格式化(有格式化检测),需保持压缩为一行
- 解决跨域问题(设置响应头
2. captchaUuid生成算法
function generateTimeFormat() {
var e = new Date()
, t = function(n) {
return +n < 10 ? "0" + n : n.toString();
};
return ((e.getFullYear().toString() + t(e.getMonth() + 1)) + t(e.getDate()) + t(e.getHours()) + t(e.getMinutes())) + t(e.getSeconds());
}
function getCaptchaUuid() {
var c = "";
var o = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
var s = o.length;
for (var a = 0; a < 18; a++) {
c += o.charAt(Math.floor(Math.random() * s));
}
return generateTimeFormat() + c;
}
3. 12个加密参数生成逻辑
- 通过
getEncryptContent方法生成4个加密参数 - 通过
getMouseAction方法生成另外8个参数
(1) getEncryptContent加密方法
- 标准DES加密算法
- 模式:ECB
- 填充:ZeroPadding
- 不需要IV
加密实现:
var CryptoJS = require("crypto-js")
function DESEncrypt(key, word) {
var key_ = CryptoJS.enc.Utf8.parse(key);
var srcs = CryptoJS.enc.Utf8.parse(word);
var encrypted = CryptoJS.DES.encrypt(srcs, key_, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.ZeroPadding
});
return encrypted.toString();
}
function DESDecrypt(key, word) {
var key_ = CryptoJS.enc.Utf8.parse(key);
var decrypt = CryptoJS.DES.decrypt(word, key_, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.ZeroPadding
});
return decrypt.toString(CryptoJS.enc.Utf8);
}
(2) 格式化检测
isJsFormat函数检测JS是否被格式化- 若检测到格式化,会导致DES Key错误,验证失败
4. 不同类型验证码的数据结构
(1) 滑块验证码(slide)
var baseData = {}
baseData.mouseData = track // 滑动轨迹 [[x,y,t],...]
baseData.startTime = 0
baseData.endTime = track[track.length - 1][2] + randomNum(100, 500)
baseData.mouseEndX = distance // 滑动距离
baseData.trueWidth = 300
baseData.trueHeight = 150
baseData.selectData = []
baseData.blockWidth = 40
滑块轨迹生成算法(Python示例):
def get_sm_track(distance):
track_length = random.randint(4, 10)
track = [[0, -2, 0]]
m = distance % track_length
e = int(distance / track_length)
for i in range(track_length):
x = (i + 1) * e + m + random.randint(20, 40)
y = -2 + (random.randint(-1, 10))
t = (i + 1) * 100 + random.randint(-3, 5)
if i == track_length - 1:
x = distance
track.append([x, y, t])
else:
track.append([x, y, t])
return track
(2) 点选类验证码
var baseData = {}
var time_ = new Date().getTime()
coordinate.forEach(function(co) {
co[0] = co[0] / 300
co[1] = co[1] / 150
co[2] = time_
time_ += randomNum(100, 500)
})
baseData.mouseData = coordinate
baseData.startTime = time_ - randomNum(800, 20000)
baseData.endTime = coordinate[coordinate.length - 1][2]
baseData.mouseEndX = 0
baseData.trueWidth = 300
baseData.trueHeight = 150
baseData.selectData = coordinate
baseData.blockWidth = undefined
(3) 无感验证码(auto_slide)
var baseData = {}
baseData.mouseData = [[0, 0, 0]]
baseData.startTime = 0
baseData.endTime = randomNum(100, 500)
baseData.mouseEndX = 260
baseData.trueWidth = 300
baseData.trueHeight = 150
baseData.selectData = []
baseData.blockWidth = 40
四、AST获取动态参数
1. 版本号规则
v1.0.4-171:v1.0.4为大版本,171为小版本- 小版本不定期更新,版本号递增
- 可通过
document.lastModified查看JS更新时间
2. 兼容版本
以下版本已验证可正常提取动态参数:
v1.0.4-148~v1.0.4-171v1.0.3-147~v1.0.3-171v1.0.1-147~v1.0.1-171
3. AST提取要点
- 提取结果是有序、未去重的
- 按索引顺序获取参数即可
- 仅提取动态参数,不还原所有混淆
五、注意事项
- DES Key:会定期变化,需动态获取
- 参数名称:12个加密参数的名称也会随版本变化
- 格式化检测:替换JS时需保持压缩格式
- 跨域问题:使用Fiddler替换时需设置
Access-Control-Allow-Origin - 版本更新:定期检查JS版本变化,更新AST解析逻辑
六、总结
本教学文档详细分析了数美验证码全家桶的逆向过程,包括:
- 接口请求流程与参数分析
- 核心加密算法与参数生成逻辑
- 不同类型验证码的数据结构差异
- 使用AST动态获取参数的方法
- 实际逆向过程中的注意事项
通过掌握这些关键点,可以有效应对数美验证码的逆向需求,实现自动化验证。