数美滑块验证码是一种常见的安全验证方式,用于防止自动化脚本和机器人进行恶意操作。本文将详细介绍如何通过抓包获取滑块图片信息、分析加密参数、生成滑动轨迹等步骤,成功破解数美滑块验证码。以下是我们要实现的主要步骤:
抓取滑块图片信息并计算滑动距离
分析加密参数
生成滑动轨迹并进行DES加密
验证破解结果
1. 抓取滑块图片信息并计算滑动距离
首先,进入数美滑块验证码的演示页面,进行抓包操作以获取滑块验证码的前景和背景图片。我们通过HttpClient从网站获取图片:
csharp
using System;
using System.Net.Http;
using System.Threading.Tasks;
using OpenCvSharp;
using Newtonsoft.Json.Linq;
public class CaptchaBreaker
{
private static readonly HttpClient client = new HttpClient();
public static async Task Main(string[] args)
{
string registerUrl = "https://www.ishumei.com/trial/captcha.html";
var images = await GetImagesAsync(registerUrl);
Mat fg = images.Item1;
Mat bg = images.Item2;
int distance = GetDistance(fg, bg);
Console.WriteLine("Calculated distance: " + distance);
}
public static async Task<Tuple<Mat, Mat>> GetImagesAsync(string registerUrl)
{
var response = await client.PostAsync(registerUrl, new StringContent("{}"));
string responseBody = await response.Content.ReadAsStringAsync();
// 假设返回的JSON包含前景和背景图片URL
string fgUrl = ParseImageUrl(responseBody, "fg");
string bgUrl = ParseImageUrl(responseBody, "bg");
Mat fgImage = await DownloadImageAsync(fgUrl);
Mat bgImage = await DownloadImageAsync(bgUrl);
return Tuple.Create(fgImage, bgImage);
}
public static string ParseImageUrl(string json, string key)
{
var jsonObj = JObject.Parse(json);
return jsonObj[key].ToString();
}
public static async Task<Mat> DownloadImageAsync(string imageUrl)
{
var response = await client.GetAsync(imageUrl);
byte[] imageBytes = await response.Content.ReadAsByteArrayAsync();
return Cv2.ImDecode(imageBytes, ImreadModes.Color);
}
public static int GetDistance(Mat fg, Mat bg)
{
Mat result = new Mat();
Cv2.MatchTemplate(fg, bg, result, TemplateMatchModes.CCoeffNormed);
Cv2.MinMaxLoc(result, out _, out _, out _, out Point maxLoc);
return (int)maxLoc.X;
}
}
2. 分析加密参数
在滑动滑块的过程中,我们需要分析加密参数。抓包查看请求信息,可以看到有一个fverify的验证信息。如果正确的话,riskLevel返回值为PASS,失败为REJECT。
通过在浏览器中设置断点,我们可以找到参数aw等的生成函数,并确定这些参数的加密方式。使用断点调试后,发现是通过DES加密。
以下是通过System.Security.Cryptography库实现DES加密的示例代码:
csharp
using System;
using System.Security.Cryptography;
using System.Text;
public class DESEncryption
{
public static void Main(string[] args)
{
string message = "Hello, World!";
string key = "your_key_here";
bool flag = true;
string encryptedMessage = EncryptContent(message, key, flag);
Console.WriteLine("Encrypted message: " + encryptedMessage);
}
public static string Pad(string data)
{
int blockSize = 8;
int paddingSize = blockSize - (data.Length % blockSize);
return data + new string('\0', paddingSize);
}
public static string EncryptContent(string message, string key, bool flag)
{
using (var des = DES.Create())
{
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.None;
des.Key = Encoding.UTF8.GetBytes(key);
var transform = flag ? des.CreateEncryptor() : des.CreateDecryptor();
byte[] paddedMessage = Encoding.UTF8.GetBytes(Pad(message.Replace(" ", "")));
byte[] result = transform.TransformFinalBlock(paddedMessage, 0, paddedMessage.Length);
return Convert.ToBase64String(result);
}
}
}
3. 生成滑动轨迹并进行DES加密
滑动轨迹可以通过模拟人的滑动行为来生成,包括一些随机的抖动和速度变化。以下是生成滑动轨迹的示例代码:
csharp
using System;
using System.Collections.Generic;
public class SlideTrackGenerator
{
public static void Main(string[] args)
{
int distance = 100; // 假设滑动距离为100
var track = GetRandom(distance);
foreach (var step in track)
{
Console.WriteLine($"x: {step[0]}, y: {step[1]}, t: {step[2]}");
}
}
public static List<int[]> GetRandom(int distance)
{
var track = new List<int[]>();
track.Add(new int[] { 0, 0, 0 });
var random = new Random();
for (int i = 0; i < 10; i++)
{
int x = 0;
int y = random.Next(3) - 1;
int t = 100 * (i + 1) + random.Next(3);
track.Add(new int[] { x, y, t });
}
for (int i = 1; i < track.Count - 5; i++)
{
track[i][0] = distance / 2;
}
for (int i = track.Count - 5; i < track.Count - 1; i++)
{
track[i][0] = distance + random.Next(4);
}
track[track.Count - 1][0] = distance;
return track;
}
}
4. 验证破解结果
最后,结合前面的步骤,实现滑块破解。以下是完整的示例代码:
csharp
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using OpenCvSharp;
using System.Security.Cryptography;
public class CaptchaBreaker
{
private static readonly HttpClient client = new HttpClient();
static CaptchaBreaker()
{
Cv2.SetUseOptimized(true);
}
public static async Task Main(string[] args)
{
string registerUrl = "https://www.ishumei.com/trial/captcha.html";
var images = await GetImagesAsync(registerUrl);
Mat fg = images.Item1;
Mat bg = images.Item2;
int distance = GetDistance(fg, bg);
var track = GetRandom(distance);
string nm = JsonConvert.SerializeObject(track);
string dy = track[track.Count - 1][2].ToString();
string key = "your_key_here";
bool flag = true;
string encryptedNm = EncryptContent(nm, key, flag);
string encryptedDy = EncryptContent(dy, key, flag);
var verifyData = new Dictionary<string, string>
{
{ "nm", encryptedNm },
{ "dy", encryptedDy },
{ "rid", "register_id_here" },
{ "dl", distance.ToString() }
};
string json = JsonConvert.SerializeObject(verifyData);
var request = new HttpRequestMessage(HttpMethod.Post, "https://www.ishumei.com/trial/fverify")
{
Content = new StringContent(json, Encoding.UTF8, "application/json")
};
var response = await client.SendAsync(request);
string responseBody = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<Dictionary<string, string>>(responseBody);
if (result["riskLevel"] == "PASS")
{
Console.WriteLine("验证成功");
}
else
{
Console.WriteLine("验证失败");
}
}
public static async Task<Tuple<Mat, Mat>> GetImagesAsync(string registerUrl)
{
var response = await client.PostAsync(registerUrl, new StringContent("{}"));
string responseBody = await response.Content.ReadAsStringAsync();
string fgUrl = ParseImageUrl(responseBody, "fg");
string bgUrl = ParseImageUrl(responseBody, "bg");
Mat fgImage = await DownloadImageAsync(fgUrl);
Mat bgImage = await DownloadImageAsync(bgUrl);
return Tuple.Create(fgImage, bgImage);
}
public static string ParseImageUrl(string json, string key)
{
var jsonObj = JObject.Parse(json);
return jsonObj[key].ToString();
}
public static async Task<Mat> DownloadImageAsync(string imageUrl)
{
var response = await client.GetAsync(imageUrl);
byte[] imageBytes = await response.Content.ReadAsByteArrayAsync();
return Cv2.ImDecode(imageBytes, ImreadModes.Color);
}
public static int GetDistance(Mat fg, Mat bg)
{
Mat result = new Mat();
Cv2.MatchTemplate(fg, bg, TemplateMatchModes.CCoeffNormed);
Cv2.MinMaxLoc(result, out _, out _, out _, out Point maxLoc);
return (int)maxLoc.X;
}
public static List<int[]> GetRandom(int distance)
{
var track = new List<int[]>();
track.Add(new int[] { 0, 0, 0 });
var random = new Random();
for (int i = 0; i < 10; i++)
{
int x = 0;
int y = random.Next(3) - 1;
int t = 100 * (i + 1) + random.Next(3);
track.Add(new int[] { x, y, t });
}
for (int i = 1; i < track.Count - 5; i++)
{
track[i][0] = distance / 2;
}
for (int i = track.Count - 5; i < track.Count - 1; i++)
{
track[i][0] = distance + random.Next(4);
}
track[track.Count - 1][0] = distance;
return track;
}
public static string Pad(string data)
{
int blockSize = 8;
int paddingSize = blockSize - (data.Length % blockSize);
return data + new string('\0', paddingSize);
}
public static string EncryptContent(string message, string key, bool flag)
{
using (var des = DES.Create())
{
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.None;
des.Key = Encoding.UTF8.GetBytes(key);
var transform = flag ? des.CreateEncryptor() : des.CreateDecryptor();
byte[] paddedMessage = Encoding.UTF8.GetBytes(Pad(message.Replace(" ", "")));
byte[] result = transform.TransformFinalBlock(paddedMessage, 0, paddedMessage.Length);
return Convert.ToBase64String(result);
}
}
}