Skip to content

Instantly share code, notes, and snippets.

@darfink
Last active June 12, 2019 19:09
Show Gist options
  • Save darfink/f14145f8713d5ab156cfc20606b27e90 to your computer and use it in GitHub Desktop.
Save darfink/f14145f8713d5ab156cfc20606b27e90 to your computer and use it in GitHub Desktop.
Example of detouring MessageBoxW in Rust using detour-rs
#[macro_use]
extern crate detour;
extern crate winapi;
// --- std ---
use std::mem;
use std::ffi::CString;
// --- external ---
use kernel32::{GetModuleHandleW, GetProcAddress};
use winapi::{
ctypes::c_int,
shared::{
windef::HWND,
minwindef::{BOOL, DWORD, HINSTANCE, LPVOID, UINT, TRUE},
},
um::{
winnt::LPCWSTR,
winuser::MessageBoxW,
},
};
static_detours! {
struct DetourMessageBoxW: unsafe extern "system" fn(HWND, LPCWSTR, LPCWSTR, UINT) -> c_int;
}
fn message_boxw_detour(h_wnd: HWND, _: LPCWSTR, lp_caption: LPCWSTR, u_type: UINT) -> c_int {
// Simply forward the call to the original
let mut text: Vec<u16> = "Ops, hook by detour-rs.".encode_utf16().collect();
text.push(0);
unsafe { DetourMessageBoxW.get().unwrap().call(h_wnd, text.as_ptr() as _, lp_caption, u_type) }
}
type FnMessageBoxW = unsafe extern "system" fn(HWND, LPCWSTR, LPCWSTR, UINT) -> c_int;
#[no_mangle]
#[allow(non_snake_case, unused_variables)]
pub extern "system" fn DllMain(dll_module: HINSTANCE, call_reason: DWORD, reserved: LPVOID) -> BOOL {
const DLL_PROCESS_ATTACH: DWORD = 1;
if call_reason == DLL_PROCESS_ATTACH {
// Retrieve an absolute address of `MessageBoxW`
let address = lookup("user32.dll", "MessageBoxW").unwrap();
let target: FnMessageBoxW = unsafe { mem::transmute(address) };
let mut hook = unsafe { DetourMessageBoxW.initialize(MessageBoxW, message_boxw_detour).unwrap() };
unsafe { hook.enable().unwrap() };
// Omit the drop to persist the hook after the current scope.
// A better alternative is to define a variable with a longer lifetime.
mem::forget(hook);
}
return TRUE;
}
pub fn lookup(module: &str, symbol: &str) -> Option<usize> {
let mut module: Vec<u16> = module.encode_utf16().collect();
module.push(0);
let symbol = CString::new(symbol).unwrap();
unsafe {
let handle = GetModuleHandleW(module.as_ptr());
match GetProcAddress(handle, symbol.as_ptr()) as usize {
0 => None,
n => Some(n),
}
}
}
@AurevoirXavier
Copy link

cannot find macro static_detours! in this scope, help: you could try the macro: static_detour

after I change it to static_detour

no method named get found for type detour::StaticDetour<unsafe extern "system" fn(*mut winapi::shared::windef::HWND__, *const u16, *const u16, u32) -> i32> in the current scope

@AurevoirXavier
Copy link

Oh, It seems you update to the version 7.0 and remove get() method.

@darfink
Copy link
Author

darfink commented Jun 12, 2019

Yes, the StaticDetour interface has been simplified. You can see a CI-tested example here:
https://github.com/darfink/detour-rs/blob/master/examples/messageboxw_detour.rs

NOTE: It uses 2018 crate edition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment