Cara Memecahkan GeeTest v3 di C#

GeeTest mematahkan model berpikir yang mendasari sebagian besar kode CAPTCHA. Tidak ada satu token untuk dimasukkan ke kolom formulir. Satu pemecahan mengembalikan tiga nilai yang harus dikirim kembali bersama-sama, dan challenge yang Anda mulai kedaluwarsa dalam sekitar satu menit. Salah pada salah satu bagian dan permintaannya gagal tanpa error yang berguna.
Inilah keseluruhan alurnya dalam C#, termasuk bagian-bagian yang mudah salah.
Dua input, dan hanya satu di antaranya yang stabil
GeeTest v3 mengidentifikasi situs dengan gt dan satu percobaan dengan challenge. Keduanya berperilaku sangat berbeda.
| Nilai | Seumur hidup | Dari mana asalnya |
|---|---|---|
gt | Statis untuk situs tersebut. Aman untuk di-hard-code atau di-cache | Respons init GeeTest milik situs tersebut |
challenge | Sekali pakai, kedaluwarsa dalam kurang lebih 60 detik | Respons init yang sama, selalu baru setiap kali |
Masa kedaluwarsa itu adalah penyebab tunggal paling umum kegagalan GeeTest. Jika Anda mengambil sepasang nilai, mengantrekan pekerjaannya, lalu memecahkannya tiga puluh detik kemudian di belakang pekerjaan lain, challenge itu mungkin sudah mati. Ambil tepat sebelum memecahkan, jangan pernah dari cache.
Penyiapan
# Targets .NET Standard 2.0, so Framework 4.6.1+ and .NET 6-9 all work. dotnet add package CapSkip
CapSkip berjalan di komputer Anda sendiri, jadi jalankan dulu aplikasinya lalu arahkan client ke port yang tercantum di pengaturannya:
using CapSkip;
var solver = new CapSkipClient(
apiKey: "capskip", // any string when key validation is off
host: "127.0.0.1",
port: 8080,
recaptchaTimeout: 300); // seconds, and this one covers GeeTest tooPerhatikan bahwa GeeTest menggunakan recaptchaTimeout, bukan defaultTimeout. Yang terakhir hanya berlaku untuk CAPTCHA gambar.
Memecahkannya
Tiga argumen posisional, dalam urutan ini:
var result = await solver.GeetestAsync(
"81388ea1fc187e0c335c0a8907ff2625", // gt, static per site
"7cf6a8b1a2c34d5e6f7089abcdef0123", // challenge, fetched seconds ago
"https://example.com/login");
Console.WriteLine(result.Challenge);
Console.WriteLine(result.Validate);
Console.WriteLine(result.Seccode);Ketiga properti itulah jawabannya. result.Code juga terisi, tetapi untuk GeeTest isinya adalah string JSON mentah, bukan token yang bisa dipakai, sehingga mengambil Code karena kebiasaan adalah kesalahan. Pada SolveResult, Challenge, Validate dan Seccode hanya untuk GeeTest dan bernilai null untuk semua jenis lainnya.
Perlu diketahui: challenge yang dikembalikan tidak selalu sama dengan yang Anda kirim. Gunakan nilai yang dikembalikan, bukan input Anda.
Mengirim balik jawabannya
Kirim ketiganya persis seperti yang akan dilakukan front end situs itu sendiri. Sebagian besar integrasi GeeTest v3 menggunakan nama kolom ini, meskipun sebuah situs dapat mengganti namanya, jadi periksa formulir yang sebenarnya sebelum berasumsi:
using System.Net.Http;
using System.Collections.Generic;
using var http = new HttpClient();
var form = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("geetest_challenge", result.Challenge),
new KeyValuePair<string, string>("geetest_validate", result.Validate),
new KeyValuePair<string, string>("geetest_seccode", result.Seccode),
new KeyValuePair<string, string>("username", "..."),
new KeyValuePair<string, string>("password", "..."),
});
var response = await http.PostAsync("https://example.com/login", form);Mengirim dua dari tiga, atau memasangkan versi baru validate dengan challenge, akan ditolak dengan cara yang sama seperti jawaban yang salah.
Seluruh alur, secara berurutan
Pengambilan pasangan dan pemecahan harus berdampingan. Bentuk kode ini menjaga keduanya tetap begitu:
using System;
using System.Net.Http;
using System.Text.Json;
using CapSkip;
// 1. Fetch a fresh gt/challenge pair from the site's own init endpoint.
using var http = new HttpClient();
var initJson = await http.GetStringAsync(
"https://example.com/geetest/init?t=" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());
using var doc = JsonDocument.Parse(initJson);
var gt = doc.RootElement.GetProperty("gt").GetString();
var challenge = doc.RootElement.GetProperty("challenge").GetString();
// 2. Solve immediately. Do not queue this or await anything slow in between.
var result = await solver.GeetestAsync(gt, challenge, "https://example.com/login");
// 3. Post all three values together.
Console.WriteLine($"{result.Challenge} {result.Validate} {result.Seccode}");Timestamp cache-busting pada panggilan init lebih penting daripada kelihatannya. Endpoint init GeeTest sering di-cache oleh perantara, dan respons yang di-cache memberi Anda tantangan yang sudah terpakai.
Ketika gagal
using System;
using CapSkip;
try
{
var result = await solver.GeetestAsync(gt, challenge, pageUrl);
}
catch (CapSkip.ValidationException) { /* missing gt or challenge */ }
catch (NetworkException) { /* CapSkip is not running */ }
catch (ApiException) { /* API error, often a dead challenge */ }
catch (CapSkip.TimeoutException) { /* exceeded recaptchaTimeout */ }
catch (CapSkipError) { /* anything else from the SDK */ }Qualify ValidationException dan TimeoutException dengan CapSkip namespace. Kedua nama juga ada di System, dan dengan kedua namespace diimpor, catch tanpa kualifikasi terikat ke System tipe dan diam-diam tidak pernah terpicu. Menangkap kelas dasar CapSkipError menghindari masalah itu sepenuhnya.
Dalam praktiknya sebagian besar kegagalan GeeTest muncul sebagai ApiException dan berarti tantangan sudah mati sebelum pemecahan selesai. Perbaikannya adalah mengambil lebih lambat, bukan mencoba ulang dengan nilai yang sama.
Proxy dan konkurensi
GeeTest adalah salah satu dari tiga tipe yang menerima proxy, bersama reCAPTCHA dan Turnstile. CAPTCHA gambar tidak, karena tidak pernah menyentuh situs target.
using System.Collections.Generic;
var result = await solver.GeetestAsync(gt, challenge, pageUrl,
new Dictionary<string, object?>
{
["proxy"] = new Proxy("HTTPS", "user:[email protected]:3128"),
});Menjalankan beberapa secara paralel memang bisa, tetapi masing-masing memerlukan pasangan yang baru diambil sendiri. Jangan mengambil sekumpulan tantangan di awal lalu memecahkannya bersamaan, karena yang terakhir akan kedaluwarsa sebelum tiba gilirannya.
// Correct: fetch and solve inside the same task.
var tasks = urls.Select(async url =>
{
var (gt, challenge) = await FetchPairAsync(url);
return await solver.GeetestAsync(gt, challenge, url);
});
var results = await Task.WhenAll(tasks);Pertanyaan yang sering diajukan
Mengapa result.Code bukan token yang bisa dipakai?
Karena jawaban GeeTest terdiri dari tiga nilai, bukan satu. Code menyimpan string JSON mentah demi kelengkapan, sementara SDK menguraikan bagian yang berguna menjadi Challenge, Validate dan Seccode. Gunakan ketiganya.
Bisakah saya menyimpan challenge di cache untuk menghemat satu permintaan?
Tidak. Nilainya sekali pakai dan kedaluwarsa dalam sekitar satu menit. Menyimpannya di cache adalah alasan paling umum integrasi GeeTest berhasil saat pengujian dan gagal saat beban tinggi, karena penundaan antrean mendorong pemecahan melewati jendela kedaluwarsa. gt nilai aman untuk di-cache.
Apakah ini bekerja untuk GeeTest v4?
The GeetestAsync metode ini menargetkan v3, versi puzzle geser yang dibangun di sekitar gt dan challenge pasangan. v4 mengubah model parameternya, jadi periksa versi terkini dari dokumentasi API untuk mengetahui apa yang didukung sebelum menganggap panggilan yang sama berfungsi.
Apakah saya perlu proxy?
Hanya ketika situs sensitif terhadap lokasi atau sudah menganggap alamat Anda mencurigakan. Pecahkan dan kirim dari jalur jaringan yang sama saat Anda memang memakainya, jika tidak, ketidakcocokan itu sendiri dapat memicu tantangan ulang.
Ringkasan
Ambil gt dan challenge tepat sebelum memecahkan, panggil GeetestAsync dengan keduanya ditambah URL halaman, lalu kirim Challenge, Validate dan Seccode kembali bersama-sama. Perlakukan tantangan sebagai sesuatu yang cepat kedaluwarsa, gunakan challenge yang dikembalikan alih-alih input Anda, dan tangkap CapSkipError untuk menghindari benturan namespace.
Signature metode untuk bahasa lainnya ada di pemecah GeeTest , cakupan .NET lengkap ada di halaman pemecah CAPTCHA C# , dan Anda dapat mencoba puzzle langsung di halaman kami Demo GeeTest v3. CapSkip menangani bypass captcha secara lokal, sehingga volume pemecahan tidak memakan biaya per permintaan.
