极验验证码是一种广泛应用的滑动验证码系统,通过分析其加密和验证机制,我们可以模拟滑动操作并破解验证码。本文将详细介绍如何在Rust语言环境下实现这一过程。
一、观察verify请求
首先,我们需要观察verify请求的来源。在浏览器开发者工具中查看verify请求的发起者,可以发现它来自于gcaptcha4.js文件。由于该文件经过混淆处理,我们需要对其进行还原和分析。
二、AST还原混淆代码
为了便于调试和分析,我们使用AST(抽象语法树)还原混淆的JS文件。通过Chrome的reres插件替换混淆后的JS文件,我们可以在浏览器中加载还原后的代码进行调试。
三、定位w参数加密位置
通过对代码的分析和调试,可以确定w参数的加密位置。通过搜索关键字"w",可以找到相关代码并在适当位置打上断点,观察w参数的生成过程。
四、分析w参数加密算法
通过分析w参数的生成代码,可以简化为以下内容:
rust
let r = d.default(l.default.stringify(e), a);
其中,e是一个包含多个固定值和从请求响应中获取的数据的对象。通过进一步分析,可以确定e的组成如下:
rust
let e = json!({
"device_id": "A8A0",
"em": {
"cp": 0,
"ek": "11",
"nt": 0,
"ph": 0,
"sc": 0,
"si": 0,
"wd": 1
},
"ep": "123",
"geetest": "captcha",
"fq6a": "1925502591",
"lang": "zh",
"lot_number": lot_number,
"passtime": passtime,
"pow_msg": generate_pow_msg(&lot_number, passtime),
"pow_sign": generate_pow_sign(&generate_pow_msg(&lot_number, passtime)),
"setLeft": set_left,
"track": track,
"userresponse": user_response
});
五、Rust代码实现
下面是一个完整的Rust程序示例,它演示了如何生成滑动验证码所需的参数,并发送验证请求。
rust
use md5;
use rand::Rng;
use serde_json::json;
use std::time::{SystemTime, UNIX_EPOCH};
// 生成UUID
fn generate_challenge() -> String {
let start = SystemTime::now();
let since_the_epoch = start
.duration_since(UNIX_EPOCH)
.
rust
use md5;
use rand::Rng;
use serde_json::json;
use std::time::{SystemTime, UNIX_EPOCH};
// 生成UUID
fn generate_challenge() -> String {
let start = SystemTime::now();
let since_the_epoch = start
.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let timestamp = since_the_epoch.as_millis().to_string();
format!("{:x}", md5::compute(timestamp))
}
// 生成滑动轨迹
fn generate_track(distance: i32) -> Vec<(i32, i32, i32)> {
let mut track = Vec::new();
let mut current = 0;
let mut rng = rand::thread_rng();
while current < distance {
let step = rng.gen_range(1..=5);
current += step;
track.push((step, rng.gen_range(0..=2), rng.gen_range(10..=20)));
}
track
}
// 计算滑动距离
fn get_set_left(track: &[(i32, i32, i32)]) -> i32 {
track.iter().map(|(x, _, _)| *x).sum()
}
// 生成pow_msg
fn generate_pow_msg(lot_number: &str, passtime: i32) -> String {
format!(
"1|0|md5|2022-03-25T14:23:36.364152+08:00|24f56dc13c40dc4a02fd0318567caef5|{}||29f07cebf938aa4e",
lot_number
)
}
// 生成pow_sign
fn generate_pow_sign(pow_msg: &str) -> String {
format!("{:x}", md5::compute(pow_msg))
}
fn main() {
let captcha_id = "24f56dc13c40dc4a02fd0318567caef5";
let challenge = generate_challenge();
let client_type = "web";
let risk_type = "slide";
let lang = "zh";
let callback = format!("geetest_{}", SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis());
// 模拟加载请求
let load_response = load_request(captcha_id, &challenge, client_type, risk_type, lang, &callback);
let lot_number = load_response.get("lot_number").unwrap().as_str().unwrap();
let bg_image = load_response.get("bg").unwrap().as_str().unwrap();
let full_image = load_response.get("fullbg").unwrap().as_str().unwrap();
// 分析背景图与完整图以确定滑块位置
let set_left = analyze_image(bg_image, full_image);
// 生成滑动轨迹
let track = generate_track(set_left);
let passtime = track.iter().map(|(_, _, t)| *t).sum();
// 计算userresponse
let user_response = set_left as f64 / (0.8876 * 340.0 / 300.0);
// 构造w参数
let w_param = json!({
"device_id": "A8A0",
"em": {
"cp": 0,
"ek": "11",
"nt": 0,
"ph": 0,
"sc": 0,
"si": 0,
"wd": 1
},
"ep": "123",
"geetest": "captcha",
"fq6a": "1925502591",
"lang": "zh",
"lot_number": lot_number,
"passtime": passtime,
"pow_msg": generate_pow_msg(lot_number, passtime),
"pow_sign": generate_pow_sign(&generate_pow_msg(lot_number, passtime)),
"setLeft": set_left,
"track": track,
"userresponse": user_response
});
// 发送验证请求
let verify_response = verify_request(&w_param);
println!("Verify Response: {}", verify_response);
}
// 示例函数:加载请求
fn load_request(
_captcha_id: &str,
_challenge: &str,
_client_type: &str,
_risk_type: &str,
_lang: &str,
_callback: &str,
) -> serde_json::Value {
// 模拟发送请求并获取响应
json!({
"lot_number": "7e22264d4f3e4dd8a6ffbf6e82e1122d",
"bg": "bg_image_data",
"fullbg": "full_image_data",
})
}
// 示例函数:分析图像
fn analyze_image(_bg_image: &str, _full_image: &str) -> i32 {
// 简化的图像分析函数,返回假定的滑块位置
88
}
// 示例函数:验证请求
fn verify_request(w_param: &serde_json::Value) -> String {
// 模拟发送验证请求并获取响应
println!("Sending Verify Request with wParam: {}", w_param.to_string());
// 模拟响应
"Success".to_string()
}