ct / src /vm /executor.rs
sanbo110's picture
update sth at 2025-10-12 18:06:26
94c29e9
// JavaScript VM executor for ChatGPT reverse engineering
use crate::utils::{Result, Utils};
use crate::vm::{Decompiler, Parser};
use base64::{Engine as _, engine::general_purpose};
use rand::Rng;
use serde_json::{Map, Value};
use std::collections::HashMap;
/// Virtual Machine for executing turnstile challenges
pub struct VM;
impl VM {
/// HTML object used in VM calculations
const HTML_OBJECT: &'static str = r#"{"x":0,"y":1219,"width":37.8125,"height":30,"top":1219,"right":37.8125,"bottom":1249,"left":0}"#;
/// Generate turnstile token (simplified)
pub fn get_turnstile(_bytecode: &str, _token: &str, _ip_info: &str) -> Result<String> {
// Placeholder implementation: real logic would parse bytecode and token to
// compute the turnstile token. For now, keep a deterministic shape so the
// rest of the pipeline can execute.
Ok(format!(
"0.{}.{}",
chrono::Utc::now().timestamp(),
rand::random::<u32>()
))
}
/// Decompile VM bytecode to JavaScript
pub fn decompile_vm(turnstile: &str, token: &str) -> Result<String> {
Decompiler::decompile_vm(turnstile, token)
}
/// Parse keys from decompiled JavaScript
pub fn parse_keys(decompiled_code: &str) -> Result<(String, HashMap<String, String>)> {
Parser::parse_keys(decompiled_code)
}
/// Execute JavaScript code and extract result
///
/// Note: This is a simplified stub. Full implementation would require
/// a JavaScript engine like V8 or QuickJS bindings
pub fn execute_js(_code: &str) -> Result<String> {
// In a full implementation, this would:
// 1. Create a JavaScript context
// 2. Execute the decompiled code
// 3. Extract the result
// For now, return a placeholder
Ok("{}".to_string())
}
/// XOR two strings
pub fn xor(data: &str, key: &str) -> String {
Utils::xor_strings(data, key)
}
/// Add values to VM payload based on extracted operations
pub fn add_vm_values(
payload: &mut Map<String, Value>,
xor_key: &str,
ip_info: &str,
) -> Result<()> {
let mut rng = rand::rng();
// Random values
let random1: f64 = rng.random();
let random2: f64 = rng.random();
payload.insert(
"19.33".to_string(),
Value::String(
general_purpose::STANDARD
.encode(Self::xor(&format!("{}", random1 + 0.6), xor_key).as_bytes()),
),
);
payload.insert(
"56.04".to_string(),
Value::String(
general_purpose::STANDARD
.encode(Self::xor(r#"["Google Inc.","Win32",8,0]"#, xor_key).as_bytes()),
),
);
payload.insert(
"14.85".to_string(),
Value::String(
general_purpose::STANDARD.encode(Self::xor(Self::HTML_OBJECT, xor_key).as_bytes()),
),
);
payload.insert(
"31.17".to_string(),
Value::String(general_purpose::STANDARD.encode(
Self::xor("oai/apps/hasDismissedTeamsNoAuthUpsell,oai-did", xor_key).as_bytes(),
)),
);
payload.insert(
"7.1".to_string(),
Value::String(
general_purpose::STANDARD
.encode(Self::xor(&rng.random_range(1..5).to_string(), xor_key).as_bytes()),
),
);
payload.insert(
"75.89".to_string(),
Value::String(general_purpose::STANDARD.encode(Self::xor(ip_info, xor_key).as_bytes())),
);
payload.insert(
"84.91".to_string(),
Value::String(
general_purpose::STANDARD
.encode(Self::xor("https://chatgpt.com/", xor_key).as_bytes()),
),
);
payload.insert(
"30.7".to_string(),
Value::String(
general_purpose::STANDARD
.encode(Self::xor(&random1.to_string(), &random1.to_string()).as_bytes()),
),
);
payload.insert(
"27.36".to_string(),
Value::Number(serde_json::Number::from_f64(random2).unwrap()),
);
Ok(())
}
/// Simplified bytecode decompiler (placeholder for complex implementation)
pub fn decompile_bytecode(_bytecode: &str) -> Result<HashMap<String, String>> {
// This is a placeholder for the complex JavaScript decompiler
// In the real implementation, this would parse and execute the bytecode
let mut operations = HashMap::new();
// These would be extracted from the actual bytecode
operations.insert("xor_key".to_string(), "48.51".to_string());
operations.insert("19.33".to_string(), "random_add".to_string());
operations.insert("56.04".to_string(), "vendor".to_string());
operations.insert("14.85".to_string(), "element".to_string());
operations.insert("31.17".to_string(), "localstorage".to_string());
operations.insert("7.1".to_string(), "history".to_string());
operations.insert("75.89".to_string(), "ipinfo".to_string());
operations.insert("84.91".to_string(), "location".to_string());
operations.insert("30.7".to_string(), "random_1".to_string());
operations.insert("27.36".to_string(), "random_2".to_string());
Ok(operations)
}
/// Process and execute VM bytecode with full pipeline
pub fn process_bytecode(
turnstile: &str,
token: &str,
ip_info: &str,
) -> Result<Map<String, Value>> {
// Step 1: Decompile bytecode
let decompiled = Self::decompile_vm(turnstile, token)?;
// Step 2: Parse keys from decompiled code
let (xor_key, _parsed_keys) = Self::parse_keys(&decompiled)?;
// Step 3: Build payload
let mut payload = Map::new();
Self::add_vm_values(&mut payload, &xor_key, ip_info)?;
Ok(payload)
}
}