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

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

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

我们使用Java的HttpURLConnection类来捕获和分析这些请求。

java

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class VerifyRequest {
    public static void main(String[] args) throws Exception {
        String url = "https://example.com/verify";
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        connection.setRequestMethod("GET");

        BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String inputLine;
        StringBuffer content = new StringBuffer();
        while ((inputLine = in.readLine()) != null) {
            content.append(inputLine);
        }
        in.close();
        connection.disconnect();

        System.out.println(content.toString());
    }
}
通过分析响应内容,可以发现所有的verify请求都指向了gcaptcha4.js文件。

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

java

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FindWParameter {
    public static void main(String[] args) throws IOException {
        String content = new String(Files.readAllBytes(Paths.get("gcaptcha4.js")));

        Pattern pattern = Pattern.compile("[\\.'\"]w[\\.'\"]");
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println("Found at: " + matcher.start() + " - " + matcher.end() + ": " + matcher.group());
        }
    }
}
通过搜索"w",我们找到了相关代码。在第2527行,我们发现了w的值r在第2525行被定义。

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

java

import com.google.gson.Gson;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class WParameter {
    public static String stringify(Object obj) {
        Gson gson = new Gson();
        return gson.toJson(obj);
    }

    public static String defaultEncrypt(String data, String key) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update((data + key).getBytes());
        byte[] digest = md.digest();
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    public static void main(String[] args) throws NoSuchAlgorithmException {
        // 示例数据
        String e = stringify(new YourClass());
        String a = "your_key";

        String r = defaultEncrypt(e, a);
        System.out.println(r);
    }
}
首先,stringify(e)相当于对e进行JSON序列化操作。然后,我们分析defaultEncrypt(stringify(e), a)的含义。

java

public class Encryption {
    public static String encrypt(String e, String t) {
        String n = generateGuid();
        String a = new Encryptor().encrypt(n);
        while (a == null || a.length() != 256) {
            n = generateGuid();
            a = new Encryptor().encrypt(n);
        }
        String o = new Encryptor().encrypt(e, n);
        return arrayToHex(o) + a;
    }

    public static String generateGuid() {
        return String.format("%04x%04x%04x%04x", 
            (int)(Math.random() * 0x10000),
            (int)(Math.random() * 0x10000),
            (int)(Math.random() * 0x10000),
            (int)(Math.random() * 0x10000));
    }

    public static String arrayToHex(String input) {
        // 实现数组到十六进制字符串的转换
        // 这里只是一个简单的示例实现,实际代码可能需要处理更多细节
        StringBuilder sb = new StringBuilder();
        for (char c : input.toCharArray()) {
            sb.append(Integer.toHexString((int) c));
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        // 示例数据
        String e = "example_data";
        String t = "example_key";
        
        String result = encrypt(e, t);
        System.out.println(result);
    }
}
从这里可以确定参数t未被使用,参数e就是w的明文。接着我们分析e的组成部分:

java

import java.util.HashMap;
import java.util.Map;

public class WParameterComponents {
    public static void main(String[] args) {
        Map<String, Object> e = new HashMap<>();
        e.put("device_id", "A8A0");  // 固定值
        e.put("em", Map.of(
            "cp", 0,
            "ek", "11",
            "nt", 0,
            "ph", 0,
            "sc", 0,
            "si", 0,
            "wd", 1
        ));  // 固定值
        e.put("ep", "123");  // 固定值
        e.put("geetest", "captcha");  // 固定值
        e.put("fq6a", "1925502591");  // 固定值
        e.put("lang", "zh");  // 固定值
        e.put("lot_number", "7e22264d4f3e4dd8a6ffbf6e82e1122d");  // load请求返回值
        e.put("passtime", 166);  // 通过时间
        e.put("pow_msg", "1|0|md5|2022-03-25T14:23:36.364152+08:00|24f56dc13c40dc4a02fd0318567caef5|7e22264d4f3e4dd8a6ffbf6e82e1122d||29f07cebf938aa4e");  // load请求返回加上某算法返回值
        e.put("pow_sign", "2b47a3a9425dd19dd5abf902c8bb0763");  // pow_msg的md5值
        e.put("setLeft", 88);  // 滑动距离
        e.put("track", new int[][]{{38, 18, 0}, {1, 0, 33}......});  // 轨迹
        e.put("userresponse", 87.47978686742837);  // 某算法返回值

        System.out.println(e);
    }
}
4.1 分析pow_msg和pow_sign
通过搜索pow_msg,我们找到相关代码并解析如下:

java

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

public class PowMsgAndSign {
    public static String generateGuid() {
        Random random = new Random();
        return String.format("%04x%04x%04x%04x", 
            random.nextInt(0x10000),
            random.nextInt(0x10000),
            random.nextInt(0x10000),
            random.nextInt(0x10000));
    }

    public static String md5(String input) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] messageDigest = md.digest(input.getBytes());
        StringBuilder hexString = new StringBuilder();
        for (byte b : messageDigest) {
            hexString.append(String.format("%02x", b));
        }
        return hexString.toString();
    }

    public static void main(String[] args) throws NoSuchAlgorithmException {
        String n = "example_n";
        String a = "example_a";
        String s = "example_s";
        String o = "example_o";
        String t = "example_t";
        String e = "example_e";
        String r = "example_r";

        String u = String.join("|", n, a, s, o, t, e, r, "");
        String p = generateGuid();
        String g = u + p;
        String pow_msg = u + p;
        String pow_sign = md5(g);

        System.out.println("pow_msg: " + pow_msg);
        System.out.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)
java

public class TrackAnalysis {
    public static void main(String[] args) {
        int set_left = 88;
        int[][] track = {{38, 18, 0}, {1, 0, 33}......};
        int passtime = 166;
        double userresponse = set_left / (0.8876 * 340 / 300);

        System.out.println("set_left: " + set_left);
        System.out.println("track: " + Arrays.deepToString(track));
        System.out.println("passtime: " + passtime);
        System.out.println("userresponse: " + userresponse);
    }
}
至此,我们已经完成了w参数的明文解析。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值