bhcli

"Strange's fork of n0tr1v's bhcli (onion)"
git clone https://git.dasho.dev/Strange/bhcli.git
Log | Files | Refs | README

commit fffa933fe3e36aec8f6b80b6865ca1155930abca
parent 30846c47600dfea75436c17bfce037f9e4e7fe1a
Author: n0tr1v <n0tr1v@protonmail.com>
Date:   Tue, 28 Mar 2023 13:35:50 -0700

auto solve captcha difficulty 1

Diffstat:
Asrc/lechatphp/mod.rs | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.rs | 6++++--
2 files changed, 110 insertions(+), 2 deletions(-)

diff --git a/src/lechatphp/mod.rs b/src/lechatphp/mod.rs @@ -0,0 +1,105 @@ +use std::collections::HashMap; +use base64::{engine::general_purpose, Engine as _}; +use image::{ColorType, DynamicImage}; +use lazy_static::lazy_static; + +const B64_PREFIX: &'static str = "R0lGODlhCAAOAIAAAAAAAAAAACH5BAgAAAAALAAAAAAIAA4AgAQCBPz+/AI"; +const _ALPHABET: &'static str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +const _ALPHABET1: &'static str = "abdcefgh1ijkImnpoqrstyQuvwxzABCDEGJKMNHLORPFSTlUVWXYZ023456789"; + +lazy_static! { + static ref B64_MAP: HashMap<&'static str, char> = HashMap::from([ + ("VhI8Qkbv3FIvGMeiQ1fPSzSXiSAIFADs=", '0'), + ("UhI8QkcvnHlpJSXgNbdnO2FViVQAAOw==", '1'), + ("UhI+hcWruGkMgSmrfvGnrtVDiKBYAOw==", '2'), + ("UhH+hatyBEkTuzVjpldWtHIUiUgAAOw==", '3'), + ("VhI8XkcvqIFiGTmbvdRFl2TzJSCYFADs=", '4'), + ("WhG+hG6CYGnwrygedRIw3jGlhRpZGAQA7", '5'), + ("XhI+hcWruGoiJrRcha5fPTS0bQpamUQAAOw==", '6'), + ("ThG+hq5jhQEPz1OeuhJT3CIZiAQA7", '7'), + ("XhI+hcWruGosRLPYwxLnaqXEXQpYmUgAAOw==", '8'), + ("VhI+hcWru2kosTjAjxduydyHiSBoFADs=", '9'), + ("VhI8Qkbv3FIvGMeiQ3RlT+X3JSBoFADs=", 'A'), + ("VhG+hm3EK4GMtLimtntlmeHXISJYFADs=", 'B'), + ("VhI+hatyLAIwuhSgv1edWt1TYSAIFADs=", 'C'), + ("WhG+hm3EK4GNTNhvpdZXnvHjISJZAAQA7", 'D'), + ("UhG+hG6CYGnyTSYrw0RE6K3niaBQAOw==", 'E'), + ("ThG+hy5jhgIpsSugs0oe/CIZiAQA7", 'F'), + ("VhI+hatyLXgQuhbMqhfhWl13TSB4FADs=", 'G'), + ("UhG8RqMr93Gm0xjVhlkl3BIaiUQAAOw==", 'H'), + ("UhH+hi4rmXmzhgZmq1JQuboUiUAAAOw==", 'I'), + ("UhI8QG6mdlpMRInqhpRI/64TiUQAAOw==", 'J'), + ("XhG8RqHruQIQrNXbfirLO2oUaQpamUQAAOw==", 'K'), + ("UhG8RmMvKAHwOTVvP1bmpH4UiUgAAOw==", 'L'), + ("WhG8RqJ0NI1DTUVgrPZg7vz3ISJZGAQA7", 'M'), + ("WhG8RqH3tAFTJUSgXzpvTGlXISJZGAQA7", 'N'), + ("VhI+hcWru2kpTxlfxBZBx/23ISJYFADs=", 'O'), + ("ThG+hG6DI4JJsPuQavhJnD4ZiAQA7", 'P'), + ("WhI+hcWru2kpTxjdhXSxeDjDISJZAAQA7", 'Q'), + ("WhG+hG6DI4JJs1vNc07jlNHXISJZGAQA7", 'R'), + ("UhH+hC4obkHGywVjpw1tbC1XiiBQAOw==", 'S'), + ("UhG+hq9cIHpIuwGghTXn2eoXiVQAAOw==", 'T'), + ("UhG8RqMr93GlrQivT1UBmioTiiBQAOw==", 'U'), + ("VhG8RqMr9gJOLpjon1bsefiHiSIoFADs=", 'V'), + ("UhG8RqMr93GnLUWBhplzyh4TiaBQAOw==", 'W'), + ("UhG8RqMrrQJQNUXvfjG5S72GiWAAAOw==", 'X'), + ("UhG8RqMrrQJQNUXvtPDst/WHiiBQAOw==", 'Y'), + ("UhG+hG5jtVIRHIlvpcwBnpnHiWAAAOw==", 'Z'), + ("ThI+pq+FuYAyNvitnfuB2yoRKAQA7", 'a'), + ("WhG8RmMvKAFSONukaPDRji4VgRJZHAQA7", 'b'), + ("RhI+pq+FuYHwt1CWBfJn5VAAAOw==", 'c'), + ("VhI8YkbD93JtMrmoutpvmeEnNSB4FADs=", 'd'), + ("RhI+pq+FxnJEyvntXBRWzzxQAOw==", 'e'), + ("VhI8QG7f2VJNwoliZpQm7XSXiSBoFADs=", 'f'), + ("VhI+pm+EO3nnQwBqDpXvRq03aFy4FADs=", 'g'), + ("VhG8RmMvKAFSONukaPDTjrXlgRJYFADs=", 'h'), + ("ThI8Qkcrd1kMrzlNTpldKCIZAAQA7", 'i'), + ("UhI8XkbANF0uPTlTxVSw/P0kZVAAAOw==", 'j'), + ("VhH8RaMrgWJwrQrUSRs7Sll3PSB4FADs=", 'k'), + ("RhI+haMueAgPw1CZfjvrODxYAOw==", 'l'), + ("ThI+piwHh4ItUWkjn1Rl3x4RKAQA7", 'm'), + ("UhI+pixHgHnSG0hNljY1jvzHiUgAAOw==", 'n'), + ("ThI+pq+FxnJEyPvSgBbXyy4RMAQA7", 'o'), + ("VhI+pixHgHnSG0hNljS3vOUlXxygFADs=", 'p'), + ("VhI+pq+HwHnTS0IBuxpLaiCXVMSIFADs=", 'q'), + ("ShI+pixHgnInzyXTbw1uzDxoFADs=", 'r'), + ("RhI+pm+EPHHphUanorLeyvxQAOw==", 's'), + ("UhI95EcrIYlsTVuqueYD3qIQiUgAAOw==", 't'), + ("ThI+pixHt3onSUOggyJvHzoRLAQA7", 'u'), + ("ThI+pixHt3nGAVmnt1VtOz4RLAQA7", 'v'), + ("UhI+pixHt3onPAXprzJliyzHiUgAAOw==", 'w'), + ("ThI+pixH9nJHTPZjsBVTSyoRLAQA7", 'x'), + ("VhI+pixHt3onSUOggyJvHXlkPxS0FADs=", 'y'), + ("PhI+pm+GvXAuzIjkfZXwVADs=", 'z'), + ]); +} + +pub fn solve_b64(b64_str: &str) -> Option<String> { + let img_dec = general_purpose::STANDARD.decode(b64_str.strip_prefix("data:image/gif;base64,").unwrap()).unwrap(); + let img = image::load_from_memory(&img_dec).unwrap(); + solve_difficulty1(img) +} + +fn solve_difficulty1(img: DynamicImage) -> Option<String> { + let mut answer = String::new(); + let mut x = 5; + for i in 0..5 { + let sub_img = img.crop_imm(x, 7, 8, 14); + let mut buf = vec![]; + { + let mut enc = image::codecs::gif::GifEncoder::new(&mut buf); + enc.encode(sub_img.as_bytes(), 8, 14, ColorType::Rgba8).unwrap(); + } + let letter_b64 = general_purpose::STANDARD.encode(&buf); + let letter_b64 = letter_b64.strip_prefix(B64_PREFIX).unwrap(); + if let Some(val) = B64_MAP.get(letter_b64) { + answer.push(val.clone()); + } else { + sub_img.save(format!("captcha_{}.gif", i)).unwrap(); + println!("{} {}", i, letter_b64); + return None; + } + x += 8+1; + } + Some(answer) +} +\ No newline at end of file diff --git a/src/main.rs b/src/main.rs @@ -1,4 +1,5 @@ mod util; +mod lechatphp; use base64::{engine::general_purpose, Engine as _}; use chrono::{DateTime, Datelike, NaiveDateTime, Utc}; @@ -808,8 +809,9 @@ impl LeChatPHPClient { let mut captcha_input = String::new(); if self.manual_captcha { let captcha_img = doc.find(Name("img")).next().unwrap().attr("src").unwrap(); - - if let Some(dkf_api_key) = self.dkf_api_key.clone() { + if let Some(answer) = lechatphp::solve_b64(captcha_img) { + captcha_input = answer; + } else if let Some(dkf_api_key) = self.dkf_api_key.clone() { // If we have the DKF_API_KEY, auto solve captcha using the api let params = vec![("captcha", captcha_img)]; let resp = self