Created
April 10, 2019 17:30
-
-
Save Proximyst/309bf4d60338cdd032c351d008611d9c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "cheat" | |
version = "0.1.0" | |
authors = ["Mariell Hoversholm <proximyst@proximyst.com>"] | |
edition = "2018" | |
[dependencies] | |
winapi = { version = "^0.3", features = ["std", "everything"] } | |
libc = { version = "^0.2", features = ["use_std", "extra_traits"] } | |
getset = "^0.0" | |
failure = "^0.1" | |
[lib] | |
name = "cheat" | |
crate-type = ["dylib"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use failure::{Error as FError, Fail}; | |
use std::result::Result as StdResult; | |
pub type Result<T> = StdResult<T, FError>; | |
#[derive(Debug, Fail)] | |
pub enum ProcessErrorKind { | |
#[fail(display = "Couldn't read memory at {:#X}", _0)] | |
MemoryRead(u32), | |
#[fail(display = "CreateToolhelp32Snapshot returned INVALID_HANDLE_VALUE")] | |
InvalidHandleValue, | |
#[fail(display = "Unknown module: {}", _0)] | |
UnknownModule(String), | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[cfg(not(target_os = "windows"))] | |
compile_error!("this only works for windows"); | |
pub mod error; | |
pub mod process; | |
use self::prelude::*; | |
pub mod prelude { | |
pub use super::error::*; | |
} | |
fn dll_attach(_base: winapi::shared::minwindef::LPVOID) -> Result<()> { | |
let process = self::process::GameProcess::current_process(); | |
println!("this was injected by Rust!"); | |
println!("the PID is {}", process.pid()); | |
Ok(()) | |
} | |
fn dll_detach() -> Result<()> { | |
println!("oh no!!"); | |
Ok(()) | |
} | |
unsafe extern "system" fn dll_attach_wrapper(base: winapi::shared::minwindef::LPVOID) -> u32 { | |
use std::panic; | |
match panic::catch_unwind(|| dll_attach(base)) { | |
Err(e) => { | |
eprintln!("`dll_attach` has panicked: {:#?}", e); | |
} | |
Ok(r) => match r { | |
Ok(()) => {} | |
Err(e) => { | |
eprintln!("`dll_attach` returned an Err: {:#?}", e); | |
} | |
}, | |
} | |
match panic::catch_unwind(|| dll_detach()) { | |
Err(e) => { | |
eprintln!("`dll_detach` has panicked: {:#?}", e); | |
} | |
Ok(r) => match r { | |
Ok(()) => {} | |
Err(e) => { | |
eprintln!("`dll_detach` returned an Err: {:#?}", e); | |
} | |
}, | |
} | |
winapi::um::libloaderapi::FreeLibraryAndExitThread(base as _, 1); | |
unreachable!() | |
} | |
#[no_mangle] | |
pub extern "stdcall" fn DllMain( | |
hinst_dll: winapi::shared::minwindef::HINSTANCE, | |
fdw_reason: winapi::shared::minwindef::DWORD, | |
lpv_reserved: winapi::shared::minwindef::LPVOID, | |
) -> i32 { | |
match fdw_reason { | |
winapi::um::winnt::DLL_PROCESS_ATTACH => { | |
unsafe { | |
winapi::um::libloaderapi::DisableThreadLibraryCalls(hinst_dll); | |
winapi::um::processthreadsapi::CreateThread( | |
std::ptr::null_mut(), | |
0, | |
Some(dll_attach_wrapper), | |
hinst_dll as _, | |
0, | |
std::ptr::null_mut(), | |
); | |
} | |
return true as i32; | |
} | |
winapi::um::winnt::DLL_PROCESS_DETACH => { | |
if !lpv_reserved.is_null() { | |
match std::panic::catch_unwind(|| dll_detach()) { | |
Err(e) => { | |
eprintln!("`dll_detach` has panicked: {:#?}", e); | |
} | |
Ok(r) => match r { | |
Ok(()) => {} | |
Err(e) => { | |
eprintln!("`dll_detach` returned an Err: {:#?}", e); | |
} | |
}, | |
} | |
} | |
return true as i32; | |
} | |
_ => true as i32, | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use super::prelude::*; | |
use getset::Getters; | |
use std::{ffi::OsString, mem, os::windows::ffi::OsStringExt}; | |
use winapi::um::{handleapi, memoryapi, processthreadsapi, tlhelp32, winnt}; | |
#[derive(Getters)] | |
#[get = "pub"] | |
pub struct GameProcess { | |
handle: winnt::HANDLE, | |
pid: u32, | |
} | |
#[derive(Getters)] | |
#[get = "pub"] | |
pub struct Module { | |
base: u32, | |
size: u32, | |
} | |
impl GameProcess { | |
pub fn current_process() -> Self { | |
Self::new(unsafe { processthreadsapi::GetCurrentProcess() }) | |
} | |
pub fn new(handle: winnt::HANDLE) -> Self { | |
let pid = unsafe { processthreadsapi::GetProcessId(handle) }; | |
GameProcess { handle, pid } | |
} | |
pub fn read_memory(&self, address: u32) -> Result<u32> { | |
let mut read = unsafe { mem::uninitialized() }; | |
let mut amount_read: libc::size_t = 0; | |
if unsafe { | |
memoryapi::ReadProcessMemory( | |
self.handle, | |
address as *const _, | |
&mut read as *mut _ as *mut _, | |
mem::size_of::<u32>() as _, | |
&mut amount_read as *mut _, | |
) | |
} != (true as _) | |
|| amount_read == 0 | |
{ | |
mem::forget(read); | |
return Err(ProcessErrorKind::MemoryRead(address).into()); | |
} | |
Ok(read) | |
} | |
pub fn get_module(&self, module_name: &str) -> Result<Module> { | |
let module = | |
unsafe { tlhelp32::CreateToolhelp32Snapshot(tlhelp32::TH32CS_SNAPMODULE, self.pid) }; | |
if module == handleapi::INVALID_HANDLE_VALUE { | |
return Err(ProcessErrorKind::InvalidHandleValue.into()); | |
} | |
let mut entry: tlhelp32::MODULEENTRY32W = unsafe { mem::zeroed() }; | |
entry.dwSize = mem::size_of::<tlhelp32::MODULEENTRY32W>() as _; | |
while unsafe { tlhelp32::Module32NextW(module, &mut entry) } != 0 { | |
let name = OsString::from_wide(&entry.szModule[..]).into_string(); | |
let name = match name { | |
Err(e) => { | |
eprintln!("Couldn't convert into String: {:?}", e); | |
continue; | |
} | |
Ok(s) => s, | |
}; | |
if name.contains(module_name) { | |
unsafe { handleapi::CloseHandle(module) }; | |
println!( | |
"Base address of {}: 0x{:X} @ size of 0x{:X}", | |
module_name, entry.modBaseAddr as u32, entry.modBaseSize | |
); | |
return Ok(Module { | |
base: entry.modBaseAddr as _, | |
size: entry.modBaseSize as _, | |
}); | |
} | |
} | |
Err(ProcessErrorKind::UnknownModule(module_name.into()).into()) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment