使用Rust破解gcaptcha4.js中的w参数加密算法

在本文中,我们将介绍如何使用Rust来逆向工程gcaptcha4.js文件,找到并破解w参数的加密算法。整个过程包括观察verify请求,定位加密位置,分析加密算法,并最终还原w参数的明文。

一. 观察verify请求
首先,我们需要观察verify请求的发起者。通过网络请求分析工具,我们可以看到所有verify请求都来自于gcaptcha4.js文件。因此,这个文件成为我们分析的重点。

我们使用Rust的reqwest库来捕获和分析这些请求。

rust

use reqwest::blocking::get;
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let response = get("https://example.com/verify")?
        .text()?;
    println!("{}", response);
    Ok(())
}
通过分析响应内容,可以发现所有的verify请求都指向了gcaptcha4.js文件。

二. 定位w参数加密位置
为了找到w参数的加密位置,我们需要解析gcaptcha4.js文件。我们可以下载并格式化这个文件,然后使用正则表达式搜索关键词:w、.w、'w'或"w"。

rust

use regex::Regex;
use std::fs;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let data = fs::read_to_string("gcaptcha4.js")?;
    let re = Regex::new(r"[.\'\"w[.\'\"w]")?;
    let matches: Vec<_> = re.find_iter(&data).collect();
    for mat in matches {
        println!("{}", mat.as_str());
    }
    Ok(())
}
通过搜索"w",我们找到了相关代码。在第2527行,我们发现了w的值r在第2525行被定义。

三. 分析w参数加密算法
接下来,我们需要简化代码中w的定义。假设我们已经提取了相关的JavaScript代码,我们可以使用Rust来模拟这个过程。

rust

use serde_json::json;
use md5;

fn stringify(data: serde_json::Value) -> String {
    data.to_string()
}

fn default_encrypt(data: &str, key: &str) -> String {
    let digest = md5::compute(format!("{}{}", data, key));
    format!("{:x}", digest)
}

fn main() {
    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": "7e22264d4f3e4dd8a6ffbf6e82e1122d",
        "passtime": 166,
        "pow_msg": "1|0|md5|2022-03-25T14:23:36.364152+08:00|24f56dc13c40dc4a02fd0318567caef5|7e22264d4f3e4dd8a6ffbf6e82e1122d||29f07cebf938aa4e",
        "pow_sign": "2b47a3a9425dd19dd5abf902c8bb0763",
        "setLeft": 88,
        "track": [[38, 18, 0], [1, 0, 33]],
        "userresponse": 87.47978686742837
    });

    let a = "your_key";
    let r = default_encrypt(&stringify(e), a);
    println!("{}", r);
}
4.1 分析pow_msg和pow_sign
通过搜索pow_msg,我们找到相关代码并解析如下:

rust

use rand::Rng;
use md5;

fn generate_guid() -> String {
    let mut rng = rand::thread_rng();
    format!("{:x}{:x}{:x}{:x}", rng.gen::<u32>(), rng.gen::<u32>(), rng.gen::<u32>(), rng.gen::<u32>())
}

fn md5_hash(input: &str) -> String {
    let digest = md5::compute(input);
    format!("{:x}", digest)
}

fn main() {
    let n = "example_n";
    let a = "example_a";
    let s = "example_s";
    let o = "example_o";
    let t = "example_t";
    let e = "example_e";
    let r = "example_r";

    let u = format!("{}|{}|{}|{}|{}|{}|{}|", n, a, s, o, t, e, r);
    let p = generate_guid();
    let g = format!("{}{}", u, p);
    let pow_msg = format!("{}{}", u, p);
    let pow_sign = md5_hash(&g);

    println!("pow_msg: {}", pow_msg);
    println!("pow_sign: {}", pow_sign);
}
4.2 分析set_left、track、passtime、userresponse
set_left:滑块移动距离的整数值
track:移动轨迹,从第二步开始,是相对上一步的相对移动距离(x, y, t)
passtime:总移动时间
userresponse:计算公式为set_left / (0.8876 * 340 / 300)
rust

fn main() {
    let set_left = 88;
    let track = vec![[38, 18, 0], [1, 0, 33]];
    let passtime = 166;
    let user_response = set_left as f64 / (0.8876 * 340.0 / 300.0);

    println!("set_left: {}", set_left);
    println!("track: {:?}", track);
    println!("passtime: {}", passtime);
    println!("userresponse: {}", user_response);
}
至此,我们已经完成了w参数的明文解析。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值