refactor: extract hook::install() helper to reduce hook boilerplate
Browse filesEach hook installation was 12-14 lines of repeated MinHook setup.
New hook::install(name, addr, detour) handles create_hook, enable_hook,
and logging, returning the trampoline pointer. Each call site is now
4-5 lines.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
crates/openwa-wormkit/src/hook.rs
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//! MinHook helper for installing inline hooks on WA.exe functions.
|
| 2 |
+
|
| 3 |
+
use std::ffi::c_void;
|
| 4 |
+
|
| 5 |
+
use minhook::MinHook;
|
| 6 |
+
|
| 7 |
+
use crate::log_line;
|
| 8 |
+
use crate::rebase::rb;
|
| 9 |
+
|
| 10 |
+
/// Install a MinHook inline hook on a WA.exe function.
|
| 11 |
+
///
|
| 12 |
+
/// - `name`: human-readable name for log/error messages
|
| 13 |
+
/// - `ghidra_addr`: Ghidra VA of the target function (rebased automatically)
|
| 14 |
+
/// - `detour`: replacement function pointer
|
| 15 |
+
///
|
| 16 |
+
/// Returns the trampoline pointer (for calling the original).
|
| 17 |
+
/// Caller can store it in an `AtomicU32` if needed, or discard with `let _ =`.
|
| 18 |
+
pub unsafe fn install(
|
| 19 |
+
name: &str,
|
| 20 |
+
ghidra_addr: u32,
|
| 21 |
+
detour: *const (),
|
| 22 |
+
) -> Result<*mut c_void, String> {
|
| 23 |
+
let target = rb(ghidra_addr) as *mut c_void;
|
| 24 |
+
let detour = detour as *mut c_void;
|
| 25 |
+
|
| 26 |
+
let trampoline = MinHook::create_hook(target, detour)
|
| 27 |
+
.map_err(|e| format!("MinHook create_hook failed for {name}: {e}"))?;
|
| 28 |
+
|
| 29 |
+
MinHook::enable_hook(target)
|
| 30 |
+
.map_err(|e| format!("MinHook enable_hook failed for {name}: {e}"))?;
|
| 31 |
+
|
| 32 |
+
let _ = log_line(&format!(
|
| 33 |
+
" [REPLACE] {name}: target 0x{:08X}, trampoline 0x{:08X}",
|
| 34 |
+
target as u32, trampoline as u32
|
| 35 |
+
));
|
| 36 |
+
|
| 37 |
+
Ok(trampoline)
|
| 38 |
+
}
|
crates/openwa-wormkit/src/lib.rs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
| 2 |
|
| 3 |
use std::ffi::c_void;
|
| 4 |
|
|
|
|
| 5 |
pub mod rebase;
|
| 6 |
pub mod wa_call;
|
| 7 |
mod replacements;
|
|
|
|
| 2 |
|
| 3 |
use std::ffi::c_void;
|
| 4 |
|
| 5 |
+
pub mod hook;
|
| 6 |
pub mod rebase;
|
| 7 |
pub mod wa_call;
|
| 8 |
mod replacements;
|
crates/openwa-wormkit/src/replacements/frontend.rs
CHANGED
|
@@ -3,11 +3,8 @@
|
|
| 3 |
//! Original: 0x447A20, stdcall(screen_id), ESI = dialog this (__usercall).
|
| 4 |
//! Navigates between frontend menu screens via MFC CDialog::EndDialog.
|
| 5 |
|
| 6 |
-
use std::ffi::c_void;
|
| 7 |
use std::sync::atomic::{AtomicU32, Ordering};
|
| 8 |
|
| 9 |
-
use minhook::MinHook;
|
| 10 |
-
|
| 11 |
use crate::log_line;
|
| 12 |
use crate::rebase::rb;
|
| 13 |
use crate::wa_call;
|
|
@@ -97,21 +94,12 @@ unsafe extern "cdecl" fn frontend_change_screen_impl(dialog: u32, screen_id: u32
|
|
| 97 |
|
| 98 |
pub fn install() -> Result<(), String> {
|
| 99 |
unsafe {
|
| 100 |
-
let
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
MinHook::enable_hook(target)
|
| 107 |
-
.map_err(|e| format!("MinHook enable_hook failed for FrontendChangeScreen: {e}"))?;
|
| 108 |
-
|
| 109 |
ORIG_FRONTEND_CHANGE_SCREEN.store(trampoline_ptr as u32, Ordering::Relaxed);
|
| 110 |
-
|
| 111 |
-
let _ = log_line(&format!(
|
| 112 |
-
" [REPLACE] FrontendChangeScreen: target 0x{:08X}, trampoline 0x{:08X}",
|
| 113 |
-
target as u32, trampoline_ptr as u32
|
| 114 |
-
));
|
| 115 |
}
|
| 116 |
|
| 117 |
Ok(())
|
|
|
|
| 3 |
//! Original: 0x447A20, stdcall(screen_id), ESI = dialog this (__usercall).
|
| 4 |
//! Navigates between frontend menu screens via MFC CDialog::EndDialog.
|
| 5 |
|
|
|
|
| 6 |
use std::sync::atomic::{AtomicU32, Ordering};
|
| 7 |
|
|
|
|
|
|
|
| 8 |
use crate::log_line;
|
| 9 |
use crate::rebase::rb;
|
| 10 |
use crate::wa_call;
|
|
|
|
| 94 |
|
| 95 |
pub fn install() -> Result<(), String> {
|
| 96 |
unsafe {
|
| 97 |
+
let trampoline_ptr = crate::hook::install(
|
| 98 |
+
"FrontendChangeScreen",
|
| 99 |
+
va::FRONTEND_CHANGE_SCREEN,
|
| 100 |
+
trampoline as *const (),
|
| 101 |
+
)?;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
ORIG_FRONTEND_CHANGE_SCREEN.store(trampoline_ptr as u32, Ordering::Relaxed);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
}
|
| 104 |
|
| 105 |
Ok(())
|
crates/openwa-wormkit/src/replacements/scheme.rs
CHANGED
|
@@ -5,14 +5,11 @@
|
|
| 5 |
//! - Scheme__ValidateExtendedOptions (0x4D5110): pure Rust validation
|
| 6 |
//! - Scheme__FileExists (0x4D4CD0): Rust path check
|
| 7 |
|
| 8 |
-
use std::ffi::
|
| 9 |
use std::path::Path;
|
| 10 |
use std::sync::atomic::{AtomicU32, Ordering};
|
| 11 |
|
| 12 |
-
use minhook::MinHook;
|
| 13 |
-
|
| 14 |
use crate::log_line;
|
| 15 |
-
use crate::rebase::rb;
|
| 16 |
use openwa_types::address::va;
|
| 17 |
use openwa_types::scheme::{
|
| 18 |
ExtendedOptions, SchemeFile, SchemeVersion, EXTENDED_OPTIONS_DEFAULTS, EXTENDED_OPTIONS_SIZE,
|
|
@@ -225,62 +222,24 @@ unsafe extern "stdcall" fn hook_scheme_file_exists(name: u32) -> u32 {
|
|
| 225 |
|
| 226 |
pub fn install() -> Result<(), String> {
|
| 227 |
unsafe {
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
)
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
// Hook Scheme__ValidateExtendedOptions (0x4D5110) — full Rust replacement
|
| 248 |
-
{
|
| 249 |
-
let target = rb(va::SCHEME_VALIDATE_EXTENDED_OPTIONS) as *mut c_void;
|
| 250 |
-
let detour = trampoline_validate_ext_opts as *const () as *mut c_void;
|
| 251 |
-
|
| 252 |
-
MinHook::create_hook(target, detour).map_err(|e| {
|
| 253 |
-
format!("MinHook create_hook failed for ValidateExtendedOptions: {e}")
|
| 254 |
-
})?;
|
| 255 |
-
|
| 256 |
-
MinHook::enable_hook(target).map_err(|e| {
|
| 257 |
-
format!("MinHook enable_hook failed for ValidateExtendedOptions: {e}")
|
| 258 |
-
})?;
|
| 259 |
-
|
| 260 |
-
let _ = log_line(&format!(
|
| 261 |
-
" [REPLACE] Scheme__ValidateExtendedOptions: target 0x{:08X}",
|
| 262 |
-
target as u32
|
| 263 |
-
));
|
| 264 |
-
}
|
| 265 |
-
|
| 266 |
-
// Hook Scheme__FileExists (0x4D4CD0) — full Rust replacement
|
| 267 |
-
{
|
| 268 |
-
let target = rb(va::SCHEME_FILE_EXISTS) as *mut c_void;
|
| 269 |
-
let detour = hook_scheme_file_exists as *const () as *mut c_void;
|
| 270 |
-
|
| 271 |
-
MinHook::create_hook(target, detour).map_err(|e| {
|
| 272 |
-
format!("MinHook create_hook failed for Scheme__FileExists: {e}")
|
| 273 |
-
})?;
|
| 274 |
-
|
| 275 |
-
MinHook::enable_hook(target).map_err(|e| {
|
| 276 |
-
format!("MinHook enable_hook failed for Scheme__FileExists: {e}")
|
| 277 |
-
})?;
|
| 278 |
-
|
| 279 |
-
let _ = log_line(&format!(
|
| 280 |
-
" [REPLACE] Scheme__FileExists: target 0x{:08X}",
|
| 281 |
-
target as u32
|
| 282 |
-
));
|
| 283 |
-
}
|
| 284 |
}
|
| 285 |
|
| 286 |
Ok(())
|
|
|
|
| 5 |
//! - Scheme__ValidateExtendedOptions (0x4D5110): pure Rust validation
|
| 6 |
//! - Scheme__FileExists (0x4D4CD0): Rust path check
|
| 7 |
|
| 8 |
+
use std::ffi::CStr;
|
| 9 |
use std::path::Path;
|
| 10 |
use std::sync::atomic::{AtomicU32, Ordering};
|
| 11 |
|
|
|
|
|
|
|
| 12 |
use crate::log_line;
|
|
|
|
| 13 |
use openwa_types::address::va;
|
| 14 |
use openwa_types::scheme::{
|
| 15 |
ExtendedOptions, SchemeFile, SchemeVersion, EXTENDED_OPTIONS_DEFAULTS, EXTENDED_OPTIONS_SIZE,
|
|
|
|
| 222 |
|
| 223 |
pub fn install() -> Result<(), String> {
|
| 224 |
unsafe {
|
| 225 |
+
let trampoline = crate::hook::install(
|
| 226 |
+
"Scheme__ReadFile",
|
| 227 |
+
va::SCHEME_READ_FILE,
|
| 228 |
+
hook_scheme_read_file as *const (),
|
| 229 |
+
)?;
|
| 230 |
+
ORIG_SCHEME_READ_FILE.store(trampoline as u32, Ordering::Relaxed);
|
| 231 |
+
|
| 232 |
+
let _ = crate::hook::install(
|
| 233 |
+
"Scheme__ValidateExtendedOptions",
|
| 234 |
+
va::SCHEME_VALIDATE_EXTENDED_OPTIONS,
|
| 235 |
+
trampoline_validate_ext_opts as *const (),
|
| 236 |
+
)?;
|
| 237 |
+
|
| 238 |
+
let _ = crate::hook::install(
|
| 239 |
+
"Scheme__FileExists",
|
| 240 |
+
va::SCHEME_FILE_EXISTS,
|
| 241 |
+
hook_scheme_file_exists as *const (),
|
| 242 |
+
)?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 243 |
}
|
| 244 |
|
| 245 |
Ok(())
|