**声明:**本文仅作技术交流,严禁用于任何非法用途(如有冒犯,请联系我删除此文)
顶象验证码
type类型:
0.滑块
1.文字点选
2.刮刮乐
3.图标识别:图标点选
4.空间语义:点击三角形
5.语序点选:按语序依次点击
6.乱序拼图
7.旋转验证
8.面积验证
9.语言识别
10.差异点击:不同图案或文字
12.字体识别:选择不同风格的字体
13.滑动还原
分为私有版本和公共版本,私有版本的js不会变化,这里以滑块为例
1.加载
2.流程分析
2.1 引用 constid-js/index.js?_t=
每日会变两次,主要是get_c 加密算法,通过ast和基础的补环境,可以定位到加密方法,并且导出加密方法
2.2 引用 ctu-greenseer/greenseer.js?_t=
每日会变两次,主要是轨迹算法会改变,直接通过补环境生成ac轨迹参数
2.3 请求api/a?
参数:
https://cap.dingxiang-inc.com/api/a?
w=300 宽
h=150 高
s=50 应该是按钮
ak=73360ce3e32b708eb1a2a95602a614fe apiKey
c=669f75e7FcI7M330PgZPDwaJwObHZqmHrK3akEm1 客户端c
jsv=1.5.44.2 js版本
aid=dx-1721726464301-53773798-1 时间戳+随机数
wp=1 请求图片格式0是png,1是wepg
de=0
lf=0
cid=11484111 客户端id
_r=0.5289396790558949 随机数
返回值:
{
"sid": "2f0e3af4361962bd0fa0383412e1d403",
"cid": "11484111",
"y": 41,
"p1": "/customiz/wupE6GtgUX/zib3/e12ec5f8a45d4ad399538a84a0280d39.webp",
"p2": "/customiz/wupE6GtgUX/zib3/23d470178a234c68a4e40a36d10fc4b7.webp",
"p3": null,
"type": 0,
"logo": "/captcha-custom-image/cf4afa73946b46168210b9f02d5db480.png",
"logoSwitch": 1,
"tp1": null,
"cw": null,
"sc1": null,
"icons": null,
"verifyType": null,
"childVerifyType": null,
"imgName": null,
"color": null,
"chs": null,
"ot": 0,
"tk1": null,
"speed1": 0.0,
"speed2": 0.0,
"bgUrl": null,
"sliderUrl": null,
"sliderBarUrl": null,
"extra": null,
"success": true,
"msg": null,
"t": null,
"result": 1,
"bc": null
}
2.4 请求/api/v1
https://cap.dingxiang-inc.com/api/v1
ac=4380%23j2XnQGHDtkv5IhS3XX4vJROa%2Fy3jm2mW8T%2FSjEVS43CpfrQ4kLVgYYoSsTZpsL21ZE3eu65KFXTpnYgUsNngXLnEUM%2FEij9nILy03trpfT3yFtWmiY503trEn3rEnESYPEyeYE7EiCgJihoisAIA3t2CRAWUXXHdiFWnfw37YrXmSX%2FXmUDc7J%2FhXXTHD9bBXrXEbbJMVs6u5nFAVpk85fJtrUUY7ZJMVehuQ4Rz9kPh7bjLC8IXuXJXmjrPrX88XXXXXXJXX7WPrX88mrXi5WvcZhvpmiImqrrXsBD9uJ2ctraSbH%2FdUdwli20gFYQGYKSkYttsiKSop5oGhMwPEgQeMb0ePIospKSnYrXmSXfXsJPYOg%2FEq28KXWcCfuqZCjwag%2FdmFe8yOqLOAQoQaV373VKIDWfs5V0EBBOzoXfXsJPYfXfcC8TuXWcCfuqZCjwag%2FdmFe8yOqLOAQoQaV373VKIDWfs5V0EBBOzoXVXY1Cy4ig2U%2FSXj8Xn%2B1TVLjX7hrXZXXCSOPRdIXTiXXVXY1Cy4F22X%2FSZj8Xn%2B1TV7wXvhrVZXXCSOPRoImvijXVXY1Cy4ZW21VSij8Xn%2B1TVdwjphrSZXXCSOPR1IFZiYrVXY1Cy4Ig2M%2FSij8Xn%2B1T9IwjuhrSZXXCSOP%2FdIIbiYrVXY1Cy4Rg2V%2FSij8Xn%2B1T9vwj%2BhrSZXXCSOP%2F0IiviYrVXY1Cy4TX2SySij8Xn%2B1T9uLYxhrSZXXCSOP%2FHIs4iYrVXY1Cy48f20ySij8Xn%2B1T9jwY7hryZXXCSOPaNInOiY8VXY1Cy4Dg2r%2FSnj8Xn%2B1T9OLYjhrrZXXCSOPa0InbiYXVXY1Cy4aW2E%2Fxdj8Xn%2B1T9DwYihzWZXXCSOPaPInxi42VXY1Cy4%2Fg2EVxdj8Xn%2B1T9QjYshzWZXXCSOPDpIvTi42VXY1Cy44r2c3xdj8Xn%2B1TtZwYahzWZXXCSOPnBIvOi4rVXY1CyWE%2F2y3xNj8Xn%2B1TtsLYThzfZXXCSOPn%2FIvZi4rVXY1CyWCg2yVxNj8Xn%2B1TtmLYWhzfZXXCSOPvdIv9i4rVXY1CyWz22zyxNj8Xn%2B1TtHRYJhzfZXXCSOPvzIvbi4rVXY1CyWAg2A3xNj8Xn%2B1TtDwYOhzfZXXCSOPiBIvxi4rVXY1CyWxW2AVxNj8Xn%2B1TtrjYkhzfZXXCSOPiPZNTi4rVXY1CyW03dO3xNj8Xn%2B1TtBw4chzfZXXCSOPs6ZNai4rVXY1CyWQfdOyxNj8Xn%2B1Ttww4zhzfZXXCSOPIdZN4i4rVXY1CyWt8dOVxNj8Xn%2B1TwPw4rhzfZXXCSOPIFZNui4rVXY1CyWNWdfyxNj8Xn%2B1TwTw4LhzfZXXCSOPZnZNZi4rVXY1CyWqfdk3xNj8Xn%2B1TwcL4ohz%2FZXXCSOPFBZNMi48VXY1CyWbIdk%2Fx9j8Xn%2B1TwdL4phz%2FZXXCSOPF4ZN7i48VXY1CyWjWdkVxNj8Xn%2B1T2Wj40hzfZXXCSOPmrZNbi4rVXY1CyWv8dkVxNj8Xn%2B1T2Nw40hzfZXXCSOPjHZNCi4rVXY1CyWRrd%2B3xNj8Xn%2B1TMkw4ShzfZXXCSOPuWZNCi4r3X7XdCWh9Kfz7zkEVVsaMEHA4pshIQ%2B6T0WVapO6MKftVVULyKFRfLs6Zp%2BAbukAaoHAIQZjgKFLodFYIQWzxlHAIQZYVrfd7AOtmxO1bwn1bEHYVLsDnQZjgNUtIQWtVVUwWLs6v7DPCBJD7pktVVHzCBkEIQkDClk1OpOD5QZYVlFyrlF%2Fx0fz2lFj7EktSbRhSgF1bt%2BDbKHATciL2giL2K%2B14lJDylF%2FVlFjM0Wc4S%2BzxK%2B1ZliL2KkdvD%2B1xqHACL%2Bc4zO1x0fAaonzcKWN4pnA7A%2B670iL2KkdvD%2B1xqHArQ42%3D%3D
ak=4efbf53ceebc7b351e8d4e27114bcc83
c=669f75e7FcI7M330PgZPDwaJwObHZqmHrK3akEm1
uid=
jsv=1.5.44.2
sid=fae0ece4461f52caf3fcf10a32dc573f
aid=dx-1721729209168-20039217-1
x=185
y=59
需要自己生成的是:x、轨迹数组
js内容主要是:
1.执行
let init = window._dx.UA.init( {“token”: sid});
2.触发滑动事件
触发滑块事件mousedown
触发滑块事件mousemove,并传入轨迹
3.执行
init.sendSA()
init.sendTemp({xpath: divPath, x: x, y: y});
3.参数分析
clickword-Captcha-js.js和basic-Captcha-js.js 还有greenseer.js 这三个js好像都是从captcha-ui/index.js中引用的
分析加密时,只需要反混greenseer.js文件就行
3.1 c参数
是设备指纹参数,从constid-js/index.js加密请求生成的,需要经过两次c请求,然后返回
解决方法:
1.只要找到加密方法,就能直接使用算法生成,使用ast,可以快速找到加密方法,分析加密参数
2.通过补环境,自动发送两次c1请求,就能生成,如果混淆得很厉害,就使用这种方案
3.2 图片还原
1.还原算法:通过hook canvas的图片拼接函数,可以快速得到算法步骤
2.通过扣js补环境执行canvas 的方式,还原图片,适合js代码无法还原的情况,应该很少用
3.3 计算坐标
将背景和图片都进行灰度化处理:
def handle_img(self, path, threshold1, threshold2):
img = cv2.imread(path)
edge = cv2.Canny(img, threshold1, threshold2)
pic = cv2.cvtColor(edge, cv2.COLOR_GRAY2BGR)
return pic
def get_distance(self, fg_path, bg_path):
# 对滑块进行图片处理
fg_pic = self.handle_img(fg_path, 1000, 200)
# 对背景进行图片处理
bg_pic = self.handle_img(bg_path, 1000, 200)
# 使用【相关系数匹配 和 归一化相关系数匹配】
methods = ["cv2.TM_CCOEFF", "cv2.TM_CCOEFF_NORMED"]
results = {}
move = 0
for meth in methods:
# 模板匹配matchTemplate
res = cv2.matchTemplate(bg_pic.copy(), fg_pic, eval(meth))
loc = cv2.minMaxLoc(res)[3] # 左上角点的位置:最大值的索引位置
results[meth] = loc # 方便测试
move = loc[0] # 左边方框距离
# 绘制方框【方便查看】
th, tw = fg_pic.shape[:2]
bottom_right = (loc[0] + tw, loc[1] + th) # 右下角点的坐标
cv2.rectangle(bg_pic, loc, bottom_right, (0, 0, 225), 2) # 绘制矩形
cv2.imshow("bg_img.png", bg_pic)
cv2.waitKey(0)
logger.debug(f"匹配参数: {results}: 移动距离:{move}")
distance = math.floor((move + 34) * 3 / 4) - 24
return distance
3.4 生成事件
轨迹算法生成涉及参数比较多,并且算法每天都会改变,所以采用补环境的方式,生成轨迹算法
流程:初始化、执行轨迹事件、执行加密(每种类型的验证码可能不一样)、发送模板(sendTem每种类型的值可能不同)
初始化:统一都是window._dx.UA.init(token)
事件触发,通过hook 事件的执行,来观察触发了哪些事件:
// 保存原始的 addEventListener 方法
const originalAddEventListener = EventTarget.prototype.addEventListener;
// 重写 addEventListener 方法
Object.defineProperty(EventTarget.prototype, 'addEventListener', {
value: function(type, callback, options) {
console.log("绑定事件:", type.toLowerCase(), this);
const wrappedCallback = function(event) {
console.log("执行事件:", type.toLowerCase(), this);
callback.call(this, event);
};
originalAddEventListener.call(this, type, wrappedCallback, options);
},
configurable: true,
enumerable: true,
writable: true
});