Skip to content

Commit

Permalink
refactor detours + update win64 sigs
Browse files Browse the repository at this point in the history
  • Loading branch information
kusabana committed Jan 9, 2024
1 parent 683a541 commit 6e0278b
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 84 deletions.
159 changes: 80 additions & 79 deletions src/detour.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
use anyhow::Result;
use bzip2_rs::decoder::DecoderReader;
use gmod::{find_gmod_signature, open_library, type_alias};
use reqwest::StatusCode;
use rglua::prelude::*;
use std::ffi::OsString;
use std::ffi::{c_char, c_void, CStr, OsString};
use std::fs::File;
use std::io::copy;
use std::io::Cursor;
use std::path::Path;
use std::path::PathBuf;
use std::io::{copy, Cursor, Read};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::sync::Mutex;
use std::thread;
use std::thread::JoinHandle;
use std::time::Instant;
use std::{
ffi::{c_void, CStr},
os::raw::c_char,
};

use std::sync::Mutex;
use std::thread::{self, JoinHandle};

use anyhow::Result;
use gmod::detour::GenericDetour;
use rglua::prelude::*;

use crate::error::AcceleratorError;
use crate::log;

static mut GET_DOWNLOAD_QUEUE_SIZE_DETOUR: Option<
gmod::detour::GenericDetour<GetDownloadQueueSize>,
> = None;
static mut QUEUE_DOWNLOAD_DETOUR: Option<gmod::detour::GenericDetour<QueueDownload>> = None;
static mut DOWNLOAD_UPDATE_DETOUR: Option<gmod::detour::GenericDetour<DownloadUpdate>> = None;
// TODO:
// static VALVE_USER_AGENT: &str = "Half-Life 2";
// static REFERER: &str = "hl2://accelerator";

static mut GET_DOWNLOAD_QUEUE_SIZE_DETOUR: Option<GenericDetour<GetDownloadQueueSize>> = None;
static mut QUEUE_DOWNLOAD_DETOUR: Option<GenericDetour<QueueDownload>> = None;
static mut DOWNLOAD_UPDATE_DETOUR: Option<GenericDetour<DownloadUpdate>> = None;

struct DownloadState {
lua: LuaState,
Expand All @@ -46,17 +41,17 @@ impl DownloadState {

static mut STATE: Option<Mutex<DownloadState>> = None;

#[type_alias(GetDownloadQueueSize)]
unsafe extern "cdecl" fn GetDownloadQueueSize_detour() -> i64 {
#[gmod::type_alias(GetDownloadQueueSize)]
unsafe extern "cdecl" fn get_download_queue_size() -> i64 {
let binding = STATE.as_ref().unwrap();
let state = &mut binding.lock().unwrap();
let res: i64 = GET_DOWNLOAD_QUEUE_SIZE_DETOUR.as_ref().unwrap().call();

res + <usize as TryInto<i64>>::try_into(state.handles.len()).unwrap()
}

#[type_alias(QueueDownload)]
unsafe extern "cdecl" fn QueueDownload_detour(
#[gmod::type_alias(QueueDownload)]
unsafe extern "cdecl" fn queue_download(
this: *mut c_void,
c_url: *const c_char,
unk0: i32,
Expand Down Expand Up @@ -85,6 +80,7 @@ unsafe extern "cdecl" fn QueueDownload_detour(
url.is_empty(),
!as_http
);

return QUEUE_DOWNLOAD_DETOUR
.as_ref()
.unwrap()
Expand All @@ -105,34 +101,38 @@ unsafe extern "cdecl" fn QueueDownload_detour(

log!(state.lua, "dispatching `{}`", path.display());
let handle: JoinHandle<Result<String>> = thread::spawn(move || {
let client = reqwest::blocking::Client::new();
let client = reqwest::blocking::Client::builder()
.build()?;
let response = client
.get(format!("{}/{}", url, path.to_str().unwrap_or_default(),))
.get(format!("{}/{}", url, path.to_str().unwrap_or_default()))
.send()?;

if response.status() == StatusCode::OK {
if response.status().is_success() {
let mut content = Cursor::new(response.bytes()?);

let file_path = Path::new("garrysmod/download").join(path.with_extension(""));
std::fs::create_dir_all(file_path.parent().unwrap_or_else(|| return Path::new("")))?;
let mut dest = File::create_new(file_path)?;

let _ = if compressed {
copy(&mut DecoderReader::new(&mut content), &mut dest)
let mut reader: Box<dyn Read> = if compressed {
use bzip2_rs::decoder::DecoderReader;
Box::new(DecoderReader::new(&mut content))
} else {
copy(&mut content, &mut dest)
Box::new(content)
};

copy(&mut reader, &mut dest)?;
Ok(path.to_str().unwrap().to_string())
} else {
Err(AcceleratorError::RemoteFileNotFound(path.display().to_string(), url).into())
}
});

state.handles.push(handle);
}

#[type_alias(DownloadUpdate)]
unsafe extern "cdecl" fn DownloadUpdate_detour() -> bool {
#[gmod::type_alias(DownloadUpdate)]
unsafe extern "cdecl" fn download_update() -> bool {
let binding = STATE.as_ref().unwrap();
let mut state = binding.lock().unwrap();

Expand All @@ -141,8 +141,8 @@ unsafe extern "cdecl" fn DownloadUpdate_detour() -> bool {
let file = handle.join().unwrap();

match file {
Ok(file) => log!(state.lua, "finished `{}`", file),
Err(e) => log!(state.lua, "caught error: {}", e),
Ok(file) => log!(state.lua, "download finished: `{}`", file),
Err(e) => log!(state.lua, "download failed: {}", e),
}
}

Expand All @@ -157,48 +157,53 @@ unsafe extern "cdecl" fn DownloadUpdate_detour() -> bool {
return DOWNLOAD_UPDATE_DETOUR.as_ref().unwrap().call();
}

pub unsafe fn apply(l: LuaState) -> Result<()> {
log!(l, "applying detours");
pub unsafe fn apply(lua: LuaState) -> Result<()> {
log!(lua, "applying detours");

let state = DownloadState::new(l);
let state = DownloadState::new(lua);

let (_lib, path) = if cfg!(all(target_os = "linux", target_pointer_width = "64")) {
open_library!("engine_client")?
gmod::open_library!("engine_client")?
} else {
open_library!("engine")?
gmod::open_library!("engine")?
};

let GetDownloadQueueSize = find_gmod_signature!((_lib, path) -> {
win64_x86_64: [@SIG = "48 83 ec 28 48 8b 0d 85 5c 32 00 48 8b 01 ff 50 58 48 8b c8 48 8b 10 ff 52 10 03 05 88 ff 33 00 48 83 c4 28 c3"],
win32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself
macro_rules! detour_fn {
($func:ident, $type_alias:ty, ($library:ident, $path:ident) -> $pattern:tt) => {
let $func = {
let addr = gmod::find_gmod_signature!(($library, $path) -> $pattern)
.ok_or(AcceleratorError::SigNotFound)?;

linux64_x86_64: [@SIG = "55 48 89 e5 53 48 83 ec 08 48 8b 05 ?? ?? ?? ?? 8b 1d"],
linux32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself
let detour = GenericDetour::new::<$type_alias>(addr, $func)?;
detour.enable()?;
detour
};
}
}

detour_fn!(get_download_queue_size, GetDownloadQueueSize, (_lib, path) -> {
win64_x86_64: [@SIG = "48 83 ec 28 48 8b 0d ?? ?? ?? ?? 48 8b 01 ff 50 58 48 8b c8 48 8b 10 ff 52 10"],
win32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself

linux64_x86_64: [@SIG = "55 48 89 e5 53 48 83 ec 08 48 8b 05 ?? ?? ?? ?? 8b 1d"],
linux32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself

win32: [@SIG = "8b 0d ?? ?? ?? ?? 56 8b 01 ff 50 2c 8b 35 ?? ?? ?? ?? 8b c8 8b 10 ff 52 08 03 c6 5e c3"], // untested
linux32: [@SIG = "55 89 e5 53 83 ec 14 8b 15 ?? ?? ?? ?? 8b 1d ?? ?? ?? ?? 8b 02 89 14 24"], // untested
}).ok_or(AcceleratorError::SigNotFound)?;
let get_download_queue_size_detour = gmod::detour::GenericDetour::new::<GetDownloadQueueSize>(
GetDownloadQueueSize,
GetDownloadQueueSize_detour,
)?;
get_download_queue_size_detour.enable()?;

let DownloadUpdate = find_gmod_signature!((_lib, path) -> {
win64_x86_64: [@SIG = "48 83 ec 28 48 8b 0d ?? ?? ?? ?? 48 8b 01 ff 50 58 48 8b c8 48 8b 10 ff 52 08"],
win32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself

linux64_x86_64: [@SIG = "55 48 8d 3d ?? ?? ?? ?? 48 89 e5 5d e9 9f ff ff ff 90 90 90"],
linux32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself

win32: [@SIG = "55 8b ec 5d e9 87 05 00 00"], // untested
linux32: [@SIG = "55 89 e5 83 ec 18 c7 04 24 ?? ?? ?? ?? e8 9e ff ff ff c9 c3"], // untested
}).ok_or(AcceleratorError::SigNotFound)?;
let download_update_detour =
gmod::detour::GenericDetour::new::<DownloadUpdate>(DownloadUpdate, DownloadUpdate_detour)?;
download_update_detour.enable()?;

let QueueDownload = find_gmod_signature!((_lib, path) -> {
linux32: [@SIG = "55 89 e5 53 83 ec 14 8b 15 ?? ?? ?? ?? 8b 1d ?? ?? ?? ?? 8b 02 89 14 24"], // untested
});

detour_fn!(download_update, DownloadUpdate, (_lib, path) -> {
win64_x86_64: [@SIG = "48 83 ec 28 48 8b 0d ?? ?? ?? ?? 48 8b 01 ff 50 58 48 8b c8 48 8b 10 ff 52 08"],
win32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself

linux64_x86_64: [@SIG = "55 48 8d 3d ?? ?? ?? ?? 48 89 e5 5d e9 9f ff ff ff 90 90 90"],
linux32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself

win32: [@SIG = "55 8b ec 5d e9 87 05 00 00"], // untested
linux32: [@SIG = "55 89 e5 83 ec 18 c7 04 24 ?? ?? ?? ?? e8 9e ff ff ff c9 c3"], // untested
});

detour_fn!(queue_download, QueueDownload, (_lib, path) -> {
win64_x86_64: [@SIG = "40 53 55 56 57 41 54 41 55 41 56 41 57 48 81 ec 78 02 00 00"],
win32_x86_64: [@SIG = "00 00"], // open an issue if you need this sig, or find it yourself

Expand All @@ -207,23 +212,19 @@ pub unsafe fn apply(l: LuaState) -> Result<()> {

win32: [@SIG = "55 8b ec 51 83 3d ?? ?? ?? ?? 01 0f 8e 8f 01 00 00 8b 0d ?? ?? ?? ?? 53 8b 01 ff 50 2c 8b 5d"], // untested
linux32: [@SIG = "55 89 e5 57 56 53 81 ec 5c 02 00 00 8b 45 0c 8b 5d 08 8b 7d 1c"], // untested
})
.ok_or(AcceleratorError::SigNotFound)?;
let queue_download_detour =
gmod::detour::GenericDetour::new::<QueueDownload>(QueueDownload, QueueDownload_detour)?;
queue_download_detour.enable()?;
});

GET_DOWNLOAD_QUEUE_SIZE_DETOUR = Some(get_download_queue_size_detour);
QUEUE_DOWNLOAD_DETOUR = Some(queue_download_detour);
DOWNLOAD_UPDATE_DETOUR = Some(download_update_detour);
GET_DOWNLOAD_QUEUE_SIZE_DETOUR = Some(get_download_queue_size);
QUEUE_DOWNLOAD_DETOUR = Some(queue_download);
DOWNLOAD_UPDATE_DETOUR = Some(download_update);

STATE = Some(Mutex::new(state));

Ok(())
}

pub unsafe fn revert(l: LuaState) {
log!(l, "reverting detours");
pub unsafe fn revert(lua: LuaState) {
log!(lua, "reverting detours");

GET_DOWNLOAD_QUEUE_SIZE_DETOUR.take();
QUEUE_DOWNLOAD_DETOUR.take();
Expand Down
5 changes: 0 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
#![feature(c_unwind)]
#![feature(thread_id_value)]
#![feature(file_create_new)]
#![allow(non_snake_case)]

use anyhow::Result;
use rglua::prelude::*;

Expand Down

0 comments on commit 6e0278b

Please sign in to comment.