Last active
June 12, 2019 19:09
-
-
Save darfink/f14145f8713d5ab156cfc20606b27e90 to your computer and use it in GitHub Desktop.
Example of detouring MessageBoxW in Rust using detour-rs
This file contains hidden or 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
#[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), | |
} | |
} | |
} |
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
Oh, It seems you update to the version 7.0 and remove
get()
method.