Merge pull request #4720 from jpark37/detours-integration

Finish Detours integration for remaining game capture APIs
This commit is contained in:
Jim 2021-08-23 23:18:10 -07:00 committed by GitHub
commit 84bf08c171
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 190 additions and 523 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

@ -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;
}

View File

@ -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);
}
hlog("Hooked D3D9");
return true;
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);
}
return success;
}

View File

@ -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;
}

View File

@ -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);
}
rehook(&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);
}
return true;
return success;
}

View File

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