1use crate::{AddonApi, MinHookApi};
6use std::{ffi::c_void, ptr};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11#[cfg_attr(
12 feature = "strum",
13 derive(
14 strum::AsRefStr,
15 strum::Display,
16 strum::EnumCount,
17 strum::EnumIter,
18 strum::IntoStaticStr,
19 strum::VariantArray,
20 strum::VariantNames
21 )
22)]
23#[repr(C)]
24pub enum HookStatus {
25 Unknown = -1,
27
28 Ok = 0,
30
31 ErrorAlreadyInitialized,
33
34 ErrorNotInitialized,
36
37 ErrorAlreadyCreated,
39
40 ErrorNotCreated,
42
43 ErrorEnabled,
45
46 ErrorDisabled,
48
49 ErrorNotExecutable,
52
53 ErrorUnsupportedFunction,
55
56 ErrorMemoryAlloc,
58
59 ErrorMemoryProtect,
61
62 ErrorModuleNotFound,
64
65 ErrorFunctionNotFound,
67}
68
69impl HookStatus {
70 #[inline]
72 pub fn is_ok(&self) -> bool {
73 matches!(self, Self::Ok)
74 }
75
76 #[inline]
78 pub fn ok(self) -> Result<(), Self> {
79 self.ok_then(())
80 }
81
82 pub fn ok_then<T>(self, value: T) -> Result<T, Self> {
84 match self {
85 Self::Ok => Ok(value),
86 _ => Err(self),
87 }
88 }
89}
90
91pub type RawHookCreate = unsafe extern "system-unwind" fn(
92 target: *const c_void,
93 detour: *const c_void,
94 trampoline: *mut *const c_void,
95) -> HookStatus;
96
97pub type RawHookRemove = unsafe extern "system-unwind" fn(target: *const c_void) -> HookStatus;
98
99pub type RawHookEnable = unsafe extern "system-unwind" fn(target: *const c_void) -> HookStatus;
100
101pub type RawHookDisable = unsafe extern "system-unwind" fn(target: *const c_void) -> HookStatus;
102
103#[inline]
110pub unsafe fn create_hook_raw(
111 target: *const (),
112 detour: *const (),
113) -> Result<*const (), HookStatus> {
114 let mut original = ptr::null();
115 let MinHookApi { create, .. } = AddonApi::get().min_hook;
116 let result = unsafe { create(target.cast(), detour.cast(), &mut original) };
117 result.ok_then(original.cast())
118}
119
120#[inline]
122pub fn remove_hook_raw(target: *const ()) -> Result<(), HookStatus> {
123 let MinHookApi { remove, .. } = AddonApi::get().min_hook;
124 let result = unsafe { remove(target.cast()) };
125 result.ok()
126}
127
128#[inline]
130pub fn enable_hook_raw(target: *const ()) -> Result<(), HookStatus> {
131 let MinHookApi { enable, .. } = AddonApi::get().min_hook;
132 let result = unsafe { enable(target.cast()) };
133 result.ok()
134}
135
136#[inline]
138pub fn disable_hook_raw(target: *const ()) -> Result<(), HookStatus> {
139 let MinHookApi { disable, .. } = AddonApi::get().min_hook;
140 let result = unsafe { disable(target.cast()) };
141 result.ok()
142}
143
144#[cfg(feature = "hook")]
145mod bindings {
146 use super::*;
147 use retour::{Function, HookableWith};
148
149 pub fn create_hook<F, D>(target: F, detour: D) -> Result<*const (), HookStatus>
153 where
154 F: Function + HookableWith<D>,
155 D: Function,
156 {
157 unsafe { create_hook_raw(target.to_ptr(), detour.to_ptr()) }
158 }
159
160 pub fn create_hook_enabled<F, D>(target: F, detour: D) -> Result<*const (), HookStatus>
164 where
165 F: Function + HookableWith<D>,
166 D: Function,
167 {
168 let trampoline = create_hook(target, detour)?;
169 enable_hook(target)?;
170 Ok(trampoline)
171 }
172
173 pub fn remove_hook(target: impl Function) -> Result<(), HookStatus> {
175 remove_hook_raw(target.to_ptr())
176 }
177
178 pub fn enable_hook(target: impl Function) -> Result<(), HookStatus> {
180 enable_hook_raw(target.to_ptr())
181 }
182
183 pub fn disable_hook(target: impl Function) -> Result<(), HookStatus> {
185 disable_hook_raw(target.to_ptr())
186 }
187}
188
189#[cfg(feature = "hook")]
190pub use bindings::*;