数美滑块验证码是一种常见的验证方式,用于防止自动化脚本和机器人进行恶意操作。本文将详细介绍如何使用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();