Initial commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
101
Cargo.lock
generated
Normal file
101
Cargo.lock
generated
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ahc-rs"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"ctor",
|
||||||
|
"gl",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ctor"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gl"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a94edab108827d67608095e269cf862e60d920f144a5026d3dbcfd8b877fb404"
|
||||||
|
dependencies = [
|
||||||
|
"gl_generator",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gl_generator"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
|
||||||
|
dependencies = [
|
||||||
|
"khronos_api",
|
||||||
|
"log",
|
||||||
|
"xml-rs",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "khronos_api"
|
||||||
|
version = "3.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.186"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.117"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xml-rs"
|
||||||
|
version = "0.8.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f"
|
||||||
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "ahc-rs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc = "0.2"
|
||||||
|
ctor = "0.2"
|
||||||
|
gl = "0.14"
|
||||||
52
load.sh
Executable file
52
load.sh
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Путь к скомпилированной библиотеке
|
||||||
|
LIB_NAME="libahc_rs.so"
|
||||||
|
LIB_PATH="$(pwd)/target/i686-unknown-linux-gnu/release/$LIB_NAME"
|
||||||
|
|
||||||
|
if [ ! -f "$LIB_PATH" ]; then
|
||||||
|
echo "[-] Ошибка: Файл $LIB_PATH не найден."
|
||||||
|
echo "[!] Сначала скомпилируйте проект: cargo build --release --target i686-unknown-linux-gnu"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Поиск процесса игры
|
||||||
|
GAME_PID=$(pidof hl_linux)
|
||||||
|
|
||||||
|
if [ -z "$GAME_PID" ]; then
|
||||||
|
echo "[+] Игра не запущена. Запуск через LD_PRELOAD..."
|
||||||
|
echo "[!] Убедитесь, что вы находитесь в папке с игрой или укажите полный путь."
|
||||||
|
|
||||||
|
# Пример запуска (путь может отличаться в зависимости от установки Steam)
|
||||||
|
# LD_PRELOAD="$LIB_PATH" ./hl.sh -game cstrike
|
||||||
|
|
||||||
|
echo "Введите команду для запуска CS 1.6 (например, ./hl.sh -game cstrike):"
|
||||||
|
read -r RUN_CMD
|
||||||
|
LD_PRELOAD="$LIB_PATH" eval "$RUN_CMD"
|
||||||
|
else
|
||||||
|
# Копируем библиотеку в /tmp с уникальным именем для форсированной перезагрузки
|
||||||
|
TIMESTAMP=$(date +%s)
|
||||||
|
TMP_LIB="/tmp/libahc_rs_$TIMESTAMP.so"
|
||||||
|
cp "$LIB_PATH" "$TMP_LIB"
|
||||||
|
chmod 777 "$TMP_LIB"
|
||||||
|
|
||||||
|
echo "[+] Инъекция: $TMP_LIB"
|
||||||
|
|
||||||
|
# Создаем временный файл команд для gdb
|
||||||
|
GDB_CMD=$(mktemp)
|
||||||
|
echo "attach $GAME_PID" > "$GDB_CMD"
|
||||||
|
echo "call (void*)dlopen(\"$TMP_LIB\", 2)" >> "$GDB_CMD"
|
||||||
|
echo "detach" >> "$GDB_CMD"
|
||||||
|
echo "quit" >> "$GDB_CMD"
|
||||||
|
|
||||||
|
# Запускаем gdb
|
||||||
|
sudo gdb -batch -x "$GDB_CMD"
|
||||||
|
|
||||||
|
rm "$GDB_CMD"
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "[+] Sucsess injected"
|
||||||
|
else
|
||||||
|
echo "[-] Ошибка при инъекции. Проверьте, установлен ли gdb и есть ли права sudo."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
166
src/lib.rs
Normal file
166
src/lib.rs
Normal 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; }
|
||||||
|
}
|
||||||
3
src/main.rs
Normal file
3
src/main.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
||||||
103
src/sdk.rs
Normal file
103
src/sdk.rs
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
use std::ffi::c_char;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone, Default)]
|
||||||
|
pub struct Vector {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
pub z: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const IN_ATTACK: u16 = 1 << 0;
|
||||||
|
pub const IN_JUMP: u16 = 1 << 1;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct UserCmd {
|
||||||
|
pub _pad0: [u8; 3],
|
||||||
|
pub viewangles: Vector,
|
||||||
|
pub forwardmove: f32,
|
||||||
|
pub sidemove: f32,
|
||||||
|
pub upmove: f32,
|
||||||
|
pub _pad1: [u8; 1],
|
||||||
|
pub buttons: u16,
|
||||||
|
pub _pad2: [u8; 18],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct EntityState {
|
||||||
|
pub _pad0: [u8; 12],
|
||||||
|
pub msgnum: i32,
|
||||||
|
pub _pad1: [u8; 72],
|
||||||
|
pub movetype: i32,
|
||||||
|
pub _pad2: [u8; 248],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Entity {
|
||||||
|
pub i: i32,
|
||||||
|
pub player: i32,
|
||||||
|
pub _pad0: [u8; 2 * 340],
|
||||||
|
pub curstate: EntityState,
|
||||||
|
pub _pad1: [u8; 1860],
|
||||||
|
pub origin: Vector,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct EventAPI {
|
||||||
|
pub _pad0: [u8; 0x18],
|
||||||
|
pub localplayerviewheight: extern "C" fn(*mut Vector),
|
||||||
|
pub _pad1: [u8; 0x40],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Engine {
|
||||||
|
pub _pad0: [u8; 0x8C],
|
||||||
|
pub setviewangles: extern "C" fn(*const Vector),
|
||||||
|
pub getmaxclients: extern "C" fn() -> i32,
|
||||||
|
pub _pad1: [u8; 0xC],
|
||||||
|
pub con_printf: extern "C" fn(*const c_char, ...),
|
||||||
|
pub _pad2: [u8; 0x28],
|
||||||
|
pub getlocalplayer: extern "C" fn() -> *mut Entity,
|
||||||
|
pub _pad3: [u8; 0x4],
|
||||||
|
pub getentitybyindex: extern "C" fn(i: i32) -> *mut Entity,
|
||||||
|
pub _pad4: [u8; 0x78],
|
||||||
|
pub eventapi: *mut EventAPI,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct RefParams {
|
||||||
|
pub vieworigin: Vector,
|
||||||
|
pub viewangles: Vector,
|
||||||
|
pub forward: Vector,
|
||||||
|
pub right: Vector,
|
||||||
|
pub up: Vector,
|
||||||
|
pub _pad0: [u8; 0x64],
|
||||||
|
pub punchangle: Vector,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Client {
|
||||||
|
pub _pad0: [u8; 0xC],
|
||||||
|
pub hudredraw: extern "C" fn(f32, i32) -> i32,
|
||||||
|
pub _pad1: [u8; 0x18], // Пропускаем до HUD_Key_Event (индекс 10)
|
||||||
|
pub hudkeyevent: extern "C" fn(i32, i32, *const c_char) -> i32,
|
||||||
|
pub _pad2: [u8; 0xC], // До CreateMove (индекс 14)
|
||||||
|
pub createmove: extern "C" fn(f32, *mut UserCmd, i32),
|
||||||
|
pub is3rdperson: extern "C" fn() -> i32,
|
||||||
|
pub cameraoffset: extern "C" fn(*mut Vector),
|
||||||
|
pub _pad3: [u8; 0x8],
|
||||||
|
pub calcrefdef: extern "C" fn(*mut RefParams),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const FL_ONGROUND: i32 = 1 << 9;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PlayerMove {
|
||||||
|
pub _pad0: [u8; 56],
|
||||||
|
pub origin: Vector,
|
||||||
|
pub _pad1: [u8; 24],
|
||||||
|
pub velocity: Vector,
|
||||||
|
pub _pad2: [u8; 80],
|
||||||
|
pub flags: i32,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user