Initial commit

This commit is contained in:
2026-05-10 15:14:49 +03:00
commit db66b68a30
7 changed files with 438 additions and 0 deletions

166
src/lib.rs Normal file
View File

@@ -0,0 +1,166 @@
mod sdk;
use sdk::*;
use std::ffi::{CString, c_char, c_void};
use std::ptr;
use std::sync::atomic::{AtomicPtr, Ordering};
use libc::{dlopen, dlsym, dlclose, RTLD_LAZY, RTLD_NOLOAD, mprotect, PROT_READ, PROT_WRITE};
use std::fs::OpenOptions;
use std::io::Write;
static ENGINE: AtomicPtr<Engine> = AtomicPtr::new(ptr::null_mut());
static CLIENT: AtomicPtr<Client> = AtomicPtr::new(ptr::null_mut());
static PLAYER_MOVE: AtomicPtr<PlayerMove> = AtomicPtr::new(ptr::null_mut());
static mut ORIG_CLIENT: Option<Client> = None;
static mut FILL_RGBA_BOX: Option<extern "C" fn(i32, i32, i32, i32, i32, i32, i32, i32)> = None;
struct Settings {
show_menu: bool,
bhop: bool,
chams: bool,
}
static mut SETTINGS: Settings = Settings {
show_menu: false,
bhop: true,
chams: true,
};
fn log(msg: &str) {
if let Ok(mut file) = OpenOptions::new().create(true).append(true).open("/tmp/basturma.log") {
let _ = writeln!(file, "[DEBUG] {}", msg);
}
}
#[ctor::ctor]
fn init() {
log("Library injected. Starting search thread...");
std::thread::spawn(|| {
unsafe {
let mut hw = ptr::null_mut();
// Список возможных имен движка в Linux
let libs = [
b"hw.so\0".as_ptr() as *const c_char,
b"engine_i486.so\0".as_ptr() as *const c_char,
b"engine.so\0".as_ptr() as *const c_char,
b"./hw.so\0".as_ptr() as *const c_char,
b"hw_i386.so\0".as_ptr() as *const c_char,
];
log("Waiting for engine library to be loaded...");
for i in 0..500 { // Ждем до 50 секунд
for &lib in libs.iter() {
hw = dlopen(lib, RTLD_LAZY | RTLD_NOLOAD);
if !hw.is_null() {
let lib_name = std::ffi::CStr::from_ptr(lib).to_string_lossy();
log(&format!("Success! Found engine: {}", lib_name));
break;
}
}
if !hw.is_null() { break; }
std::thread::sleep(std::time::Duration::from_millis(100));
}
if hw.is_null() {
log("FATAL: Engine library not found after timeout!");
return;
}
setup(hw);
}
});
}
unsafe fn setup(hw: *mut c_void) {
log("Starting setup and symbol lookups...");
FILL_RGBA_BOX = std::mem::transmute(dlsym(hw, b"Draw_FillRGBA\0".as_ptr() as *const c_char));
if FILL_RGBA_BOX.is_some() { log("Found Draw_FillRGBA"); }
let engine_ptr = dlsym(hw, b"cl_enginefuncs\0".as_ptr() as *const c_char) as *mut Engine;
if !engine_ptr.is_null() {
ENGINE.store(engine_ptr, Ordering::SeqCst);
log("Found cl_enginefuncs");
} else {
log("WARNING: cl_enginefuncs not found via dlsym");
}
let client_ptr = dlsym(hw, b"cl_funcs\0".as_ptr() as *const c_char) as *mut Client;
if !client_ptr.is_null() {
CLIENT.store(client_ptr, Ordering::SeqCst);
ORIG_CLIENT = Some(*client_ptr);
let addr = client_ptr as usize;
let page_size = libc::sysconf(libc::_SC_PAGESIZE) as usize;
let page_start = addr & !(page_size - 1);
mprotect(page_start as *mut c_void, page_size, PROT_READ | PROT_WRITE);
(*client_ptr).createmove = hooked_createmove;
(*client_ptr).hudredraw = hooked_hudredraw;
(*client_ptr).hudkeyevent = hooked_hudkeyevent;
log("Hooks applied: CreateMove, HUD_Redraw, Key_Event");
}
let pmove_ptr_ptr = dlsym(hw, b"pmove\0".as_ptr() as *const c_char) as *mut *mut PlayerMove;
if !pmove_ptr_ptr.is_null() {
PLAYER_MOVE.store(*pmove_ptr_ptr, Ordering::SeqCst);
log("Found pmove");
}
dlclose(hw);
log("Setup complete!");
}
extern "C" fn hooked_hudkeyevent(eventcode: i32, keynum: i32, binding: *const c_char) -> i32 {
unsafe {
if eventcode == 1 && keynum == 146 { // INSERT
SETTINGS.show_menu = !SETTINGS.show_menu;
return 0;
}
if SETTINGS.show_menu && eventcode == 1 {
match keynum {
135 => { SETTINGS.bhop = !SETTINGS.bhop; return 0; } // F1
136 => { SETTINGS.chams = !SETTINGS.chams; return 0; } // F2
_ => {}
}
}
if let Some(orig) = ORIG_CLIENT {
(orig.hudkeyevent)(eventcode, keynum, binding)
} else { 1 }
}
}
extern "C" fn hooked_hudredraw(time: f32, intermission: i32) -> i32 {
unsafe {
if SETTINGS.show_menu {
if let Some(fill_box) = FILL_RGBA_BOX {
fill_box(100, 100, 200, 100, 0, 0, 0, 200);
let bhop_c = if SETTINGS.bhop { (0, 255, 0) } else { (255, 0, 0) };
fill_box(110, 130, 15, 15, bhop_c.0, bhop_c.1, bhop_c.2, 255);
let chams_c = if SETTINGS.chams { (0, 255, 0) } else { (255, 0, 0) };
fill_box(110, 160, 15, 15, chams_c.0, chams_c.1, chams_c.2, 255);
}
}
if let Some(orig) = ORIG_CLIENT { (orig.hudredraw)(time, intermission) } else { 0 }
}
}
extern "C" fn hooked_createmove(frametime: f32, cmd: *mut UserCmd, active: i32) {
unsafe {
if let Some(orig) = ORIG_CLIENT { (orig.createmove)(frametime, cmd, active); }
let engine = ENGINE.load(Ordering::SeqCst);
if engine.is_null() { return; }
let lp = ((*engine).getlocalplayer)();
if !lp.is_null() && SETTINGS.bhop { bhop(&mut *cmd); }
}
}
unsafe fn bhop(cmd: &mut UserCmd) {
if (cmd.buttons & IN_JUMP) == 0 { return; }
let pmove = PLAYER_MOVE.load(Ordering::SeqCst);
if pmove.is_null() { return; }
if ((*pmove).flags & FL_ONGROUND) == 0 { cmd.buttons &= !IN_JUMP; }
}