破解数美滑块验证码TypeScript


数美滑块验证码是一种常见的验证方式,用于防止自动化脚本和机器人进行恶意操作。本文将详细介绍如何使用TypeScript从抓包获取滑块图片信息、分析加密参数、生成滑动轨迹等步骤,成功破解数美滑块验证码。

1. 抓取滑块图片信息并计算滑动距离
首先,我们需要抓取滑块验证码的前景和背景图片,并计算滑块的滑动距离。使用axios库进行HTTP请求,从数美的演示页面获取图片信息。

typescript

import axios from 'axios';
import { createCanvas, loadImage } from 'canvas';

interface ImageURLs {
  fg: string;
  bg: string;
}

async function getImages(registerUrl: string): Promise<{ fgImg: HTMLImageElement; bgImg: HTMLImageElement }> {
  const response = await axios.post(registerUrl, {});
  const urls: ImageURLs = response.data;

  const fgImg = await loadImage(urls.fg);
  const bgImg = await loadImage(urls.bg);

  return { fgImg, bgImg };
}

function getDistance(fgImg: HTMLImageElement, bgImg: HTMLImageElement): number {
  const canvas = createCanvas(fgImg.width, fgImg.height);
  const context = canvas.getContext('2d');
  context.drawImage(bgImg, 0, 0);
  context.globalCompositeOperation = 'difference';
  context.drawImage(fgImg, 0, 0);

  const imageData = context.getImageData(0, 0, canvas.width, canvas.height).data;
  let minDistance = Number.MAX_VALUE;
  let xOffset = 0;

  for (let x = 0; x < canvas.width; x++) {
    let sum = 0;
    for (let y = 0; y < canvas.height; y++) {
      const index = (y * canvas.width + x) * 4;
      sum += imageData[index] + imageData[index + 1] + imageData[index + 2];
    }
    if (sum < minDistance) {
      minDistance = sum;
      xOffset = x;
    }
  }

  return xOffset;
}

async function main() {
  const registerUrl = 'https://www.ishumei.com/trial/captcha.html';
  const { fgImg, bgImg } = await getImages(registerUrl);
  const distance = getDistance(fgImg, bgImg);

  console.log('Calculated distance:', distance);
}

main();
2. 分析加密参数
通过抓包和分析网络请求,我们发现滑块验证的fverify接口需要加密的参数。经过断点调试和代码分析,我们确定这些参数是通过DES加密实现的。以下是使用Node.js的crypto模块进行DES加密的代码示例:

typescript

import crypto from 'crypto';

function pad(data: Buffer, blockSize: number): Buffer {
  const paddingSize = blockSize - (data.length % blockSize);
  const padding = Buffer.alloc(paddingSize, 0);
  return Buffer.concat([data, padding]);
}

function encryptContent(message: string, key: string, flag: boolean): string {
  const des = crypto.createCipheriv('des-ecb', Buffer.from(key, 'utf8'), null);
  const paddedMessage = pad(Buffer.from(message, 'utf8'), des.getBlockSize());
  const encrypted = des.update(paddedMessage) + des.final();
  return Buffer.from(encrypted).toString('base64');
}

const message = 'Hello, World!';
const key = 'your_key_here';
const encryptedMessage = encryptContent(message, key, true);
console.log('Encrypted message:', encryptedMessage);
3. 生成滑动轨迹并进行DES加密
我们需要生成一个模拟用户滑动行为的轨迹,包括随机的抖动和速度变化。以下是生成滑动轨迹的代码示例:

typescript

import { randomInt } from 'crypto';

interface TrackPoint {
  x: number;
  y: number;
  t: number;
}

function getRandomTrack(distance: number): { track: TrackPoint[]; dy: number } {
  const track: TrackPoint[] = [{ x: 0, y: 0, t: 0 }];
  
  for (let i = 0; i < 10; i++) {
    const x = 0;
    const y = randomInt(-1, 2);
    const t = 100 * (i + 1) + randomInt(0, 3);
    track.push({ x, y, t });
  }
  
  for (let i = 1; i < track.length - 5; i++) {
    track[i].x = Math.floor(distance / 2);
  }
  
  for (let i = track.length - 5; i < track.length - 1; i++) {
    track[i].x = distance + randomInt(1, 5);
  }
  
  track[track.length - 1].x = distance;
  
  console.log('Slide track:', JSON.stringify(track));
  return { track, dy: track[track.length - 1].t };
}

const distance = 100; // 假设滑动距离为100
const { track, dy } = getRandomTrack(distance);
console.log('Generated slide track:', track);
console.log('Slide time:', dy);
4. 验证破解结果
结合以上步骤,以下是完整的TypeScript代码示例,用于模拟滑块破解的过程:

typescript

import axios from 'axios';
import { createCanvas, loadImage } from 'canvas';
import crypto from 'crypto';
import { randomInt } from 'crypto';

interface ImageURLs {
  fg: string;
  bg: string;
}

interface TrackPoint {
  x: number;
  y: number;
  t: number;
}

async function getImages(registerUrl: string): Promise<{ fgImg: HTMLImageElement; bgImg: HTMLImageElement }> {
  const response = await axios.post(registerUrl, {});
  const urls: ImageURLs = response.data;

  const fgImg = await loadImage(urls.fg);
  const bgImg = await loadImage(urls.bg);

  return { fgImg, bgImg };
}

function getDistance(fgImg: HTMLImageElement, bgImg: HTMLImageElement): number {
  const canvas = createCanvas(fgImg.width, fgImg.height);
  const context = canvas.getContext('2d');
  context.drawImage(bgImg, 0, 0);
  context.globalCompositeOperation = 'difference';
  context.drawImage(fgImg, 0, 0);

  const imageData = context.getImageData(0, 0, canvas.width, canvas.height).data;
  let minDistance = Number.MAX_VALUE;
  let xOffset = 0;

  for (let x = 0; x < canvas.width; x++) {
    let sum = 0;
    for (let y = 0; y < canvas.height; y++) {
      const index = (y * canvas.width + x) * 4;
      sum += imageData[index] + imageData[index + 1] + imageData[index + 2];
    }
    if (sum < minDistance) {
      minDistance = sum;
      xOffset = x;
    }
  }

  return xOffset;
}

function pad(data: Buffer, blockSize: number): Buffer {
  const paddingSize = blockSize - (data.length % blockSize);
  const padding = Buffer.alloc(paddingSize, 0);
  return Buffer.concat([data, padding]);
}

function encryptContent(message: string, key: string, flag: boolean): string {
  const des = crypto.createCipheriv('des-ecb', Buffer.from(key, 'utf8'), null);
  const paddedMessage = pad(Buffer.from(message, 'utf8'), des.getBlockSize());
  const encrypted = des.update(paddedMessage) + des.final();
  return Buffer.from(encrypted).toString('base64');
}

function getRandomTrack(distance: number): { track: TrackPoint[]; dy: number } {
  const track: TrackPoint[] = [{ x: 0, y: 0, t: 0 }];
  
  for (let i = 0; i < 10; i++) {
    const x = 0;
    const y = randomInt(-1, 2);
    const t = 100 * (i + 1) + randomInt(0, 3);
    track.push({ x, y, t });
  }
  
  for (let i = 1; i < track.length - 5; i++) {
    track[i].x = Math.floor(distance / 2);
  }
  
  for (let i = track.length - 5; i < track.length - 1; i++) {
    track[i].x = distance + randomInt(1, 5);
  }
  
  track[track.length - 1].x = distance;
  
  console.log('Slide track:', JSON.stringify(track));
  return { track, dy: track[track.length - 1].t };
}

async function main() {
  const registerUrl = 'https://www.ishumei.com/trial/captcha.html';
  const {
ChatGPT 说:
ChatGPT
fgImg, bgImg } = await getImages(registerUrl);
const distance = getDistance(fgImg, bgImg);
const { track, dy } = getRandomTrack(distance);

console.log('Calculated distance:', distance);
console.log('Generated slide track:', track);
console.log('Slide time:', dy);

// Encrypt track data for verification (example key, adjust as needed)
const key = 'your_key_here';
const encryptedTrack = encryptContent(JSON.stringify(track), key, true);
console.log('Encrypted track:', encryptedTrack);
}

main();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值