Browse Source

Merge pull request #4720 from jpark37/detours-integration

Finish Detours integration for remaining game capture APIs
Jim 4 years ago
parent
commit
84bf08c171

+ 0 - 285
plugins/win-capture/funchook.c

@@ -1,285 +0,0 @@
-#include <windows.h>
-#include <stdlib.h>
-#include "funchook.h"
-
-#define JMP_64_SIZE 14
-#define JMP_32_SIZE 5
-
-#define X86_NOP 0x90
-#define X86_JMP_NEG_5 0xF9EB
-
-static inline void fix_permissions(void *addr, size_t size)
-{
-	DWORD protect_val;
-	VirtualProtect(addr, size, PAGE_EXECUTE_READWRITE, &protect_val);
-}
-
-void hook_init(struct func_hook *hook, void *func_addr, void *hook_addr,
-	       const char *name)
-{
-	memset(hook, 0, sizeof(*hook));
-
-	hook->func_addr = (uintptr_t)func_addr;
-	hook->hook_addr = (uintptr_t)hook_addr;
-	hook->name = name;
-
-	fix_permissions((void *)(hook->func_addr - JMP_32_SIZE),
-			JMP_64_SIZE + JMP_32_SIZE);
-
-	memcpy(hook->unhook_data, func_addr, JMP_64_SIZE);
-}
-
-static inline size_t patch_size(struct func_hook *hook)
-{
-	return hook->is_64bit_jump ? JMP_64_SIZE : JMP_32_SIZE;
-}
-
-static const uint8_t longjmp64[6] = {0xFF, 0x25, 0x00, 0x00, 0x00, 0x00};
-
-static inline void rehook64(struct func_hook *hook)
-{
-	uint8_t data[JMP_64_SIZE];
-	uintptr_t *ptr_loc = (uintptr_t *)((uint8_t *)data + sizeof(longjmp64));
-
-	fix_permissions((void *)hook->func_addr, JMP_64_SIZE);
-
-	memcpy(data, (void *)hook->func_addr, JMP_64_SIZE);
-	memcpy(data, longjmp64, sizeof(longjmp64));
-	*ptr_loc = hook->hook_addr;
-
-	hook->call_addr = (void *)hook->func_addr;
-	hook->type = HOOKTYPE_FORWARD_OVERWRITE;
-	hook->hooked = true;
-
-	memcpy((void *)hook->func_addr, data, JMP_64_SIZE);
-}
-
-static inline void hook_reverse_new(struct func_hook *hook, uint8_t *p)
-{
-	hook->call_addr = (void *)(hook->func_addr + 2);
-	hook->type = HOOKTYPE_REVERSE_CHAIN;
-	hook->hooked = true;
-
-	p[0] = 0xE9;
-	*((uint32_t *)&p[1]) = (uint32_t)(hook->hook_addr - hook->func_addr);
-	*((uint16_t *)&p[5]) = X86_JMP_NEG_5;
-}
-
-static inline void hook_reverse_chain(struct func_hook *hook, uint8_t *p)
-{
-	if (hook->type != HOOKTYPE_FORWARD_OVERWRITE)
-		return;
-
-	hook->call_addr = (void *)(hook->func_addr + *((int32_t *)&p[1]));
-	hook->type = HOOKTYPE_REVERSE_CHAIN;
-	hook->hooked = true;
-
-	*((uint32_t *)&p[1]) = (uint32_t)(hook->hook_addr - hook->func_addr);
-}
-
-static inline void hook_forward_chain(struct func_hook *hook, uint8_t *p,
-				      intptr_t offset)
-{
-	int32_t cur_offset = *(int32_t *)&p[6];
-
-	if (hook->type != HOOKTYPE_FORWARD_OVERWRITE)
-		return;
-
-	hook->call_addr = (void *)(hook->func_addr + JMP_32_SIZE + cur_offset);
-	hook->type = HOOKTYPE_FORWARD_CHAIN;
-	hook->hooked = true;
-
-	*((int32_t *)&p[6]) = (int32_t)offset;
-}
-
-static inline void hook_forward_overwrite(struct func_hook *hook,
-					  intptr_t offset)
-{
-	uint8_t *ptr = (uint8_t *)hook->func_addr;
-
-	hook->call_addr = (void *)hook->func_addr;
-	hook->type = HOOKTYPE_FORWARD_OVERWRITE;
-	hook->hooked = true;
-
-	*(ptr++) = 0xE9;
-	*((int32_t *)ptr) = (int32_t)offset;
-}
-
-static inline void rehook32(struct func_hook *hook, bool force, intptr_t offset)
-{
-	fix_permissions((void *)(hook->func_addr - JMP_32_SIZE),
-			JMP_32_SIZE * 2);
-
-	if (force || !hook->started) {
-		uint8_t *p = (uint8_t *)hook->func_addr - JMP_32_SIZE;
-		size_t nop_count = 0;
-
-		/* check for reverse chain hook availability */
-		for (size_t i = 0; i < JMP_32_SIZE; i++) {
-			if (p[i] == X86_NOP)
-				nop_count++;
-		}
-
-		if (nop_count == JMP_32_SIZE && p[5] == 0x8B && p[6] == 0xFF) {
-			hook_reverse_new(hook, p);
-
-		} else if (p[0] == 0xE9 &&
-			   *(uint16_t *)&p[5] == X86_JMP_NEG_5) {
-			hook_reverse_chain(hook, p);
-
-		} else if (p[5] == 0xE9) {
-			hook_forward_chain(hook, p, offset);
-
-		} else if (hook->type != HOOKTYPE_FORWARD_OVERWRITE) {
-			hook->type = HOOKTYPE_FORWARD_OVERWRITE;
-		}
-
-		hook->started = true;
-	}
-
-	if (hook->type == HOOKTYPE_FORWARD_OVERWRITE) {
-		hook_forward_overwrite(hook, offset);
-	}
-}
-
-/*
- * Creates memory close to the target function, used to force the actual hook
- * to use a 32bit jump instead of a 64bit jump, thus preventing the chance of
- * overwriting adjacent functions, which can cause a crash.  (by R1CH)
- */
-static void setup_64bit_bounce(struct func_hook *hook, intptr_t *offset)
-{
-	MEMORY_BASIC_INFORMATION mbi;
-	uintptr_t address;
-	uintptr_t newdiff;
-	SYSTEM_INFO si;
-	bool success;
-	int pagesize;
-	int i;
-
-	success = VirtualQueryEx(GetCurrentProcess(),
-				 (const void *)hook->func_addr, &mbi,
-				 sizeof(mbi));
-	if (!success)
-		return;
-
-	GetSystemInfo(&si);
-	pagesize = (int)si.dwAllocationGranularity;
-
-	address = (uintptr_t)mbi.AllocationBase - pagesize;
-	for (i = 0; i < 256; i++, address -= pagesize) {
-		hook->bounce_addr = VirtualAlloc((LPVOID)address, pagesize,
-						 MEM_RESERVE | MEM_COMMIT,
-						 PAGE_EXECUTE_READWRITE);
-		if (hook->bounce_addr)
-			break;
-	}
-
-	if (!hook->bounce_addr) {
-		address = (uintptr_t)mbi.AllocationBase + mbi.RegionSize +
-			  pagesize;
-		for (i = 0; i < 256; i++, address += pagesize) {
-			hook->bounce_addr =
-				VirtualAlloc((LPVOID)address, pagesize,
-					     MEM_RESERVE | MEM_COMMIT,
-					     PAGE_EXECUTE_READWRITE);
-			if (hook->bounce_addr)
-				break;
-		}
-	}
-
-	if (!hook->bounce_addr)
-		return;
-
-	if ((hook->func_addr + 5) > (uintptr_t)hook->bounce_addr)
-		newdiff = hook->func_addr + 5 - (uintptr_t)hook->bounce_addr;
-	else
-		newdiff = (uintptr_t)hook->bounce_addr - hook->func_addr + 5;
-
-	if (newdiff <= 0x7ffffff0) {
-		uint8_t *addr = (uint8_t *)hook->bounce_addr;
-
-		FillMemory(hook->bounce_addr, pagesize, 0xCC);
-
-		*(addr++) = 0xFF;
-		*(addr++) = 0x25;
-		*((uint32_t *)addr) = 0;
-		*((uint64_t *)(addr + 4)) = hook->hook_addr;
-
-		hook->hook_addr = (uint64_t)hook->bounce_addr;
-		*offset = hook->hook_addr - hook->func_addr - JMP_32_SIZE;
-		hook->is_64bit_jump = false;
-	}
-}
-
-void do_hook(struct func_hook *hook, bool force)
-{
-	intptr_t offset;
-
-	if (!force && hook->hooked)
-		return;
-
-	/* copy back the memory that was previously encountered to preserve
-	 * the current hook and any newer hooks on top */
-	if (hook->started && !force) {
-		uintptr_t addr;
-		size_t size;
-
-		if (hook->type == HOOKTYPE_REVERSE_CHAIN) {
-			addr = hook->func_addr - JMP_32_SIZE;
-			size = JMP_32_SIZE;
-		} else {
-			addr = hook->func_addr;
-			size = patch_size(hook);
-		}
-
-		memcpy((void *)addr, hook->rehook_data, size);
-		hook->hooked = true;
-		return;
-	}
-
-	offset = hook->hook_addr - hook->func_addr - JMP_32_SIZE;
-
-#ifdef _WIN64
-	hook->is_64bit_jump = (llabs(offset) >= 0x7fffffff);
-
-	if (hook->is_64bit_jump) {
-		if (!hook->attempted_bounce) {
-			hook->attempted_bounce = true;
-			setup_64bit_bounce(hook, &offset);
-		}
-
-		if (hook->is_64bit_jump) {
-			rehook64(hook);
-			return;
-		}
-	}
-#endif
-
-	rehook32(hook, force, offset);
-}
-
-void unhook(struct func_hook *hook)
-{
-	uintptr_t addr;
-	size_t size;
-
-	if (!hook->hooked)
-		return;
-
-	if (hook->type == HOOKTYPE_REVERSE_CHAIN) {
-		size = JMP_32_SIZE;
-		addr = (hook->func_addr - JMP_32_SIZE);
-	} else {
-		size = patch_size(hook);
-		addr = hook->func_addr;
-	}
-
-	fix_permissions((void *)addr, size);
-	memcpy(hook->rehook_data, (void *)addr, size);
-
-	if (hook->type == HOOKTYPE_FORWARD_OVERWRITE)
-		memcpy((void *)hook->func_addr, hook->unhook_data, size);
-
-	hook->hooked = false;
-}

+ 0 - 54
plugins/win-capture/funchook.h

@@ -1,54 +0,0 @@
-#pragma once
-
-#include <stdbool.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#else
-#if defined(_MSC_VER) && !defined(inline)
-#define inline __inline
-#endif
-#endif
-
-enum hook_type {
-	HOOKTYPE_FORWARD_OVERWRITE,
-	HOOKTYPE_FORWARD_CHAIN,
-	HOOKTYPE_REVERSE_CHAIN
-};
-
-struct func_hook {
-	void *call_addr;
-
-	uintptr_t func_addr; /* function being hooked to */
-	uintptr_t hook_addr; /* hook function itself */
-	void *bounce_addr;
-	const char *name;
-	enum hook_type type;
-	bool is_64bit_jump;
-	bool hooked;
-	bool started;
-	bool attempted_bounce;
-	uint8_t unhook_data[14];
-	uint8_t rehook_data[14];
-};
-
-extern void hook_init(struct func_hook *hook, void *func_addr, void *hook_addr,
-		      const char *name);
-extern void hook_start(struct func_hook *hook);
-extern void do_hook(struct func_hook *hook, bool force);
-extern void unhook(struct func_hook *hook);
-
-static inline void rehook(struct func_hook *hook)
-{
-	do_hook(hook, false);
-}
-
-static inline void force_rehook(struct func_hook *hook)
-{
-	do_hook(hook, true);
-}
-
-#ifdef __cplusplus
-}
-#endif

+ 1 - 1
plugins/win-capture/graphics-hook-ver.h

@@ -12,7 +12,7 @@
  * THIS IS YOUR ONLY WARNING. */
 
 #define HOOK_VER_MAJOR 1
-#define HOOK_VER_MINOR 6
+#define HOOK_VER_MINOR 7
 #define HOOK_VER_PATCH 0
 
 #define STRINGIFY(s) #s

+ 0 - 2
plugins/win-capture/graphics-hook/CMakeLists.txt

@@ -17,14 +17,12 @@ set(graphics-hook_HEADERS
 	../graphics-hook-ver.h
 	../graphics-hook-info.h
 	../hook-helpers.h
-	../funchook.h
 	../obfuscate.h
 	gl-decs.h
 	d3d9-patches.hpp)
 
 set(graphics-hook_SOURCES
 	graphics-hook.c
-	../funchook.c
 	../obfuscate.c
 	gl-capture.c
 	d3d8-capture.cpp

+ 0 - 1
plugins/win-capture/graphics-hook/d3d10-capture.cpp

@@ -3,7 +3,6 @@
 
 #include "dxgi-helpers.hpp"
 #include "graphics-hook.h"
-#include "../funchook.h"
 
 struct d3d10_data {
 	ID3D10Device *device; /* do not release */

+ 0 - 1
plugins/win-capture/graphics-hook/d3d11-capture.cpp

@@ -3,7 +3,6 @@
 
 #include "dxgi-helpers.hpp"
 #include "graphics-hook.h"
-#include "../funchook.h"
 
 struct d3d11_data {
 	ID3D11Device *device;         /* do not release */

+ 33 - 27
plugins/win-capture/graphics-hook/d3d8-capture.cpp

@@ -2,7 +2,8 @@
 
 #include "../d3d8-api/d3d8.h"
 #include "graphics-hook.h"
-#include "../funchook.h"
+
+#include <detours.h>
 
 typedef HRESULT(STDMETHODCALLTYPE *reset_t)(IDirect3DDevice8 *,
 					    D3DPRESENT_PARAMETERS *);
@@ -10,8 +11,8 @@ typedef HRESULT(STDMETHODCALLTYPE *present_t)(IDirect3DDevice8 *, CONST RECT *,
 					      CONST RECT *, HWND,
 					      CONST RGNDATA *);
 
-static struct func_hook present;
-static struct func_hook reset;
+reset_t RealReset = NULL;
+present_t RealPresent = NULL;
 
 struct d3d8_data {
 	HMODULE d3d8;
@@ -250,17 +251,10 @@ static void d3d8_capture(IDirect3DDevice8 *device,
 static HRESULT STDMETHODCALLTYPE hook_reset(IDirect3DDevice8 *device,
 					    D3DPRESENT_PARAMETERS *parameters)
 {
-	HRESULT hr;
-
 	if (capture_active())
 		d3d8_free();
 
-	unhook(&reset);
-	reset_t call = (reset_t)reset.call_addr;
-	hr = call(device, parameters);
-	rehook(&reset);
-
-	return hr;
+	return RealReset(device, parameters);
 }
 
 static bool hooked_reset = false;
@@ -269,11 +263,19 @@ static void setup_reset_hooks(IDirect3DDevice8 *device)
 {
 	uintptr_t *vtable = *(uintptr_t **)device;
 
-	hook_init(&reset, (void *)vtable[14], (void *)hook_reset,
-		  "IDirect3DDevice8::Reset");
-	rehook(&reset);
+	DetourTransactionBegin();
 
-	hooked_reset = true;
+	RealReset = (reset_t)vtable[14];
+	DetourAttach((PVOID *)&RealReset, hook_reset);
+
+	const LONG error = DetourTransactionCommit();
+	const bool success = error == NO_ERROR;
+	if (success) {
+		hlog("Hooked IDirect3DDevice8::Reset");
+		hooked_reset = true;
+	} else {
+		RealReset = nullptr;
+	}
 }
 
 static HRESULT STDMETHODCALLTYPE hook_present(IDirect3DDevice8 *device,
@@ -283,7 +285,6 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDirect3DDevice8 *device,
 					      CONST RGNDATA *dirty_region)
 {
 	IDirect3DSurface8 *backbuffer;
-	HRESULT hr;
 
 	if (!hooked_reset)
 		setup_reset_hooks(device);
@@ -294,12 +295,8 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDirect3DDevice8 *device,
 		backbuffer->Release();
 	}
 
-	unhook(&present);
-	present_t call = (present_t)present.call_addr;
-	hr = call(device, src_rect, dst_rect, override_window, dirty_region);
-	rehook(&present);
-
-	return hr;
+	return RealPresent(device, src_rect, dst_rect, override_window,
+			   dirty_region);
 }
 
 typedef IDirect3D8 *(WINAPI *d3d8create_t)(UINT);
@@ -388,11 +385,20 @@ bool hook_d3d8(void)
 		return true;
 	}
 
-	hook_init(&present, present_addr, (void *)hook_present,
-		  "IDirect3DDevice8::Present");
+	DetourTransactionBegin();
 
-	rehook(&present);
+	RealPresent = (present_t)present_addr;
+	DetourAttach((PVOID *)&RealPresent, hook_present);
 
-	hlog("Hooked D3D8");
-	return true;
+	const LONG error = DetourTransactionCommit();
+	const bool success = error == NO_ERROR;
+	if (success) {
+		hlog("Hooked IDirect3DDevice8::Present");
+		hlog("Hooked D3D8");
+	} else {
+		RealPresent = nullptr;
+		hlog("Failed to attach Detours hook: %ld", error);
+	}
+
+	return success;
 }

+ 67 - 66
plugins/win-capture/graphics-hook/d3d9-capture.cpp

@@ -3,13 +3,14 @@
 #include <dxgi.h>
 
 #include "graphics-hook.h"
-#include "../funchook.h"
 #include "d3d9-patches.hpp"
 
+#include <detours.h>
+
 typedef HRESULT(STDMETHODCALLTYPE *present_t)(IDirect3DDevice9 *, CONST RECT *,
 					      CONST RECT *, HWND,
 					      CONST RGNDATA *);
-typedef HRESULT(STDMETHODCALLTYPE *present_ex_t)(IDirect3DDevice9 *,
+typedef HRESULT(STDMETHODCALLTYPE *present_ex_t)(IDirect3DDevice9Ex *,
 						 CONST RECT *, CONST RECT *,
 						 HWND, CONST RGNDATA *, DWORD);
 typedef HRESULT(STDMETHODCALLTYPE *present_swap_t)(IDirect3DSwapChain9 *,
@@ -24,11 +25,11 @@ typedef HRESULT(STDMETHODCALLTYPE *reset_ex_t)(IDirect3DDevice9 *,
 
 typedef HRESULT(WINAPI *createfactory1_t)(REFIID, void **);
 
-static struct func_hook present;
-static struct func_hook present_ex;
-static struct func_hook present_swap;
-static struct func_hook reset;
-static struct func_hook reset_ex;
+present_t RealPresent = NULL;
+present_ex_t RealPresentEx = NULL;
+present_swap_t RealPresentSwap = NULL;
+reset_t RealReset = NULL;
+reset_ex_t RealResetEx = NULL;
 
 struct d3d9_data {
 	HMODULE d3d9;
@@ -641,17 +642,14 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDirect3DDevice9 *device,
 					      CONST RGNDATA *dirty_region)
 {
 	IDirect3DSurface9 *backbuffer = nullptr;
-	HRESULT hr;
 
 	if (!hooked_reset)
 		setup_reset_hooks(device);
 
 	present_begin(device, backbuffer);
 
-	unhook(&present);
-	present_t call = (present_t)present.call_addr;
-	hr = call(device, src_rect, dst_rect, override_window, dirty_region);
-	rehook(&present);
+	const HRESULT hr = RealPresent(device, src_rect, dst_rect,
+				       override_window, dirty_region);
 
 	present_end(device, backbuffer);
 
@@ -659,22 +657,18 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDirect3DDevice9 *device,
 }
 
 static HRESULT STDMETHODCALLTYPE hook_present_ex(
-	IDirect3DDevice9 *device, CONST RECT *src_rect, CONST RECT *dst_rect,
+	IDirect3DDevice9Ex *device, CONST RECT *src_rect, CONST RECT *dst_rect,
 	HWND override_window, CONST RGNDATA *dirty_region, DWORD flags)
 {
 	IDirect3DSurface9 *backbuffer = nullptr;
-	HRESULT hr;
 
 	if (!hooked_reset)
 		setup_reset_hooks(device);
 
 	present_begin(device, backbuffer);
 
-	unhook(&present_ex);
-	present_ex_t call = (present_ex_t)present_ex.call_addr;
-	hr = call(device, src_rect, dst_rect, override_window, dirty_region,
-		  flags);
-	rehook(&present_ex);
+	const HRESULT hr = RealPresentEx(device, src_rect, dst_rect,
+					 override_window, dirty_region, flags);
 
 	present_end(device, backbuffer);
 
@@ -687,12 +681,11 @@ static HRESULT STDMETHODCALLTYPE hook_present_swap(
 {
 	IDirect3DSurface9 *backbuffer = nullptr;
 	IDirect3DDevice9 *device = nullptr;
-	HRESULT hr;
 
 	if (!present_recurse) {
-		hr = swap->GetDevice(&device);
-		if (SUCCEEDED(hr)) {
-			device->Release();
+		IDirect3DDevice9 *temp;
+		if (SUCCEEDED(swap->GetDevice(&temp))) {
+			device = temp;
 		}
 	}
 
@@ -703,14 +696,13 @@ static HRESULT STDMETHODCALLTYPE hook_present_swap(
 		present_begin(device, backbuffer);
 	}
 
-	unhook(&present_swap);
-	present_swap_t call = (present_swap_t)present_swap.call_addr;
-	hr = call(swap, src_rect, dst_rect, override_window, dirty_region,
-		  flags);
-	rehook(&present_swap);
+	const HRESULT hr = RealPresentSwap(
+		swap, src_rect, dst_rect, override_window, dirty_region, flags);
 
-	if (device)
+	if (device) {
 		present_end(device, backbuffer);
+		device->Release();
+	}
 
 	return hr;
 }
@@ -718,34 +710,20 @@ static HRESULT STDMETHODCALLTYPE hook_present_swap(
 static HRESULT STDMETHODCALLTYPE hook_reset(IDirect3DDevice9 *device,
 					    D3DPRESENT_PARAMETERS *params)
 {
-	HRESULT hr;
-
 	if (capture_active())
 		d3d9_free();
 
-	unhook(&reset);
-	reset_t call = (reset_t)reset.call_addr;
-	hr = call(device, params);
-	rehook(&reset);
-
-	return hr;
+	return RealReset(device, params);
 }
 
 static HRESULT STDMETHODCALLTYPE hook_reset_ex(IDirect3DDevice9 *device,
 					       D3DPRESENT_PARAMETERS *params,
 					       D3DDISPLAYMODEEX *dmex)
 {
-	HRESULT hr;
-
 	if (capture_active())
 		d3d9_free();
 
-	unhook(&reset_ex);
-	reset_ex_t call = (reset_ex_t)reset_ex.call_addr;
-	hr = call(device, params, dmex);
-	rehook(&reset_ex);
-
-	return hr;
+	return RealResetEx(device, params, dmex);
 }
 
 static void setup_reset_hooks(IDirect3DDevice9 *device)
@@ -754,21 +732,30 @@ static void setup_reset_hooks(IDirect3DDevice9 *device)
 	uintptr_t *vtable = *(uintptr_t **)device;
 	HRESULT hr;
 
-	hook_init(&reset, (void *)vtable[16], (void *)hook_reset,
-		  "IDirect3DDevice9::Reset");
-	rehook(&reset);
+	DetourTransactionBegin();
 
-	hr = device->QueryInterface(__uuidof(IDirect3DDevice9Ex),
-				    (void **)&d3d9ex);
+	RealReset = (reset_t)vtable[16];
+	DetourAttach((PVOID *)&RealReset, hook_reset);
+
+	hr = device->QueryInterface(IID_PPV_ARGS(&d3d9ex));
 	if (SUCCEEDED(hr)) {
-		hook_init(&reset_ex, (void *)vtable[132], (void *)hook_reset_ex,
-			  "IDirect3DDevice9Ex::ResetEx");
-		rehook(&reset_ex);
+		RealResetEx = (reset_ex_t)vtable[132];
+		DetourAttach((PVOID *)&RealResetEx, hook_reset_ex);
 
 		d3d9ex->Release();
 	}
 
-	hooked_reset = true;
+	const LONG error = DetourTransactionCommit();
+	const bool success = error == NO_ERROR;
+	if (success) {
+		hlog("Hooked IDirect3DDevice9::Reset");
+		if (RealResetEx)
+			hlog("Hooked IDirect3DDevice9Ex::ResetEx");
+		hooked_reset = true;
+	} else {
+		RealReset = nullptr;
+		RealResetEx = nullptr;
+	}
 }
 
 typedef HRESULT(WINAPI *d3d9create_ex_t)(UINT, IDirect3D9Ex **);
@@ -878,23 +865,37 @@ bool hook_d3d9(void)
 		return true;
 	}
 
+	DetourTransactionBegin();
+
 	if (present_swap_addr) {
-		hook_init(&present_swap, present_swap_addr,
-			  (void *)hook_present_swap,
-			  "IDirect3DSwapChain9::Present");
-		rehook(&present_swap);
+		RealPresentSwap = (present_swap_t)present_swap_addr;
+		DetourAttach((PVOID *)&RealPresentSwap, hook_present_swap);
 	}
 	if (present_ex_addr) {
-		hook_init(&present_ex, present_ex_addr, (void *)hook_present_ex,
-			  "IDirect3DDevice9Ex::PresentEx");
-		rehook(&present_ex);
+		RealPresentEx = (present_ex_t)present_ex_addr;
+		DetourAttach((PVOID *)&RealPresentEx, hook_present_ex);
 	}
 	if (present_addr) {
-		hook_init(&present, present_addr, (void *)hook_present,
-			  "IDirect3DDevice9::Present");
-		rehook(&present);
+		RealPresent = (present_t)present_addr;
+		DetourAttach((PVOID *)&RealPresent, hook_present);
+	}
+
+	const LONG error = DetourTransactionCommit();
+	const bool success = error == NO_ERROR;
+	if (success) {
+		if (RealPresentSwap)
+			hlog("Hooked IDirect3DSwapChain9::Present");
+		if (RealPresentEx)
+			hlog("Hooked IDirect3DDevice9Ex::PresentEx");
+		if (RealPresent)
+			hlog("Hooked IDirect3DDevice9::Present");
+		hlog("Hooked D3D9");
+	} else {
+		RealPresentSwap = nullptr;
+		RealPresentEx = nullptr;
+		RealPresent = nullptr;
+		hlog("Failed to attach Detours hook: %ld", error);
 	}
 
-	hlog("Hooked D3D9");
-	return true;
+	return success;
 }

+ 42 - 42
plugins/win-capture/graphics-hook/dxgi-capture.cpp

@@ -5,7 +5,8 @@
 #include <inttypes.h>
 
 #include "graphics-hook.h"
-#include "../funchook.h"
+
+#include <detours.h>
 
 #if COMPILE_D3D12_HOOK
 #include <d3d12.h>
@@ -19,10 +20,10 @@ typedef HRESULT(STDMETHODCALLTYPE *present_t)(IDXGISwapChain *, UINT, UINT);
 typedef HRESULT(STDMETHODCALLTYPE *present1_t)(IDXGISwapChain1 *, UINT, UINT,
 					       const DXGI_PRESENT_PARAMETERS *);
 
-static struct func_hook release;
-static struct func_hook resize_buffers;
-static struct func_hook present;
-static struct func_hook present1;
+release_t RealRelease = nullptr;
+resize_buffers_t RealResizeBuffers = nullptr;
+present_t RealPresent = nullptr;
+present1_t RealPresent1 = nullptr;
 
 thread_local bool dxgi_presenting = false;
 struct ID3D12CommandQueue *dxgi_possible_swap_queues[8]{};
@@ -112,10 +113,7 @@ static bool setup_dxgi(IDXGISwapChain *swap)
 
 static ULONG STDMETHODCALLTYPE hook_release(IUnknown *unknown)
 {
-	unhook(&release);
-	release_t call = (release_t)release.call_addr;
-	ULONG refs = call(unknown);
-	rehook(&release);
+	const ULONG refs = RealRelease(unknown);
 
 	hlog_verbose("Release callback: Refs=%lu", refs);
 	if (unknown == data.swap && refs == 0) {
@@ -155,11 +153,8 @@ static HRESULT STDMETHODCALLTYPE hook_resize_buffers(IDXGISwapChain *swap,
 		data.free();
 	data.free = nullptr;
 
-	unhook(&resize_buffers);
-	resize_buffers_t call = (resize_buffers_t)resize_buffers.call_addr;
-	const HRESULT hr =
-		call(swap, buffer_count, width, height, format, flags);
-	rehook(&resize_buffers);
+	const HRESULT hr = RealResizeBuffers(swap, buffer_count, width, height,
+					     format, flags);
 
 	resize_buffers_called = true;
 
@@ -229,10 +224,7 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDXGISwapChain *swap,
 	}
 
 	dxgi_presenting = true;
-	unhook(&present);
-	present_t call = (present_t)present.call_addr;
-	const HRESULT hr = call(swap, sync_interval, flags);
-	rehook(&present);
+	const HRESULT hr = RealPresent(swap, sync_interval, flags);
 	dxgi_presenting = false;
 	dxgi_present_attempted = true;
 
@@ -291,10 +283,7 @@ hook_present1(IDXGISwapChain1 *swap, UINT sync_interval, UINT flags,
 	}
 
 	dxgi_presenting = true;
-	unhook(&present1);
-	present1_t call = (present1_t)present1.call_addr;
-	const HRESULT hr = call(swap, sync_interval, flags, params);
-	rehook(&present1);
+	const HRESULT hr = RealPresent1(swap, sync_interval, flags, params);
 	dxgi_presenting = false;
 	dxgi_present_attempted = true;
 
@@ -337,30 +326,41 @@ bool hook_dxgi(void)
 		release_addr = get_offset_addr(
 			dxgi_module, global_hook_info->offsets.dxgi2.release);
 
-	hook_init(&present, present_addr, (void *)hook_present,
-		  "IDXGISwapChain::Present");
-	hlog("Hooked IDXGISwapChain::Present");
-	hook_init(&resize_buffers, resize_addr, (void *)hook_resize_buffers,
-		  "IDXGISwapChain::ResizeBuffers");
-	hlog("Hooked IDXGISwapChain::ResizeBuffers");
+	DetourTransactionBegin();
+
+	RealPresent = (present_t)present_addr;
+	DetourAttach(&(PVOID &)RealPresent, hook_present);
+
+	RealResizeBuffers = (resize_buffers_t)resize_addr;
+	DetourAttach(&(PVOID &)RealResizeBuffers, hook_resize_buffers);
+
 	if (present1_addr) {
-		hook_init(&present1, present1_addr, (void *)hook_present1,
-			  "IDXGISwapChain1::Present1");
-		hlog("Hooked IDXGISwapChain::Present1");
+		RealPresent1 = (present1_t)present1_addr;
+		DetourAttach(&(PVOID &)RealPresent1, hook_present1);
 	}
+
 	if (release_addr) {
-		hook_init(&release, release_addr, (void *)hook_release,
-			  "IDXGISwapChain::Release");
-		hlog("Hooked IDXGISwapChain::Release");
+		RealRelease = (release_t)release_addr;
+		DetourAttach(&(PVOID &)RealRelease, hook_release);
 	}
 
-	rehook(&resize_buffers);
-	rehook(&present);
-	if (present1_addr)
-		rehook(&present1);
-	if (release_addr)
-		rehook(&release);
+	const LONG error = DetourTransactionCommit();
+	const bool success = error == NO_ERROR;
+	if (success) {
+		hlog("Hooked IDXGISwapChain::Present");
+		hlog("Hooked IDXGISwapChain::ResizeBuffers");
+		if (RealPresent1)
+			hlog("Hooked IDXGISwapChain1::Present1");
+		if (RealRelease)
+			hlog("Hooked IDXGISwapChain::Release");
+		hlog("Hooked DXGI");
+	} else {
+		RealPresent = nullptr;
+		RealResizeBuffers = nullptr;
+		RealPresent1 = nullptr;
+		RealRelease = nullptr;
+		hlog("Failed to attach Detours hook: %ld", error);
+	}
 
-	hlog("Hooked DXGI");
-	return true;
+	return success;
 }

+ 48 - 44
plugins/win-capture/graphics-hook/gl-capture.c

@@ -11,7 +11,8 @@
 
 #include "gl-decs.h"
 #include "graphics-hook.h"
-#include "../funchook.h"
+
+#include <detours.h>
 
 #define DUMMY_WINDOW_CLASS_NAME L"graphics_hook_gl_dummy_window"
 
@@ -24,10 +25,15 @@ static const GUID GUID_IDXGIResource =
 
 /* clang-format on */
 
-static struct func_hook swap_buffers;
-static struct func_hook wgl_swap_layer_buffers;
-static struct func_hook wgl_swap_buffers;
-static struct func_hook wgl_delete_context;
+typedef BOOL(WINAPI *PFN_SwapBuffers)(HDC);
+typedef BOOL(WINAPI *PFN_WglSwapLayerBuffers)(HDC, UINT);
+typedef BOOL(WINAPI *PFN_WglSwapBuffers)(HDC);
+typedef BOOL(WINAPI *PFN_WglDeleteContext)(HGLRC);
+
+PFN_SwapBuffers RealSwapBuffers = NULL;
+PFN_WglSwapLayerBuffers RealWglSwapLayerBuffers = NULL;
+PFN_WglSwapBuffers RealWglSwapBuffers = NULL;
+PFN_WglDeleteContext RealWglDeleteContext = NULL;
 
 static bool darkest_dungeon_fix = false;
 static bool functions_initialized = false;
@@ -780,14 +786,9 @@ static inline void gl_swap_end(HDC hdc)
 
 static BOOL WINAPI hook_swap_buffers(HDC hdc)
 {
-	BOOL ret;
-
 	gl_swap_begin(hdc);
 
-	unhook(&swap_buffers);
-	BOOL(WINAPI * call)(HDC) = swap_buffers.call_addr;
-	ret = call(hdc);
-	rehook(&swap_buffers);
+	const BOOL ret = RealSwapBuffers(hdc);
 
 	gl_swap_end(hdc);
 
@@ -796,14 +797,9 @@ static BOOL WINAPI hook_swap_buffers(HDC hdc)
 
 static BOOL WINAPI hook_wgl_swap_buffers(HDC hdc)
 {
-	BOOL ret;
-
 	gl_swap_begin(hdc);
 
-	unhook(&wgl_swap_buffers);
-	BOOL(WINAPI * call)(HDC) = wgl_swap_buffers.call_addr;
-	ret = call(hdc);
-	rehook(&wgl_swap_buffers);
+	const BOOL ret = RealWglSwapBuffers(hdc);
 
 	gl_swap_end(hdc);
 
@@ -812,14 +808,9 @@ static BOOL WINAPI hook_wgl_swap_buffers(HDC hdc)
 
 static BOOL WINAPI hook_wgl_swap_layer_buffers(HDC hdc, UINT planes)
 {
-	BOOL ret;
-
 	gl_swap_begin(hdc);
 
-	unhook(&wgl_swap_layer_buffers);
-	BOOL(WINAPI * call)(HDC, UINT) = wgl_swap_layer_buffers.call_addr;
-	ret = call(hdc, planes);
-	rehook(&wgl_swap_layer_buffers);
+	const BOOL ret = RealWglSwapLayerBuffers(hdc, planes);
 
 	gl_swap_end(hdc);
 
@@ -828,8 +819,6 @@ static BOOL WINAPI hook_wgl_swap_layer_buffers(HDC hdc, UINT planes)
 
 static BOOL WINAPI hook_wgl_delete_context(HGLRC hrc)
 {
-	BOOL ret;
-
 	if (capture_active() && functions_initialized) {
 		HDC last_hdc = jimglGetCurrentDC();
 		HGLRC last_hrc = jimglGetCurrentContext();
@@ -839,12 +828,7 @@ static BOOL WINAPI hook_wgl_delete_context(HGLRC hrc)
 		jimglMakeCurrent(last_hdc, last_hrc);
 	}
 
-	unhook(&wgl_delete_context);
-	BOOL(WINAPI * call)(HGLRC) = wgl_delete_context.call_addr;
-	ret = call(hrc);
-	rehook(&wgl_delete_context);
-
-	return ret;
+	return RealWglDeleteContext(hrc);
 }
 
 static bool gl_register_window(void)
@@ -892,24 +876,44 @@ bool hook_gl(void)
 	wgl_slb_proc = base_get_proc("wglSwapLayerBuffers");
 	wgl_sb_proc = base_get_proc("wglSwapBuffers");
 
-	hook_init(&swap_buffers, SwapBuffers, hook_swap_buffers, "SwapBuffers");
+	DetourTransactionBegin();
+
+	RealSwapBuffers = SwapBuffers;
+	DetourAttach((PVOID *)&RealSwapBuffers, hook_swap_buffers);
 	if (wgl_dc_proc) {
-		hook_init(&wgl_delete_context, wgl_dc_proc,
-			  hook_wgl_delete_context, "wglDeleteContext");
-		rehook(&wgl_delete_context);
+		RealWglDeleteContext = (PFN_WglDeleteContext)wgl_dc_proc;
+		DetourAttach((PVOID *)&RealWglDeleteContext,
+			     hook_wgl_delete_context);
 	}
 	if (wgl_slb_proc) {
-		hook_init(&wgl_swap_layer_buffers, wgl_slb_proc,
-			  hook_wgl_swap_layer_buffers, "wglSwapLayerBuffers");
-		rehook(&wgl_swap_layer_buffers);
+		RealWglSwapLayerBuffers = (PFN_WglSwapLayerBuffers)wgl_slb_proc;
+		DetourAttach((PVOID *)&RealWglSwapLayerBuffers,
+			     hook_wgl_swap_layer_buffers);
 	}
 	if (wgl_sb_proc) {
-		hook_init(&wgl_swap_buffers, wgl_sb_proc, hook_wgl_swap_buffers,
-			  "wglSwapBuffers");
-		rehook(&wgl_swap_buffers);
+		RealWglSwapBuffers = (PFN_WglSwapBuffers)wgl_sb_proc;
+		DetourAttach((PVOID *)&RealWglSwapBuffers,
+			     hook_wgl_swap_buffers);
+	}
+
+	const LONG error = DetourTransactionCommit();
+	const bool success = error == NO_ERROR;
+	if (success) {
+		hlog("Hooked SwapBuffers");
+		if (RealWglDeleteContext)
+			hlog("Hooked wglDeleteContext");
+		if (RealWglSwapLayerBuffers)
+			hlog("Hooked wglSwapLayerBuffers");
+		if (RealWglSwapBuffers)
+			hlog("Hooked wglSwapBuffers");
+		hlog("Hooked GL");
+	} else {
+		RealSwapBuffers = NULL;
+		RealWglDeleteContext = NULL;
+		RealWglSwapLayerBuffers = NULL;
+		RealWglSwapBuffers = NULL;
+		hlog("Failed to attach Detours hook: %ld", error);
 	}
 
-	rehook(&swap_buffers);
-
-	return true;
+	return success;
 }

+ 0 - 1
plugins/win-capture/graphics-hook/graphics-hook.c

@@ -4,7 +4,6 @@
 #include "graphics-hook.h"
 #include "../graphics-hook-ver.h"
 #include "../obfuscate.h"
-#include "../funchook.h"
 
 #define DEBUG_OUTPUT