【验证码逆向专栏】安某客滑块逆向
字数 757 2025-08-11 08:35:55

安某客滑块验证码逆向分析教学文档

一、目标分析

目标网站:安某客滑动验证码系统
验证类型:滑块验证码
主要流程

  1. 请求首页获取sessionId
  2. 请求getInfoTp获取图片信息和responseId
  3. 请求checkInfoTp校验滑动结果
  4. 涉及加密参数:dInfo和data,以及info的解密

二、加密参数分析

1. dInfo参数生成

位置:getInfoTp请求的Form Data中
加密方式:AES加密
加密内容:包含设备信息的JSON对象
密钥生成:从sessionId中提取奇数位字符作为AES的key和iv

JavaScript实现代码:

function AESEncrypt(_cRV, _2undefinedp) {
    _2undefinedp = _2undefinedp.split("").reduce(function(_PUi, _JrX, _JP9) {
        return _JP9 % 2 == 0 ? _PUi : _PUi + _JrX;
    }, "");
    _2undefinedp = CryptoJS.enc.Utf8.parse(_2undefinedp);
    _cRV = "string" == typeof _cRV ? _cRV : JSON.stringify(_cRV);
    _cRV = CryptoJS.AES.encrypt(_cRV, _2undefinedp, {
        iv: _2undefinedp,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    return encodeURIComponent(_cRV.toString());
}

function getDInfo(sessionId) {
    const deviceInfo = {
        "sdkv": "3.0.1",
        "busurl": "https://目标网站.com/captcha-verify/",
        "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
        "clienttype": "1"
    };
    return AESEncrypt(deviceInfo, sessionId);
}

Python实现代码:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import base64
import json
from urllib.parse import quote_plus

class AESAlgorithm:
    @staticmethod
    def encrypt(aes_key_iv, text):
        cipher = AES.new(
            key=bytes(aes_key_iv, encoding='utf-8'),
            mode=AES.MODE_CBC,
            iv=bytes(aes_key_iv, encoding='utf-8')
        )
        result = base64.b64encode(cipher.encrypt(pad(text.encode('utf-8'), 16))).decode('utf-8')
        return quote_plus(result)

def get_aes_key_iv(session_id):
    return ''.join([char for idx, char in enumerate(session_id) if idx % 2 != 0])

def get_d_info(session_id):
    sdk_info = {
        "sdkv": "3.0.1",
        "busurl": "https://目标网站.com/captcha-verify/",
        "useragent": "Mozilla/5.0...",
        "clienttype": 1
    }
    aes_key_iv = get_aes_key_iv(session_id)
    return AESAlgorithm().encrypt(aes_key_iv, json.dumps(sdk_info))

2. info参数解密

位置:getInfoTp接口返回的info字段
解密方式:AES解密
密钥:与dInfo相同,使用sessionId生成的key和iv

JavaScript解密代码:

function AESDecrypt(encryptedData, sessionId) {
    const key_iv = sessionId.split("").reduce((acc, char, idx) => {
        return idx % 2 === 0 ? acc : acc + char;
    }, "");
    const key = CryptoJS.enc.Utf8.parse(key_iv);
    const iv = key;
    
    const decrypted = CryptoJS.AES.decrypt(
        decodeURIComponent(encryptedData),
        key,
        { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }
    );
    
    return JSON.parse(decrypted.toString(CryptoJS.enc.Utf8));
}

3. data参数生成

位置:checkInfoTp请求的Form Data中
组成

  • x:水平滑动距离
  • track:滑动轨迹
  • p:固定值

加密方式:AES加密,与dInfo相同

轨迹生成方法

def generate_track(distance):
    """基于样本轨迹生成新轨迹"""
    ratio = distance / 126  # 样本距离为126
    new_track = []
    base_track = [
        [29,11,0], [29,11,11], [29,11,26], [33,11,56], 
        # 更多轨迹点...
        [155,20,1717]
    ]
    
    for point in base_track:
        new_x = int(point[0] * ratio)
        new_time = int(point[2] * ratio)
        new_track.append(f"{new_x},{point[1]},{new_time}")
    
    return "|".join(new_track)

三、关键实现步骤

1. 获取sessionId

import requests
from lxml import etree

def get_session_id():
    url = "https://目标网站.com/captcha-verify/"
    response = requests.get(url)
    html = etree.HTML(response.text)
    return html.xpath("//input[@name='sessionId']/@value")[0]

2. 获取滑块图片信息

def get_slide_info(session_id):
    url = "https://目标网站.com/api/getInfoTp"
    d_info = get_d_info(session_id)
    
    response = requests.post(url, data={"dInfo": d_info})
    encrypted_info = response.json()["info"]
    
    # 解密info获取图片URL等信息
    aes_key_iv = get_aes_key_iv(session_id)
    slide_info = AESAlgorithm().decrypt(aes_key_iv, encrypted_info)
    return json.loads(slide_info), response.json()["responseId"]

3. 识别缺口距离

import cv2
import numpy as np

def get_slide_distance(bg_url, slice_url):
    # 下载背景图和滑块图
    bg_img = download_image(bg_url)
    slice_img = download_image(slice_url)
    
    # 缩放图片到原始尺寸(480×270)
    bg_img = cv2.resize(bg_img, (480, 270))
    slice_img = cv2.resize(slice_img, (480, 270))
    
    # 使用模板匹配识别缺口位置
    result = cv2.matchTemplate(bg_img, slice_img, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
    
    # 计算实际滑动距离(考虑渲染缩放比例0.5833)
    distance = max_loc[0] * 0.5833
    return distance

4. 提交验证

def submit_verify(session_id, response_id, distance):
    url = "https://目标网站.com/api/checkInfoTp"
    
    # 生成轨迹
    track = generate_track(distance)
    
    # 构造请求数据
    request_data = {
        "x": distance,
        "track": track,
        "p": 1
    }
    
    # AES加密
    aes_key_iv = get_aes_key_iv(session_id)
    encrypted_data = AESAlgorithm().encrypt(aes_key_iv, json.dumps(request_data))
    
    # 提交验证
    response = requests.post(url, data={
        "data": encrypted_data,
        "sessionId": session_id,
        "responseId": response_id
    })
    
    return response.json()

四、注意事项

  1. 图片缩放处理:原始图片尺寸480×270px,渲染后280×158px,比例约1:0.5833
  2. 轨迹生成:可以使用缩放法,基于真实轨迹样本调整
  3. 加密一致性:所有加密使用相同的AES参数(CBC模式,PKCS7填充)
  4. 密钥生成:从sessionId中提取奇数位字符作为key和iv
  5. 请求顺序:必须按sessionId→getInfoTp→checkInfoTp顺序调用

五、完整流程示例

# 1. 获取sessionId
session_id = get_session_id()

# 2. 获取滑块信息
slide_info, response_id = get_slide_info(session_id)
bg_url = slide_info["bg"]
slice_url = slide_info["slice"]

# 3. 识别缺口距离
distance = get_slide_distance(bg_url, slice_url)

# 4. 生成轨迹并提交验证
result = submit_verify(session_id, response_id, distance)

if result.get("success"):
    print("验证成功")
else:
    print("验证失败")
安某客滑块验证码逆向分析教学文档 一、目标分析 目标网站 :安某客滑动验证码系统 验证类型 :滑块验证码 主要流程 : 请求首页获取sessionId 请求getInfoTp获取图片信息和responseId 请求checkInfoTp校验滑动结果 涉及加密参数:dInfo和data,以及info的解密 二、加密参数分析 1. dInfo参数生成 位置 :getInfoTp请求的Form Data中 加密方式 :AES加密 加密内容 :包含设备信息的JSON对象 密钥生成 :从sessionId中提取奇数位字符作为AES的key和iv JavaScript实现代码: Python实现代码: 2. info参数解密 位置 :getInfoTp接口返回的info字段 解密方式 :AES解密 密钥 :与dInfo相同,使用sessionId生成的key和iv JavaScript解密代码: 3. data参数生成 位置 :checkInfoTp请求的Form Data中 组成 : x:水平滑动距离 track:滑动轨迹 p:固定值 加密方式 :AES加密,与dInfo相同 轨迹生成方法 三、关键实现步骤 1. 获取sessionId 2. 获取滑块图片信息 3. 识别缺口距离 4. 提交验证 四、注意事项 图片缩放处理 :原始图片尺寸480×270px,渲染后280×158px,比例约1:0.5833 轨迹生成 :可以使用缩放法,基于真实轨迹样本调整 加密一致性 :所有加密使用相同的AES参数(CBC模式,PKCS7填充) 密钥生成 :从sessionId中提取奇数位字符作为key和iv 请求顺序 :必须按sessionId→getInfoTp→checkInfoTp顺序调用 五、完整流程示例