From 3e4e7be4867e31b5eccfd614c42509e0c715ff7e Mon Sep 17 00:00:00 2001
From: Striven <sg.striven@cutecat.club>
Date: Wed, 21 Jan 2026 22:05:56 +0000
Subject: [PATCH] Bring HookSingleton from Spring
---
src/hook_singleton.zig | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
src/root.zig | 2 ++
2 files changed, 51 insertions(+), 0 deletions(-)
diff --git a/src/hook_singleton.zig b/src/hook_singleton.zig
new file mode 100644
index 0000000..849fc70
--- /dev/null
+++ b/src/hook_singleton.zig
@@ -0,0 +1,49 @@
+const std = @import("std");
+const minhook = @import("minhook");
+const win32 = @import("win32").everything;
+
+const memory = @import("memory.zig");
+
+pub fn HookSingleton(comptime log_scope: @Type(.enum_literal), comptime function_ref: memory.Function, comptime detour_function: anytype) type {
+ return struct {
+ pub const scope = log_scope;
+ pub const log = std.log.scoped(log_scope);
+
+ pub const function = function_ref;
+ pub const detour = detour_function;
+
+ const Fn = @TypeOf(detour_function);
+
+ pub var is_hooked: bool = false;
+
+ pub var function_call_ptr: *const Fn = undefined;
+ pub var minhook_hook: minhook.Hook(*const Fn) = undefined;
+ pub var trampoline: *const Fn = undefined;
+
+ pub fn create() !void {
+ function_call_ptr = try function.inCurrentProcess();
+ minhook_hook = try .create(function_call_ptr, detour_function, &trampoline);
+ }
+
+ pub fn createFromThunk(jmp_offset: usize) !void {
+ const thunk_ref = try function.inCurrentProcess();
+ const thunk_bytes: [*]const u8 = @ptrCast(thunk_ref);
+
+ const jmp_displacement = std.mem.readInt(u32, &thunk_bytes[jmp_offset..][3..7].*, .little);
+ const jmp_rip = thunk_bytes + jmp_offset + 7;
+
+ const new_ptr: *const ?*const anyopaque = @ptrCast(@alignCast(jmp_rip + jmp_displacement));
+ function_call_ptr = @ptrCast(new_ptr.*);
+
+ log.info("Thunk offset: {x} + {x} = {x}", .{ @intFromPtr(jmp_rip), jmp_displacement, @intFromPtr(new_ptr) });
+
+ minhook_hook = try .create(function_call_ptr, detour_function, &trampoline);
+ }
+
+ pub fn enable() !void {
+ try minhook_hook.enable();
+ log.info("Enabled hook! {x} -> {x}", .{ @intFromPtr(function_call_ptr), @intFromPtr(&detour_function) });
+ is_hooked = true;
+ }
+ };
+}
diff --git a/src/root.zig b/src/root.zig
index 037774e..df73da5 100644
--- a/src/root.zig
+++ b/src/root.zig
@@ -1,3 +1,5 @@
+pub const HookSingleton = @import("hook_singleton.zig").HookSingleton;
+
pub const memory = @import("memory.zig");
pub const Module = @import("Module.zig");
pub const Pattern = @import("Pattern.zig");
--
Gitblit v1.10.0