吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2576|回复: 9
上一主题 下一主题
收起左侧

[Web逆向] 数美滑动验证码逆向

  [复制链接]
跳转到指定楼层
楼主
13955925361 发表于 2025-9-11 23:26 回帖奖励
本帖最后由 13955925361 于 2025-9-11 23:31 编辑

数美的滑块是一个标准的DES加密,其中轨迹参考了下雨天视频中K哥的教程,
我自己用ai也写了个轨迹函数,通过率没有那么高就是了,所以我给注释掉了。


第一个接口返回两张图片和一个rid参数给下个接口用。下个验证接口有gg,hg,th三个参数需要逆向。

      


直接关键词搜gg,hg,th,定位到滑块验证码位置。 点进getEncryptContent方法里,有DES关键词,经检验,是标准的,JS直接导库就好。
      

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();
}


以下我将用python代码完成验证码的还原。


            

[Python] 纯文本查看 复制代码
import requests
import re
import json
import time
import datetime
import random
import string
import execjs

def generate_timestamp_random():
    """
    生成一个由当前时间戳(YYYYMMDDHHMMSS)和随机字符串组成的字符串

    返回:
        str: 格式为"时间戳+16位随机字符"的字符串
    """
    # 获取当前时间并格式化为YYYYMMDDHHMMSS
    current_time = datetime.datetime.now()
    timestamp = current_time.strftime("%Y%m%d%H%M%S")

    # 生成16位随机字符串(包含大小写字母和数字)
    # 使用示例中的字符集:大小写字母和数字
    characters = string.ascii_letters + string.digits
    random_string = ''.join(random.choices(characters, k=16))

    # 组合时间戳和随机字符串
    return timestamp + random_string
from captcha_recognizer.recognizer import Recognizer
import logging
captchaUuid=generate_timestamp_random()

headers = {
    "Accept": "*/*",
    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    "Cache-Control": "no-cache",
    "Connection": "keep-alive",
    "Origin": "https://www.ishumei.com",
    "Pragma": "no-cache",
    "Referer": "https://www.ishumei.com/",
    "Sec-Fetch-Dest": "script",
    "Sec-Fetch-Mode": "cors",
    "Sec-Fetch-Site": "cross-site",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0",
    "sec-ch-ua": "\"Not;A=Brand\";v=\"99\", \"Microsoft Edge\";v=\"139\", \"Chromium\";v=\"139\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\""
}
url = "https://captcha1.fengkongcloud.cn/ca/v1/register"
params = {
    "appId": "default",
    "organization": "d6tpAY1oV0Kv5jRSgxQr",
    "captchaUuid": captchaUuid,
    "data": "{}",
    "channel": "default",
    "sdkver": "1.1.3",
    "rversion": "1.0.4",
    "callback": f"sm_{time.time()*1000}",
    "model": "slide",
    "lang": "zh-cn"
}
response = requests.get(url, headers=headers, params=params).text
match = re.search(r'\((\{.*\})\)',response, re.DOTALL)
if match:
    json_str = match.group(1)
    try:
        data = json.loads(json_str)
        print("提取成功:")
        print(json.dumps(data, indent=2, ensure_ascii=False))
    except json.JSONDecodeError as e:
        print("JSON 解析失败:", e)
else:
    print("未找到 JSON 数据")

bg='https://castatic.fengkongcloud.cn/'+str(data['detail']['bg'])
front='https://castatic.fengkongcloud.cn/'+str(data['detail']['fg'])


bgContent=requests.get(bg,headers=headers).content
frontContent=requests.get(front,headers=headers).content
with open ('bg.png','wb') as f:
    f.write(bgContent)
with open ('front.png','wb') as f:
    f.write(frontContent)


import cv2
import os


def get_slide_distance( bg_path, slide_path):
    bg_img = cv2.imread(bg_path)
    sd_img = cv2.imread(slide_path)

    # 获取滑块实际宽高(关键步骤)
    slide_height, slide_width = sd_img.shape[:2]  # 提取高度和宽度(忽略通道数)

    # 背景图预处理(灰度化→模糊→边缘检测→转RGB)
    bg_gray = cv2.cvtColor(bg_img, cv2.COLOR_BGR2GRAY)
    bg_gray = cv2.GaussianBlur(bg_gray, (5, 5), 0)
    bg_edge = cv2.Canny(bg_gray, 30, 100)
    rgb_bg_gray = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)

    # 滑块图预处理(与背景图处理一致)
    sd_gray = cv2.cvtColor(sd_img, cv2.COLOR_BGR2GRAY)
    sd_gray = cv2.GaussianBlur(sd_gray, (5, 5), 0)
    sd_edge = cv2.Canny(sd_gray, 30, 100)
    rgb_sd_gray = cv2.cvtColor(sd_edge, cv2.COLOR_GRAY2RGB)

    # 模板匹配
    result = cv2.matchTemplate(rgb_bg_gray, rgb_sd_gray, cv2.TM_CCORR_NORMED)
    _, _, _, max_loc = cv2.minMaxLoc(result)

    # 用滑块真实宽高标记矩形(核心修改处)
    # 右下角坐标 = 左上角坐标 + 滑块宽高
    cv2.rectangle(
        bg_img,
        (max_loc[0], max_loc[1]),  # 左上角
        (max_loc[0] + slide_width, max_loc[1] + slide_height),  # 右下角(动态计算)
        (0, 255, 0),  # 绿色
        2  # 线宽
    )

    # 保存结果图
    result_path = os.path.join(os.path.dirname(bg_path), "result.png")
    cv2.imwrite(result_path, bg_img)

    # 返回滑动距离(滑块左上角x坐标)
    return max_loc[0]


distance= get_slide_distance('bg.png','front.png')
print(f"滑块需要滑动的距离是: {distance}px")
result_distance=distance/2
print(result_distance)
rid=data['detail']['rid']
print(rid)



with open('数美滑块.js', 'r', encoding='utf-8')as f:
    js_code = f.read()
ctx=execjs.compile(js_code)

num=result_distance/300
print(num)
gg=ctx.call('DESEncrypt',"5129c2c2",num)
print(gg)


# def generate_slider_trace(distance):
#     """
#     生成符合规律的滑块轨迹:
#     - x轴:过冲→回调→稳定
#     - y轴:小幅向下抖动,中间回调
#     - z轴:稳定递增(每次+100±10)
#     - 点数:≈ distance × 0.25~0.3
# #
# #     参数:
# #         distance: 目标滑动距离(如122)
# #
# #     返回:
# #         list: 轨迹列表[[x, y, z], ...]
# #     """
# #     # 初始化轨迹起点
#     x = [0]
#     y = [0]
#     z = [0]
#
#     # 计算总点数(0.25x~0.3x)
#     total_points = int(distance * random.uniform(0.25, 0.3))
#     # 分配各阶段点数(按规律比例)
#     accelerate_points = int(total_points * 0.15)  # 加速阶段(15%)
#     overshoot_points = 1  # 过冲点(固定1个)
#     callback_points = int(total_points * 0.1)  # 回调阶段(10%)
#     adjust_points = int(total_points * 0.2)  # 微调阶段(20%)
#     stable_points = total_points - (accelerate_points + overshoot_points + callback_points + adjust_points)  # 稳定阶段(剩余)
# #
# #     # -------------------- 1. X轴轨迹生成 --------------------
#     # 阶段1:加速增长(快速接近目标)
#     prev_x = 0
#     for _ in range(accelerate_points):
#         # 加速阶段:每次增量逐渐增大(模拟加速)
#         ratio = _ / max(1, accelerate_points - 1)  # 0~1
#         delta = int(distance * 0.05 + distance * 0.6 * ratio)  # 从慢到快
#         prev_x += delta
#         x.append(prev_x)
# #
#     # 阶段2:过冲(超过目标值5%~15%)
#     overshoot_ratio = random.uniform(0.05, 0.15)
#     overshoot_x = distance + int(distance * overshoot_ratio)
#     x.append(overshoot_x)
#
#     # 阶段3:回调(从过冲值降到目标值下方5%~10%)
#     callback_target = distance - int(distance * random.uniform(0.05, 0.1))
#     step = (overshoot_x - callback_target) // callback_points
#     current_x = overshoot_x
#     for _ in range(callback_points):
#         current_x -= step
#         x.append(current_x)
#
#     # 阶段4:微调(从目标下方逐步接近目标)
#     current_x = x[-1]
#     for _ in range(adjust_points):
#         delta = random.randint(1, 3)
#         current_x += delta
#         if current_x >= distance:
#             current_x = distance
#         x.append(current_x)
#
#     # 阶段5:稳定(保持在目标值)
#     x.extend([distance] * stable_points)
#
#     # 截断/补充至总点数(避免计算误差)
#     x = x[:total_points]
# #
# #     # -------------------- 2. Y轴轨迹生成 --------------------
#     # 阶段1:初期抖动(幅度逐渐增大)
#     current_y = 0
#     for i in range(min(5, len(x) // 3)):  # 前1/3轨迹
#         delta = random.randint(-3, -1)  # 向下抖动
#         current_y += delta
#         y.append(current_y)
# #
#     # 阶段2:中期回调(向上调整)
#     for i in range(min(3, len(x) // 4)):  # 中间1/4轨迹
#         delta = random.randint(1, 3)  # 向上回调
#         current_y += delta
#         if current_y > 0:
#             current_y = 0  # 不超过0
#         y.append(current_y)
# #
#     # 阶段3:后期稳定(小幅向下后保持)
#     remaining = len(x) - len(y)
#     for _ in range(remaining):
#         if current_y > -5:  # 限制最低值
#             delta = random.choice([-1, -1, 0])
#         else:
#             delta = random.choice([0, 0, 1])
#         current_y += delta
#         y.append(current_y)
# #
# #     # -------------------- 3. Z轴轨迹生成 --------------------
#     # 每次增量100±10,稳定递增
#     current_z = 0
#     for _ in range(len(x) - 1):
#         increment = random.randint(90, 110)  # 100±10
#         current_z += increment
#         z.append(current_z)
#
#     # 组合轨迹
#     trace = [list(point) for point in zip(x, y, z)]
#     return trace
#
# trace = generate_slider_trace(result_distance)
# print(trace)
# hg=ctx.call('DESEncrypt',"be221ccf",str(trace))
# print(hg)
# time_diff=round(int(result_distance)*3181/107)
# #
# print(f"滑块滑动时间差为: {time_diff}ms")
# th=ctx.call('DESEncrypt',"231a540d",time_diff)
# print(th)



import numpy as np
import math

def get_track(distance):
    x = [0, 0]
    y = [0, 0, 0]
    z = [0]

    count = np.linspace(-math.pi / 2, math.pi / 2, random.randrange(20, 30))
    func = list(map(math.sin, count))
    nx = [i + 1 for i in func]
    add = random.randrange(10, 15)
    sadd = distance + add

    x.extend(list(map(lambda x: x * (sadd / 2), nx)))
    x.extend(np.linspace(sadd, distance, 3 if add > 12 else 2))
    x = [math.floor(i) for i in x]

    for i in range(len(x) - 2):
        if y[-1] < 30:
            y.append(y[-1] + random.choice([0, 0, 1, 1, 2, 2, 2, 1, 2, 0, 0, 3, 3]))
        else:
            y.append(y[-1] + random.choice([0, 0, -1, -1, -2, -2, -1, -2, -1, -2, 0, 0, -3, -3]))

    for i in range(len(x) - 1):
        z.append((z[-1] // 100 * 100) + 100 + random.choice([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2]))

    trace = list(map(list, zip(x, y, z)))
    times = trace[-1][-1] + random.randint(1, 5)

    # logger.info(f'模拟的轨迹--->>>{trace}')
    # logger.info(f'times--->>>{times}')

    return trace, times


trace,times=get_track(result_distance)
print(trace)
print( times)
hg=ctx.call('DESEncrypt',"be221ccf",str(trace))
print(hg)
th=ctx.call('DESEncrypt',"231a540d",times)
print(th)
#
#
# # 测试:生成目标距离为182的轨迹
# #
# #
params = {
    "to": "bftazdO+dKs=",
    "ny": "cvSxP/Xnulg=",
    "callback": f"sm_{round(time.time()*1000)}",
    "bs": "ZGIsKZZObiI=",
    "fm": "BNYA+9sHvZU=",
    "act.os": "web_pc",
    "captchaUuid": captchaUuid,
    "lf": "LCntkg8Oqr0=",
    "protocol": "185",
    "sl": "ld3hnK7eLbY=",
    "rid": rid,
    "qt": "QcZFnVbE0HA=",
    "sdkver": "1.1.3",
    "rversion": "1.0.4",
    "yh": "wFVE7H+kToU=",
    "ostype": "web",
    "bq": "1szrpYdSRZQ=",
    "organization": "d6tpAY1oV0Kv5jRSgxQr",
    'gg':gg,
    'hg': hg,
    'th':th,
}
print(params)

url_2 = "https://captcha1.fengkongcloud.cn/ca/v2/fverify"
headers_2= {
    "Accept": "*/*",
    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    "Cache-Control": "no-cache",
    "Connection": "keep-alive",
    "Origin": "https://www.ishumei.com",
    "Pragma": "no-cache",
    "Referer": "https://www.ishumei.com/",
    "Sec-Fetch-Dest": "script",
    "Sec-Fetch-Mode": "cors",
    "Sec-Fetch-Site": "cross-site",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0",
    "sec-ch-ua": "\"Chromium\";v=\"140\", \"Not=A?Brand\";v=\"24\", \"Microsoft Edge\";v=\"140\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\""
}
response_2 = requests.get(url_2, headers=headers_2, params=params)

print(response_2.text)


最终输出效果为pass代表通过。






QQ20250911-232010.png (716.05 KB, 下载次数: 2)

QQ20250911-232010.png

QQ20250911-232121.png (48.79 KB, 下载次数: 3)

QQ20250911-232121.png

QQ20250911-231924.png (717.05 KB, 下载次数: 3)

QQ20250911-231924.png

免费评分

参与人数 6威望 +1 吾爱币 +25 热心值 +5 收起 理由
ioyr5995 + 1 + 1 热心回复!
allspark + 1 + 1 用心讨论,共获提升!
涛之雨 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
xueren114 + 1 + 1 我很赞同!
gongjiankk + 1 用心讨论,共获提升!
liuxuming3303 + 1 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
dhsfb 发表于 2025-9-12 08:42
向牛人学习,不断进步
3#
18382747915 发表于 2025-9-12 09:10
发现最好用的还是中文字符验证码,破解成本高得离谱
4#
shanhu5235 发表于 2025-9-12 11:10
5#
lzk1 发表于 2025-9-12 11:42
感谢楼主分享
6#
艾莉希雅 发表于 2025-9-12 16:09
数美有一个靶场,虽然基本上都被干爆了,人手拿捏,但还是很有教学示范意义的
https://castatic.fengkongcloud.cn/pr/v1.0.4/demo.html

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
anning666 + 1 + 1 热心回复!

查看全部评分

7#
weiwei9 发表于 2025-9-12 17:23
感谢楼主分享
8#
DsYs 发表于 2025-9-12 17:38
学习一下,感觉分享
9#
杜海涛 发表于 2025-9-13 14:02
发现最好用的还是中文字符验证码,破解成本高得离谱
10#
johnny880730 发表于 2025-10-9 14:34
感谢分享,开始学习
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-2-9 03:28

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表