diff --git a/Cargo.toml b/Cargo.toml index 6cb9ddd..e6303d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,18 +1,18 @@ [package] name = "autorun" -version = "0.5.1" +version = "0.6.0" authors = ["Vurv78 "] -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] -crate-type = ["dylib"] +crate-type = ["cdylib"] [dependencies] rglua = { git = "https://github.com/Vurv78/rglua" } -detour = "0.8.1" +detour = { version = "0.8.1", default-features = false } # Global Mutable Variables once_cell = "1.8.0" @@ -20,11 +20,19 @@ atomic = "0.5.0" # Misc home = "0.5.3" -anyhow = "1.0.42" +anyhow = "1.0.44" +thiserror = "1.0.30" # Logging -chrono = "0.4.19" -log = "0.4.14" -simplelog = "0.10.0" +chrono = { version = "0.4.19", optional = true } +log = { version = "0.4.14", optional = true } +simplelog = { version = "0.11.0", optional = true } -regex = "1.5.4" \ No newline at end of file +regex = "1.5.4" + +[features] +default = ["runner"] +runner = [] + +# Disabled by default for now as this breaks autorun. +logging = ["chrono", "log", "simplelog"] \ No newline at end of file diff --git a/README.md b/README.md index 562bb3b..e9b6eec 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,11 @@ This file runs before every single lua script run on your client from addons and local script = sautorun.CODE if script:find("while true do end") then sautorun.log("Found an evil script!") - return true -- Exit from here & don't run the script + -- Run our modified script that will replace all ``while true do end`` with ``while false do end``. 😎 + + return string.Replace(script, "while true do end", "while false do end") + + -- OR: return true to not run the script at all. end ``` __autorun.lua__ @@ -73,10 +77,12 @@ sautorun.log( "Connected to server " .. sautorun.IP, DEBUG ) ``` ## Logging -Autorun automatically writes logs to a log file whenever you boot up a game for your security and for easy debugging. -Check the sautorun-rs/logs directory for crash dumps & logs if you use something like [Safety](https://github.com/Vurv78/Safety) to log HTTP requests, etc. +Autorun features logging under the ``logging`` feature. You need to build it yourself to enable this. +It will be re-enabled in the future when it is fixed. + +> Autorun automatically writes logs to a log file whenever you boot up a game for your security and for easy debugging. +> Check the sautorun-rs/logs directory for crash dumps & logs if you use something like [Safety](https://github.com/Vurv78/Safety) to log HTTP requests, etc. ## Building 1. [Setup Rust & Cargo](https://www.rust-lang.org/learn/get-started) -2. Use ``build_win_32.bat`` or ``build_win_64.bat``. -**This requires Nightly** (in order to use ``thiscall`` and ``static_detour!``) +2. Use ``build_win_32.bat`` or ``build_win_64.bat``. \ No newline at end of file diff --git a/build_win_32.bat b/build_win_32.bat index f2957d2..0f5c480 100644 --- a/build_win_32.bat +++ b/build_win_32.bat @@ -1,5 +1,12 @@ @echo off -rustup target add i686-pc-windows-msvc -cargo build --target=i686-pc-windows-msvc -move %cd%\target\i686-pc-windows-msvc\debug\Autorun.dll %cd%\gmsv_autorun_win32.dll +set file_name=autorun.dll + +set target=i686-pc-windows-msvc +set target_dir=%cd%\target\%target%\release +set out=%cd%\gmsv_autorun_win32.dll + +rustup target add %target% +cargo build --release --target=%target% + +move %target_dir%\%file_name% %out% pause \ No newline at end of file diff --git a/build_win_64.bat b/build_win_64.bat index eccd115..f00ac43 100644 --- a/build_win_64.bat +++ b/build_win_64.bat @@ -1,4 +1,12 @@ @echo off -cargo build -move %cd%\target\debug\Autorun.dll %cd%\gmsv_autorun_win64.dll +set file_name=autorun.dll + +set target=x86_64-pc-windows-msvc +set target_dir=%cd%\target\%target%\release +set out=%cd%\gmsv_autorun_win64.dll + +rustup target add %target% +cargo build --release --target=%target% + +move %target_dir%\%file_name% %out% pause \ No newline at end of file diff --git a/src/detours/lazy.rs b/src/detours/lazy.rs new file mode 100644 index 0000000..3650f84 --- /dev/null +++ b/src/detours/lazy.rs @@ -0,0 +1,22 @@ +#[macro_export] +macro_rules! lazy_detour { + // Lazy Path + ( $vis:vis static $name:ident : $t:ty = ($target:expr, $tour:expr) ; $($rest:tt)* ) => { + $vis static $name: once_cell::sync::Lazy< detour::GenericDetour< $t > > = once_cell::sync::Lazy::new(|| unsafe { + match detour::GenericDetour::new( $target, $tour ) { + Ok(b) => { + b.enable().expect( concat!("Failed to enable detour '", stringify!($name), "'") ); + b + }, + Err(why) => panic!( concat!("Failed to create hook '", stringify!($name), "' {}"), why) + } + }); + lazy_detour!( $($rest)* ); + }; + // OnceCell Path + ( $vis:vis static $name:ident : $t:ty ; $($rest:tt)* ) => { + $vis static $name: once_cell::sync::OnceCell> = once_cell::sync::OnceCell::new(); + lazy_detour!( $($rest)* ); + }; + () => (); +} \ No newline at end of file diff --git a/src/detours/mod.rs b/src/detours/mod.rs index e199562..d77fa91 100644 --- a/src/detours/mod.rs +++ b/src/detours/mod.rs @@ -1,41 +1,50 @@ use std::{fs, io::prelude::*, sync::atomic::Ordering}; use crate::sys::{ - util::{self, getAutorunHandle, getClientState, setClientState}, + util::{getAutorunHandle, setClientState}, runlua::runLuaEnv, statics::* }; use rglua::{ lua_shared::{self, *}, types::*, - rstring, - interface::IPanel + rstring }; -use detour::static_detour; - const LUA_BOOL: i32 = rglua::globals::Lua::Type::Bool as i32; const LUA_STRING: i32 = rglua::globals::Lua::Type::String as i32; -static_detour! { - pub static luaL_newstate_h: extern "C" fn() -> LuaState; - pub static luaL_loadbufferx_h: extern "C" fn(LuaState, *const i8, SizeT, *const i8, *const i8) -> CInt; - pub static joinserver_h: extern "C" fn(LuaState) -> CInt; - pub static paint_traverse_h: extern "thiscall" fn(&'static IPanel, usize, bool, bool); +#[macro_use] +pub mod lazy; + +// Make our own static detours because detours.rs is lame and locked theirs behind nightly. :) +lazy_detour! { + pub static LUAL_NEWSTATE_H: extern "C" fn() -> LuaState = (*lua_shared::luaL_newstate, luaL_newstate); + pub static LUAL_LOADBUFFERX_H: extern "C" fn(LuaState, *const i8, SizeT, *const i8, *const i8) -> CInt = (*lua_shared::luaL_loadbufferx, luaL_loadbufferx); + pub static JOINSERVER_H: extern "C" fn(LuaState) -> CInt; +} + +#[cfg(feature = "runner")] +use rglua::interface::IPanel; + +#[cfg(feature = "runner")] +lazy_detour! { + static PAINT_TRAVERSE_H: extern "fastcall" fn(&'static IPanel, usize, bool, bool); } -fn luaL_newstate() -> LuaState { - let state = luaL_newstate_h.call(); +extern "C" fn luaL_newstate() -> LuaState { + let state = LUAL_NEWSTATE_H.call(); debug!("Got client state through luaL_newstate"); setClientState(state); state } -fn luaL_loadbufferx(state: LuaState, mut code: *const i8, mut size: SizeT, identifier: *const i8, mode: *const i8) -> CInt { +extern "C" fn luaL_loadbufferx(state: LuaState, mut code: *const i8, mut size: SizeT, identifier: *const i8, mode: *const i8) -> CInt { use crate::sys::util::initMenuState; if MENU_STATE.get().is_none() { - initMenuState(state) - .expect("Couldn't initialize menu state"); + if let Err(why) = initMenuState(state) { + error!("Couldn't initialize menu state. {}", why); + } } // Todo: Check if you're in menu state (Not by checking MENU_DLL because that can be modified by lua) and if so, don't dump files. @@ -44,18 +53,16 @@ fn luaL_loadbufferx(state: LuaState, mut code: *const i8, mut size: SizeT, ident let server_ip = CURRENT_SERVER_IP.load( Ordering::Relaxed ); let mut do_run = true; - if raw_path == "lua/includes/init.lua" { - if HAS_AUTORAN.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed).is_ok() { - // This will only run once when HAS_AUTORAN is false, setting it to true. - // Will be reset by JoinServer. - if let Ok(script) = fs::read_to_string(&*AUTORUN_SCRIPT_PATH) { - // Try to run here - if let Err(why) = runLuaEnv(&script, identifier, code, server_ip, true) { - error!("{}", why); - } - } else { - error!( "Couldn't read your autorun script file at {}/{}", SAUTORUN_DIR.display(), AUTORUN_SCRIPT_PATH.display() ); + if raw_path == "lua/includes/init.lua" && HAS_AUTORAN.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed).is_ok() { + // This will only run once when HAS_AUTORAN is false, setting it to true. + // Will be reset by JoinServer. + if let Ok(script) = fs::read_to_string(&*AUTORUN_SCRIPT_PATH) { + // Try to run here + if let Err(why) = runLuaEnv(&script, identifier, code, server_ip, true) { + error!("{}", why); } + } else { + error!( "Couldn't read your autorun script file at [{}]", AUTORUN_SCRIPT_PATH.display() ); } } @@ -91,31 +98,34 @@ fn luaL_loadbufferx(state: LuaState, mut code: *const i8, mut size: SizeT, ident if do_run { // Call the original function and return the value. - return luaL_loadbufferx_h.call( state, code, size, identifier, mode ); + return LUAL_LOADBUFFERX_H.call( state, code, size, identifier, mode ); } 0 } // Since the first lua state will always be the menu state, just keep a variable for whether joinserver has been hooked or not, // If not, then hook it. -pub fn joinserver(state: LuaState) -> CInt { - let ip = rstring!( lua_tolstring(state, 1, 0) ); +pub extern "C" fn joinserver(state: LuaState) -> CInt { + let ip = rstring!(lua_tolstring(state, 1, 0)); info!("Joining Server with IP {}!", ip); CURRENT_SERVER_IP.store(ip, Ordering::Relaxed); // Set the IP so we know where to write files in loadbufferx. HAS_AUTORAN.store(false, Ordering::Relaxed); - joinserver_h.call(state) + JOINSERVER_H.get().unwrap().call(state) } -fn paint_traverse(this: &'static IPanel, panel_id: usize, force_repaint: bool, force_allow: bool) { - paint_traverse_h.call(this, panel_id, force_repaint, force_allow); +#[cfg(feature = "runner")] +extern "fastcall" fn paint_traverse(this: &'static IPanel, panel_id: usize, force_repaint: bool, force_allow: bool) { + use crate::sys::util::{self, getClientState}; + + PAINT_TRAVERSE_H.get().unwrap().call(this, panel_id, force_repaint, force_allow); let script_queue = &mut *LUA_SCRIPTS .lock() .unwrap(); - if script_queue.len() > 0 { + if !script_queue.is_empty() { let (realm, script) = script_queue.remove(0); let state = match realm { @@ -123,28 +133,21 @@ fn paint_traverse(this: &'static IPanel, panel_id: usize, force_repaint: bool, f REALM_CLIENT => getClientState() }; - if state == std::ptr::null_mut() { return; } + if state.is_null() { return; } match util::lua_dostring(state, &script) { Err(why) => { error!("{}", why); }, Ok(_) => { - info!("Code [#{}] ran successfully.", script.len()) + info!("Script of len #{} ran successfully.", script.len()) } } } } -pub unsafe fn init() -> Result<(), detour::Error> { - luaL_loadbufferx_h - .initialize(*lua_shared::luaL_loadbufferx, luaL_loadbufferx)? - .enable()?; - - luaL_newstate_h - .initialize(*lua_shared::luaL_newstate, luaL_newstate)? - .enable()?; - +#[cfg(feature = "runner")] +unsafe fn init_paint_traverse() -> Result<(), detour::Error> { use rglua::interface::*; let vgui_interface = get_from_interface( "VGUI_Panel009", get_interface_handle("vgui2.dll").unwrap() ) @@ -152,7 +155,7 @@ pub unsafe fn init() -> Result<(), detour::Error> { let panel_interface = vgui_interface.as_ref().unwrap(); - type PaintTraverseFn = extern "thiscall" fn(&'static IPanel, usize, bool, bool); + type PaintTraverseFn = extern "fastcall" fn(&'static IPanel, usize, bool, bool); // Get painttraverse raw function object to detour. let painttraverse: PaintTraverseFn = std::mem::transmute( (panel_interface.vtable as *mut *mut CVoid) @@ -160,18 +163,33 @@ pub unsafe fn init() -> Result<(), detour::Error> { .read() ); - paint_traverse_h - .initialize( painttraverse, paint_traverse )? - .enable()?; + let detour = detour::GenericDetour::new(painttraverse, paint_traverse)?; + + PAINT_TRAVERSE_H.set(detour); + PAINT_TRAVERSE_H.get().unwrap().enable()?; + + Ok(()) +} + +pub unsafe fn init() -> Result<(), detour::Error> { + use once_cell::sync::Lazy; + + Lazy::force(&LUAL_LOADBUFFERX_H); + Lazy::force(&LUAL_NEWSTATE_H); + + #[cfg(feature = "runner")] + init_paint_traverse()?; Ok(()) } pub unsafe fn cleanup() -> Result<(), detour::Error>{ - luaL_loadbufferx_h.disable()?; - luaL_newstate_h.disable()?; - joinserver_h.disable()?; - paint_traverse_h.disable()?; + LUAL_LOADBUFFERX_H.disable()?; + LUAL_NEWSTATE_H.disable()?; + JOINSERVER_H.get().unwrap().disable()?; + + #[cfg(feature = "runner")] + PAINT_TRAVERSE_H.get().unwrap().disable()?; Ok(()) } \ No newline at end of file diff --git a/src/input.rs b/src/input.rs index 4dc9cf2..2612d00 100644 --- a/src/input.rs +++ b/src/input.rs @@ -6,11 +6,9 @@ pub(crate) fn try_process_input() -> anyhow::Result<()> { let mut buffer = String::new(); std::io::stdin().read_line(&mut buffer)?; - let (word, rest) = buffer.split_once(' ').unwrap_or( (&buffer.trim_end(), "") ); + let (word, rest) = buffer.split_once(' ').unwrap_or( (buffer.trim_end(), "") ); let rest_trim = rest.trim_end(); - debug!("Command used: [{}], rest [{}]", word, rest); - match word { "lua_run_cl" => if let Err(why) = runLua(REALM_CLIENT, rest.to_owned()) { error!("{}", why); @@ -29,9 +27,8 @@ pub(crate) fn try_process_input() -> anyhow::Result<()> { "lua_openscript_menu" => match std::fs::read_to_string( Path::new( rest ) ) { Err(why) => error!("Errored on lua_openscript. [{}]", why), - Ok(contents) => match runLua( REALM_MENU, contents ) { - Err(why) => error!("Errored on lua_openscript. {}", why), - _ => () + Ok(contents) => if let Err(why) = runLua( REALM_MENU, contents ) { + error!("Errored on lua_openscript. {}", why); } }, diff --git a/src/lib.rs b/src/lib.rs index 9254dc1..3d151be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,92 +1,97 @@ #![allow(non_snake_case)] -#![feature(abi_thiscall)] use std::{sync::mpsc, thread}; +#[cfg(feature = "logging")] #[macro_use] extern crate log; + +#[cfg(feature = "logging")] extern crate simplelog; +#[macro_use] +mod logging; + use once_cell::sync::OnceCell; mod input; // Console input mod sys; // Configs mod detours; -mod logging; -const SENDER: OnceCell< mpsc::Sender<()> > = OnceCell::new(); +static SENDER: OnceCell< mpsc::SyncSender<()> > = OnceCell::new(); const DLL_PROCESS_ATTACH: u32 = 1; const DLL_PROCESS_DETACH: u32 = 0; extern "system" { - fn AllocConsole() -> i32; - fn FreeConsole() -> i32; + fn AllocConsole() -> bool; + fn FreeConsole() -> bool; fn GetLastError() -> u32; } -fn init() { - if let Err(why) = logging::init() { - eprintln!("Couldn't start logging module. [{}]", why); - return; - } +fn init() -> anyhow::Result<()> { + logging::init()?; unsafe { - assert_eq!( - AllocConsole(), 1, - "Couldn't allocate console. Error id: [{}]", GetLastError() - ); - } + if !AllocConsole() { + // Assume a console already exists and just log an error. + error!("Failed to allocate console. {}", GetLastError()); + } - if let Err(why) = unsafe { detours::init() } { - error!("Fatal error when setting up detours. {}", why); - return; + detours::init()?; } debug!("Initialized."); println!("<---> Autorun-rs <--->"); println!("Type [help] for the list of commands"); - let (sender, receiver) = mpsc::channel(); + let (sender, receiver) = mpsc::sync_channel(1); thread::spawn(move || loop { + use mpsc::TryRecvError::*; if input::try_process_input().is_ok() { // Got a command continue; } match receiver.try_recv() { - Ok(_) => { - break; - }, - Err( mpsc::TryRecvError::Disconnected ) => { - break; - }, - Err( mpsc::TryRecvError::Empty ) => () + Ok(_) | Err(Disconnected) => break, + Err(Empty) => () } }); - SENDER.set(sender).expect("Couldn't set mpsc kill channel!"); + if SENDER.set(sender).is_err() { + anyhow::bail!("Failed to set sender."); + } + + Ok(()) } -fn cleanup() { - // Detour cleanups - if let Err(why) = unsafe { detours::cleanup() } { - error!("Failed to cleanup all detours. {}", why); +fn cleanup() -> anyhow::Result<()> { + unsafe { detours::cleanup()? }; + + if let Some(sender) = SENDER.get() { + sender.send(())?; } unsafe { FreeConsole(); }; - if let Some(sender) = SENDER.get() { - sender.send(()).expect("Couldn't send mpsc kill message"); - } + Ok(()) } // Windows Only. I'm not going to half-ass Linux support (And don't even get me to try and work with OSX..) #[no_mangle] pub extern "system" fn DllMain(_: *const u8, reason: u32, _: *const u8) -> u32 { match reason { - DLL_PROCESS_ATTACH => init(), - DLL_PROCESS_DETACH => cleanup(), + DLL_PROCESS_ATTACH => { + if let Err(why) = init() { + error!("Failed to inject Autorun. [{}]", why); + } + }, + DLL_PROCESS_DETACH => { + if let Err(why) = cleanup() { + error!("Failed to inject Autorun. [{}]", why); + } + }, _ => () } 1 @@ -97,14 +102,21 @@ use rglua::types::LuaState; #[no_mangle] pub extern "C" fn gmod13_open(state: LuaState) -> i32 { use crate::sys::util::initMenuState; - init(); - initMenuState(state) - .expect("Couldn't initialize menu state."); + if let Err(why) = init() { + error!("Failed to open Autorun module. [{}]", why); + return 0; + } + + if let Err(why) = initMenuState(state) { + error!("Couldn't initialize menu state! [{}]", why); + } 0 } #[no_mangle] pub extern "C" fn gmod13_close(_state: LuaState) -> i32 { - cleanup(); + if let Err(why) = cleanup() { + error!("Failed to close Autorun module. [{}]", why); + } 0 } \ No newline at end of file diff --git a/src/logging.rs b/src/logging.rs index 9ad5761..3bd6e71 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -1,10 +1,10 @@ -use simplelog::*; - -use chrono::prelude::*; -use std::fs::File; -use crate::sys::statics::SAUTORUN_LOG_DIR; - +#[cfg(feature = "logging")] pub fn init() -> anyhow::Result<()> { + use chrono::prelude::*; + use std::fs::File; + use crate::sys::statics::SAUTORUN_LOG_DIR; + use simplelog::*; + if !SAUTORUN_LOG_DIR.exists() { std::fs::create_dir_all(&*SAUTORUN_LOG_DIR)?; } @@ -35,5 +35,53 @@ pub fn init() -> anyhow::Result<()> { ] )?; + Ok(()) +} + +// Stderr +#[cfg(not(feature = "logging"))] +macro_rules! warn { + ($($arg:tt)*) => { + eprintln!( $($arg)* ) + }; +} + +// Will never print (unless logging is enabled) +#[cfg(not(feature = "logging"))] +macro_rules! trace { + ($($arg:tt)*) => { () }; +} + +// Regular stdout +#[cfg(not(feature = "logging"))] +macro_rules! info { + ($($arg:tt)*) => { + println!( $($arg)* ) + }; +} + +// Only prints when in a debug build. +#[cfg(all(not(feature = "logging"), debug_assertions))] +macro_rules! debug { + ($($arg:tt)*) => { + println!( $($arg)* ) + }; +} + +// We are in a release build, don't print anything. +#[cfg(all(not(feature = "logging"), not(debug_assertions)))] +macro_rules! debug { + ($($arg:tt)*) => { () }; +} + +// Print to stderr +#[cfg(not(feature = "logging"))] +macro_rules! error { + ($($arg:tt)*) => { + eprintln!( $($arg)* ) + }; +} + +pub fn init() -> anyhow::Result<()> { Ok(()) } \ No newline at end of file diff --git a/src/sys/runlua.rs b/src/sys/runlua.rs index 98f8ae9..92c8862 100644 --- a/src/sys/runlua.rs +++ b/src/sys/runlua.rs @@ -9,7 +9,6 @@ use crate::{ use rglua::{globals::Lua::{self, GLOBALSINDEX}, lua_shared::*, rstring, types::LuaState}; -const LUA_REGISTRYINDEX: i32 = -10000; const NO_LUA_STATE: &str = "Didn't run lua code, lua state is not valid/loaded!"; const INVALID_LOG_LEVEL: *const i8 = "Invalid log level (Should be 1-5, 1 being Error, 5 being Trace)\0".as_ptr() as *const i8; @@ -25,7 +24,7 @@ pub fn runLua(realm: Realm, code: String) -> Result<(), &'static str>{ }, REALM_CLIENT => { let s = getClientState(); - if s == std::ptr::null_mut() { return Err("Client state has not been loaded. Join a server!"); } + if s.is_null() { return Err("Client state has not been loaded. Join a server!"); } s } }; @@ -40,7 +39,7 @@ pub fn runLua(realm: Realm, code: String) -> Result<(), &'static str>{ extern "C" fn log(state: LuaState) -> i32 { let s = luaL_checklstring(state, 1, 0); - let level = luaL_optinteger(state, 2, simplelog::Level::Info as isize); + let level = luaL_optinteger(state, 2, 3); // INFO by default let str = rstring!(s); match level { @@ -62,8 +61,9 @@ extern "C" fn sautorun_require(state: LuaState) -> i32 { let raw_path = luaL_checklstring(state, 1, 0); - // Lua 5.4 style loading rather than package.loaded - lua_getfield( state, LUA_REGISTRYINDEX, "_LOADED\0".as_ptr() as *const i8 ); + lua_getfield(state, rglua::globals::Lua::GLOBALSINDEX, "sautorun\0".as_ptr() as *const i8 ); + lua_getfield( state, rglua::globals::Lua::GLOBALSINDEX, "package\0".as_ptr() as *const i8 ); + lua_getfield( state, rglua::globals::Lua::GLOBALSINDEX, "loaded\0".as_ptr() as *const i8 ); lua_getfield( state, 2, raw_path ); if lua_toboolean(state, -1) != 0 { return 1; @@ -81,14 +81,10 @@ extern "C" fn sautorun_require(state: LuaState) -> i32 { let mut script = String::new(); if let Err(why) = handle.read_to_string(&mut script) { error!( "Failed to read script from file [{}]. Reason: {}", path.display(), why ); - } else { - if let Err(why) = util::lua_dostring(state, &script) { - error!("Error when requiring [{}]. [{}]", path.display(), why); - } else { - if lua_type(state, -1) == Lua::Type::Nil as i32 { - println!("nil"); - } - } + } else if let Err(why) = util::lua_dostring(state, &script) { + error!("Error when requiring [{}]. [{}]", path.display(), why); + } else if lua_type(state, -1) == Lua::Type::Nil as i32 { + println!("nil"); } } } @@ -100,7 +96,7 @@ extern "C" fn sautorun_require(state: LuaState) -> i32 { pub fn runLuaEnv(script: &str, identifier: *const i8, dumped_script: *const i8, ip: &str, startup: bool) -> Result { let state = getClientState(); - if state == std::ptr::null_mut() { + if state.is_null() { return Err( NO_LUA_STATE.to_owned() ); } @@ -133,10 +129,11 @@ pub fn runLuaEnv(script: &str, identifier: *const i8, dumped_script: *const i8, lua_pushcfunction( state, log ); lua_setfield( state, -2, "log\0".as_ptr() as *const i8 ); - lua_createtable( state, 0, 0 ); // local t = {} + /*lua_createtable( state, 0, 0 ); // local t = {} lua_createtable( state, 0, 0 ); // local t2 = {} lua_setfield( state, -2, "loaded\0".as_ptr() as *const i8 ); // package.loaded = t2 - lua_setfield( state, -2, "packages\0".as_ptr() as *const i8 ); // package = t + lua_setfield( state, -2, "package\0".as_ptr() as *const i8 ); // package = t + */ lua_pushcfunction( state, sautorun_require ); lua_setfield( state, -2, "require\0".as_ptr() as *const i8 ); diff --git a/src/sys/statics.rs b/src/sys/statics.rs index f55b62e..95ab0c1 100644 --- a/src/sys/statics.rs +++ b/src/sys/statics.rs @@ -9,6 +9,7 @@ use rglua::types::*; // ---------------- Configs ---------------- // pub static HOME_DIR: Lazy = Lazy::new(|| home::home_dir().expect("Couldn't get your home directory!") ); pub static SAUTORUN_DIR: Lazy = Lazy::new(|| HOME_DIR.join("sautorun-rs") ); +#[cfg(feature = "logging")] pub static SAUTORUN_LOG_DIR: Lazy = Lazy::new(|| SAUTORUN_DIR.join("logs") ); pub static SAUTORUN_SCRIPT_DIR: Lazy = Lazy::new(|| SAUTORUN_DIR.join("scripts") ); @@ -29,8 +30,9 @@ pub static CURRENT_SERVER_IP: Atomic<&'static str> = Atomic::new pub static HAS_AUTORAN: AtomicBool = AtomicBool::new(false); // Whether an autorun script has been run and detected already. pub static MENU_STATE: OnceCell> = OnceCell::new(); +type LuaScript = Vec<(bool, String)>; // Scripts waiting to be ran in painttraverse -pub static LUA_SCRIPTS: Lazy>>> = Lazy::new(|| { +pub static LUA_SCRIPTS: Lazy>> = Lazy::new(|| { Arc::new( Mutex::new( Vec::new() ) ) }); diff --git a/src/sys/util.rs b/src/sys/util.rs index d9c9bc8..b1ab8ec 100644 --- a/src/sys/util.rs +++ b/src/sys/util.rs @@ -12,7 +12,7 @@ use rglua::{ const LUA_OK: i32 = 0; -use crate::detours::luaL_loadbufferx_h; +use crate::detours::LUAL_LOADBUFFERX_H; use crate::sys::{ statics::* }; @@ -64,22 +64,23 @@ pub fn getAutorunHandle(garry_dir: &str, server_ip: &str) -> Option { pub fn initMenuState(state: LuaState) -> Result<(), detour::Error> { use rglua::lua_shared::*; use std::sync::atomic::AtomicPtr; - use crate::detours::{joinserver_h, joinserver}; + use crate::detours::{JOINSERVER_H, joinserver}; - MENU_STATE - .set( AtomicPtr::from(state) ) - .expect("MENU_STATE was occupied in gmod13_open. Shouldn't happen."); + if MENU_STATE.set( AtomicPtr::from(state) ).is_err() { + error!("MENU_STATE was occupied in gmod13_open. Shouldn't happen."); + } - info!("Init menu state"); + info!("Loaded into menu state."); lua_getglobal( state, "JoinServer\0".as_ptr() as *const i8 ); let joinserver_fn = lua_tocfunction(state, -1); lua_pop(state, 1); unsafe { - joinserver_h - .initialize(joinserver_fn, joinserver)? - .enable()?; + let hook = detour::GenericDetour::new(joinserver_fn, joinserver)?; + JOINSERVER_H + .set(hook).unwrap(); + JOINSERVER_H.get().unwrap().enable().unwrap(); } Ok(()) @@ -115,7 +116,7 @@ const REPL: &str = "_"; // Returns a string that is safe to use as a file path pub fn sanitizePath>(input: T) -> String { - let path = ILLEGAL.replace_all(&input.as_ref(), REPL); + let path = ILLEGAL.replace_all(input.as_ref(), REPL); let path = CONTROL_RESERVED.replace_all(&path, REPL); let path = RESERVED.replace_all(&path, REPL); let path = WINDOWS_RESERVED.replace_all(&path, REPL); @@ -127,7 +128,7 @@ pub fn sanitizePath>(input: T) -> String { pub fn lua_compilestring(state: LuaState, code: &str) -> Result<(), &'static str> { - if luaL_loadbufferx_h.call( + if LUAL_LOADBUFFERX_H.call( state, code.as_ptr() as *const i8, code.len(),