Skip to content

Instantly share code, notes, and snippets.

@Proximyst
Created April 10, 2019 17:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Proximyst/309bf4d60338cdd032c351d008611d9c to your computer and use it in GitHub Desktop.
Save Proximyst/309bf4d60338cdd032c351d008611d9c to your computer and use it in GitHub Desktop.
[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"]
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),
}
#[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,
}
}
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