-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmod.rs
107 lines (91 loc) · 2.67 KB
/
mod.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use crate::game;
use crate::PROCESS_EVENT;
use std::ffi::c_void;
use std::mem;
use detours_sys::{
DetourAttach, DetourDetach, DetourTransactionBegin, DetourTransactionCommit,
DetourUpdateThread, LONG as DetourErrorCode,
};
use log::{error, info, warn};
use thiserror::Error;
use winapi::um::processthreadsapi::GetCurrentThread;
mod bitfield;
mod sdk;
#[derive(Error, Debug)]
pub enum Error {
#[error("detour error: {0} returned {1}")]
Detour(&'static str, DetourErrorCode),
}
/// A helper macro to call Detour functions and wrap any error codes into a
/// variant of the top-level `Error` enum.
macro_rules! det {
($call:expr) => {{
const NO_ERROR: DetourErrorCode = 0;
let error_code = $call;
if error_code == NO_ERROR {
Ok(())
} else {
Err(Error::Detour(stringify!($call), error_code))
}
}};
}
pub struct Hook;
impl Hook {
pub unsafe fn new() -> Result<Hook, Error> {
hook_process_event()?;
Ok(Hook)
}
}
impl Drop for Hook {
fn drop(&mut self) {
unsafe {
if let Err(e) = unhook_process_event() {
error!("{}", e);
}
}
}
}
unsafe fn hook_process_event() -> Result<(), Error> {
det!(DetourTransactionBegin())?;
det!(DetourUpdateThread(GetCurrentThread()))?;
det!(DetourAttach(&mut PROCESS_EVENT, my_process_event as *mut _))?;
det!(DetourTransactionCommit())?;
Ok(())
}
unsafe fn unhook_process_event() -> Result<(), Error> {
det!(DetourTransactionBegin())?;
det!(DetourUpdateThread(GetCurrentThread()))?;
det!(DetourDetach(&mut PROCESS_EVENT, my_process_event as *mut _))?;
det!(DetourTransactionCommit())?;
Ok(())
}
unsafe extern "fastcall" fn my_process_event(
this: &game::Object,
edx: usize,
function: &game::Function,
parameters: *mut c_void,
return_value: *mut c_void,
) {
type ProcessEvent = unsafe extern "fastcall" fn(
this: &game::Object,
_edx: usize,
function: &game::Function,
parameters: *mut c_void,
return_value: *mut c_void,
);
if let Some(full_name) = function.full_name() {
use std::collections::HashSet;
static mut UNIQUE_EVENTS: Option<HashSet<String>> = None;
if let Some(set) = UNIQUE_EVENTS.as_mut() {
if set.insert(full_name.clone()) {
info!("{}", full_name);
}
} else {
UNIQUE_EVENTS = Some(HashSet::new());
}
} else {
warn!("couldn't get full name");
}
let original = mem::transmute::<*mut c_void, ProcessEvent>(PROCESS_EVENT);
original(this, edx, function, parameters, return_value);
}