数美滑块验证码是一种常见的安全验证方式,用于防止自动化脚本和机器人进行恶意操作。本文将详细介绍如何通过抓包获取滑块图片信息、分析加密参数、生成滑动轨迹等步骤,成功破解数美滑块验证码。以下是我们要实现的主要步骤:
抓取滑块图片信息并计算滑动距离
分析加密参数
生成滑动轨迹并进行DES加密
验证破解结果
1. 抓取滑块图片信息并计算滑动距离
首先,进入数美滑块验证码的演示页面,进行抓包操作以获取滑块验证码的前景和背景图片。我们通过HttpClient从网站获取图片:
java
import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.core.Core;
public class CaptchaBreaker {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void main(String[] args) throws Exception {
String registerUrl = "https://www.ishumei.com/trial/captcha.html";
var images = getImages(registerUrl);
Mat fg = images[0];
Mat bg = images[1];
int distance = getDistance(fg, bg);
System.out.println("Calculated distance: " + distance);
}
public static Mat[] getImages(String registerUrl) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(registerUrl))
.POST(HttpRequest.BodyPublishers.ofString("{}"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
String responseBody = response.body();
// 假设返回的JSON包含前景和背景图片URL
String fgUrl = parseImageUrl(responseBody, "fg");
String bgUrl = parseImageUrl(responseBody, "bg");
Mat fgImage = downloadImage(fgUrl);
Mat bgImage = downloadImage(bgUrl);
return new Mat[] { fgImage, bgImage };
}
public static String parseImageUrl(String json, String key) {
// 实现简单的JSON解析来提取图片URL 更多内容联系1436423940
int index = json.indexOf(key);
int start = json.indexOf(":", index) + 2;
int end = json.indexOf("\"", start);
return json.substring(start, end);
}
public static Mat downloadImage(String imageUrl) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(imageUrl))
.build();
HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
return Imgcodecs.imdecode(new Mat(response.body().readAllBytes(), CvType.CV_8UC1), Imgcodecs.IMREAD_COLOR);
}
public static int getDistance(Mat fg, Mat bg) {
Mat result = new Mat();
Imgproc.matchTemplate(fg, bg, result, Imgproc.TM_CCOEFF_NORMED);
Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
Point matchLoc = mmr.maxLoc;
return (int) matchLoc.x;
}
}
2. 分析加密参数
在滑动滑块的过程中,我们需要分析加密参数。抓包查看请求信息,可以看到有一个fverify的验证信息。如果正确的话,riskLevel返回值为PASS,失败为REJECT。
通过在浏览器中设置断点,我们可以找到参数aw等的生成函数,并确定这些参数的加密方式。使用断点调试后,发现是通过DES加密。
以下是通过javax.crypto库实现DES加密的示例代码:
java
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.util.Base64;
public class DESEncryption {
public static void main(String[] args) throws Exception {
String message = "Hello, World!";
String key = "your_key_here";
boolean flag = true;
String encryptedMessage = encryptContent(message, key, flag);
System.out.println("Encrypted message: " + encryptedMessage);
}
public static String pad(String data) {
int blockSize = 8;
int paddingSize = blockSize - (data.length() % blockSize);
return data + "\0".repeat(paddingSize);
}
public static String encryptContent(String message, String key, boolean flag) throws Exception {
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
cipher.init(flag ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, keyFactory.generateSecret(desKeySpec));
byte[] paddedMessage = pad(message.replace(" ", "")).getBytes();
byte[] result = cipher.doFinal(paddedMessage);
return Base64.getEncoder().encodeToString(result);
}
}
3. 生成滑动轨迹并进行DES加密
滑动轨迹可以通过模拟人的滑动行为来生成,包括一些随机的抖动和速度变化。以下是生成滑动轨迹的示例代码:
java
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class SlideTrackGenerator {
public static void main(String[] args) {
int distance = 100; // 假设滑动距离为100
List<int[]> track = getRandom(distance);
for (int[] step : track) {
System.out.println("x: " + step[0] + ", y: " + step[1] + ", t: " + step[2]);
}
}
public static List<int[]> getRandom(int distance) {
List<int[]> track = new ArrayList<>();
track.add(new int[] { 0, 0, 0 });
Random random = new Random();
for (int i = 0; i < 10; i++) {
int x = 0;
int y = random.nextInt(3) - 1;
int t = 100 * (i + 1) + random.nextInt(3);
track.add(new int[] { x, y, t });
}
for (int i = 1; i < track.size() - 5; i++) {
track.get(i)[0] = distance / 2;
}
for (int i = track.size() - 5; i < track.size() - 1; i++) {
track.get(i)[0] = distance + random.nextInt(4);
}
track.get(track.size() - 1)[0] = distance;
return track;
}
}
4. 验证破解结果
最后,结合前面的步骤,实现滑块破解。以下是完整的示例代码:
java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gson.Gson;
public class CaptchaBreaker {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void main(String[] args) throws Exception {
String registerUrl = "https://www.ishumei.com/trial/captcha.html";
var images = getImages(registerUrl);
Mat fg = images[0];
Mat bg = images[1];
int distance = getDistance(fg, bg);
List<int[]> track = getRandom(distance);
String nm = new Gson().toJson(track);
String dy = String.valueOf(track.get(track.size() - 1)[2]);
String key = "your_key_here";
boolean flag = true;
String encryptedNm = encryptContent(nm, key, flag);
String encryptedDy = encryptContent(dy, key, flag);
Map<String, String> verifyData = new HashMap<>();
verifyData.put("nm", encryptedNm);
verifyData.put("dy", encryptedDy);
verifyData.put("rid", "register_id_here");
verifyData.put("dl", String.valueOf(distance));
Gson gson = new Gson();
String json = gson.toJson(verifyData);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://www.ishumei.com/trial/fverify"))
.POST(HttpRequest.BodyPublishers.ofString(json))
.header("Content-Type", "application/json")
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
Map<String, Object> result = gson.fromJson(response.body(), Map.class);
if ("PASS".equals(result.get("riskLevel"))) {
System.out.println("验证成功");
} else {
System.out.println("验证失败");
}
}
}