Skip to content

Commit

Permalink
0.2.0 (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
Vurv78 authored May 23, 2021
1 parent 2879a9f commit ee2d315
Show file tree
Hide file tree
Showing 8 changed files with 433 additions and 312 deletions.
21 changes: 11 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "Autorun"
version = "0.1.1"
version = "0.2.0"
authors = ["Vurv78 <[email protected]>"]
edition = "2018"

Expand All @@ -10,16 +10,17 @@ edition = "2018"
crate-type = ["dylib"]

[dependencies]
# detour-rs static detours needs nightly, which sucks since nightly breaks rls, I don't wanna bother trying to search up how to fix that.
detour = { version = "0.7.1", default-features = false }

libc = "0.2.85" # FFI Types
winapi = {version = "0.3.9", features = ["consoleapi"]}
# lua_shared bindings
rglua = { git = "https://github.com/Vurv78/rglua", branch = "main" }

# DLL Loading
dlopen = "0.1.8"
dlopen_derive = "0.1.4"
# Detour lua_loadbufferx and other functions
detour = { version = "0.8.0", default-features = false }

dirs = "3.0.1" # To get your home directory.
# Global Mutable Variables
once_cell = "1.7.2"
atomic = "0.5.0"

lazy_static = "1.4.0"
# Misc
winapi = {version = "0.3.9", features = ["consoleapi"]}
dirs = "3.0.1" # To get your home directory.
49 changes: 30 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
## Autorun-rs [![Release Shield](https://img.shields.io/github/v/release/Vurv78/Autorun-rs)](https://github.com/Vurv78/Autorun-rs/releases/latest) [![License](https://img.shields.io/github/license/Vurv78/Autorun-rs?color=red)](https://opensource.org/licenses/Apache-2.0) ![CI](https://github.com/Vurv78/Autorun-rs/workflows/Build/badge.svg) [![github/Vurv78](https://discordapp.com/api/guilds/824727565948157963/widget.png)](https://discord.gg/epJFC6cNsw)
# Autorun-rs
[![Release Shield](https://img.shields.io/github/v/release/Vurv78/Autorun-rs)](https://github.com/Vurv78/Autorun-rs/releases/latest)
[![License](https://img.shields.io/github/license/Vurv78/Autorun-rs?color=red)](https://opensource.org/licenses/Apache-2.0)
![CI](https://github.com/Vurv78/Autorun-rs/workflows/Build/badge.svg) [![github/Vurv78](https://img.shields.io/discord/824727565948157963?color=7289DA&label=chat&logo=discord)](https://discord.gg/epJFC6cNsw)

Garrysmod Lua Dumper / Runner, written in Rust.

Like my other repo, https://github.com/Vurv78/Autorun, but written in Rust.
Also, this has more features and is safer.

The file structure starts at C:\Users\User\sautorun-rs\.
The file structure starts at ``C:\Users\<User>\sautorun-rs\``

### Features
* Lua dumping through hooked loadbufferx at C:\Users\User\sautorun-rs\lua_dumps\ServerIP\... (Use init_file_steal)
* Lua loading through lua_run and lua_openscript
* Could load lua scripts before autorun.
* Not supported out of the box, could add it yourself relatively easily
* Separate AllocConsole that allows for running commands (See the help command)
* Works for both x64 and x86 windows. (Tested on Chromium / x86-64 branch)
* Dumping all lua scripts to ``C:\Users\<User>\sautorun-rs\lua_dumps\<ServerIP>\..``
* Runtime lua loading through lua_run and lua_openscript in an external console
* Supports x86 and x64 bit
* Scripthook, stop & run scripts before anything runs on you, gives information & functions to assist in a safe separate lua fenv

### Usage
Get an injector (Make sure it's compatible to inject 32/64 bit code depending on your use).
Use one of the build_win batchfiles to build the output dll, then inject that into garrysmod at the main menu.
See the Notes for more info.

### TODOs
* Automating JoinServer hook
* Making a lua script in sautorun run before autorun out of the box.

### Notes
This is Windows ONLY. Autorun might've had a chance at being multi-platform but this is absolutely not going to work with OSX/Linux.
You need to call init_file_steal in your garrysmod main menu in the Autorun terminal, so that files will be dumped.
* For now this is only supporting Windows.
In the future this may be able to run on Linux/OSX but if that does happen I won't be able to actively support it.

### Examples

sautorun-rs/hook.lua
```lua
local script = sautorun.CODE
if script:find("while true do end") then
sautorun.log("Found a naughty script!")
return true -- Exit from here & don't run the script
end
```

sautorun-rs/autorun.lua
```lua
sautorun.log( "Connected to server " .. sautorun.IP )
```

### TODOs
* Actual GUI
118 changes: 118 additions & 0 deletions src/hooks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use std::{
io::prelude::*,
sync::atomic::Ordering,
ffi::CStr,
fs
};

use crate::sys::{
funcs::getAutorunHandle,
statics::*,
runlua::runLuaEnv
};

use rglua::{
lua_shared::*,
types::*
};

#[macro_export]
macro_rules! get_cstring {
($cstring:expr) => {
{
#[allow(unused_unsafe)]
let cstr = unsafe{ CStr::from_ptr($cstring) };
cstr.to_owned()
}
}
}

pub extern fn loadbufferx(state: LuaState, code: CharBuf, size: SizeT, identifier: CharBuf, mode: CharBuf) -> CInt {
if state != std::ptr::null_mut() {
CURRENT_LUA_STATE.store(state, Ordering::Relaxed);
}

// If JoinServer hasn't been hooked, hook it.
let _ = JOIN_SERVER.get_or_try_init(|| {
lua_getglobal!( state, cstring!("JoinServer") );
let hook = match unsafe { detour::GenericDetour::new( lua_tocfunction(state, -1), crate::hooks::joinserver ) } {
Ok(hook) => {
unsafe {
hook.enable().expect("Couldn't enable JoinServer hook");
}

Ok(hook)
}
Err(why) => {
eprintln!("Couldn't hook JoinServer. {}", why);
return Err(());
}
};
lua_pop!(state, 1);
hook
});

// 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.
// Dump the file to sautorun-rs/lua_dumps/IP/...
let raw_path = &rstring!(identifier)[1 ..]; // Remove the @ from the beginning of the path.
let server_ip = CURRENT_SERVER_IP.load( Ordering::Relaxed );

let loadbuffer_h = &*LUAL_LOADBUFFERX;

let mut autoran = false;
let mut do_run = true;
if raw_path == "lua/includes/init.lua" {
if let Ok(_) = HAS_AUTORAN.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) {
// 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
runLuaEnv(&script, identifier, code, server_ip, true);
autoran = true;
} else {
eprintln!( "Couldn't read your autorun script file at {}/{}", SAUTORUN_DIR.display(), AUTORUN_SCRIPT_PATH.display() );
}
}
}

if !autoran {
if let Ok(script) = fs::read_to_string(&*HOOK_SCRIPT_PATH) {
if runLuaEnv(&script, identifier, code, server_ip, false) {
// If you return ``true`` in your sautorun/hook.lua file, then don't run the sautorun.CODE that is about to run.
if lua_type(state, 1) == rglua::globals::Lua::Type::Bool as i32 {
do_run = lua_toboolean(state, 1) == 0;
lua_pop!(state, 1);
}
}
}

}

if let Some(mut file) = getAutorunHandle(raw_path, server_ip) {
if let Err(why) = file.write_all( get_cstring!(code).as_bytes() ) {
eprintln!("Couldn't write to file made from lua path [{}]. {}", raw_path, why);
}
}

if do_run {
return loadbuffer_h.call( state, code, size, identifier, mode ); // Call the original function and return the value.
}
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 extern fn joinserver(state: LuaState) -> CInt {
let ip = rstring!( lua_tolstring(state, 1, 0) );
println!("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);
if let Some(hook) = JOIN_SERVER.get() {
// We could retrieve the hook from our global variables
hook.call(state);
} else {
eprintln!("Failed to get JOIN_SERVER hook from global state");
}
0
}
Loading

0 comments on commit ee2d315

Please sign in to comment.