Merge pull request #4720 from jpark37/detours-integration
Finish Detours integration for remaining game capture APIs
This commit is contained in:
commit
84bf08c171
@ -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;
|
||||
}
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include "dxgi-helpers.hpp"
|
||||
#include "graphics-hook.h"
|
||||
#include "../funchook.h"
|
||||
|
||||
struct d3d10_data {
|
||||
ID3D10Device *device; /* do not release */
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include "dxgi-helpers.hpp"
|
||||
#include "graphics-hook.h"
|
||||
#include "../funchook.h"
|
||||
|
||||
struct d3d11_data {
|
||||
ID3D11Device *device; /* do not release */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "graphics-hook.h"
|
||||
#include "../graphics-hook-ver.h"
|
||||
#include "../obfuscate.h"
|
||||
#include "../funchook.h"
|
||||
|
||||
#define DEBUG_OUTPUT
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user