Refactor hooks towards more unified/clean approach

* Hooking is now done the same way across platform, with different OS
  implementations.
* Regardless of how exactly hooks are implemented, we register libraries to hook
  and functions to hook within those libraries, and provide a location to store
  the original/onwards function pointer. This allows hooking to work whether
  it's done using import hooking that doesn't modify target libraries (so using
  dlsym or GetProcAddress will return the same value for the onwards function
  pointer) or whether it's implemented with prologue patching and trampolines,
  where we'd create an infinite loop if we did that.
* We also provide stronger guarantees - the original function pointers will
  _always_ be made available as soon as the library is loaded, whether hooked or
  not, no exceptions. This means less uncertainty in hooking code about when or
  how onward functions will be available.
* OS-specific hook functions are changed to just be implementations of
  LibraryHooks functions rather than indirected through macros and pre-processor
  definitions.
* In this commit we provide some temporary functions providing the old interface
  to reduce churn - the library-specific hook code will be updated shortly after
This commit is contained in:
baldurk
2018-06-26 13:54:02 +01:00
parent edd6ab4faa
commit c70c116bd7
28 changed files with 1146 additions and 922 deletions
-3
View File
@@ -214,7 +214,6 @@ if(ANDROID)
os/posix/android/android_threading.cpp
os/posix/android/android_hook.cpp
os/posix/android/android_network.cpp
os/posix/posix_hook.h
os/posix/posix_network.h
os/posix/posix_network.cpp
os/posix/posix_process.cpp
@@ -230,7 +229,6 @@ elseif(APPLE)
os/posix/apple/apple_threading.cpp
os/posix/apple/apple_hook.cpp
os/posix/apple/apple_network.cpp
os/posix/posix_hook.h
os/posix/posix_network.h
os/posix/posix_network.cpp
os/posix/posix_process.cpp
@@ -248,7 +246,6 @@ elseif(UNIX)
os/posix/linux/linux_network.cpp
3rdparty/plthook/plthook.h
3rdparty/plthook/plthook_elf.c
os/posix/posix_hook.h
os/posix/posix_network.h
os/posix/posix_network.cpp
os/posix/posix_process.cpp
+1 -1
View File
@@ -1043,7 +1043,7 @@ void RenderDoc::SetCaptureOptions(const CaptureOptions &opts)
{
m_Options = opts;
LibraryHooks::GetInstance().OptionsUpdated();
LibraryHooks::OptionsUpdated();
}
void RenderDoc::SetCaptureFileTemplate(const char *pathtemplate)
+36 -34
View File
@@ -28,6 +28,16 @@
#include "driver/ihv/amd/official/DXExt/AmdDxExtApi.h"
#include "hooks/hooks.h"
#if ENABLED(RDOC_X64)
#define BIT_SPECIFIC_DLL(dll32, dll64) dll64
#else
#define BIT_SPECIFIC_DLL(dll32, dll64) dll32
#endif
ID3D11Resource *UnwrapDXResource(void *dxObject);
ID3DDevice *GetD3D11DeviceIfAlloc(IUnknown *dev)
@@ -110,7 +120,7 @@ class D3D11Hook : LibraryHook
{
public:
D3D11Hook() { m_InsideCreate = false; }
bool CreateHooks(const char *libName)
void RegisterHooks()
{
WrappedIDXGISwapChain4::RegisterD3DDeviceCallback(GetD3D11DeviceIfAlloc);
@@ -118,52 +128,44 @@ public:
if(GetD3DCompiler() == NULL)
{
RDCERR("Failed to load d3dcompiler_??.dll - not inserting D3D11 hooks.");
return false;
return;
}
CreateDevice.Initialize("D3D11CreateDevice", "d3d11.dll", D3D11CreateDevice_hook);
CreateDeviceAndSwapChain.Initialize("D3D11CreateDeviceAndSwapChain", "d3d11.dll",
D3D11CreateDeviceAndSwapChain_hook);
LibraryHooks::RegisterLibraryHook("d3d11.dll", NULL);
// these are hooked to prevent AMD extensions from activating and causing later crashes when not
// replayed correctly
#if ENABLED(RDOC_X64)
AmdCreate11.Initialize("AmdDxExtCreate11", "atidxx64.dll", AmdCreate11_hook);
#else
AmdCreate11.Initialize("AmdDxExtCreate11", "atidxx32.dll", AmdCreate11_hook);
#endif
CreateDevice.Register("d3d11.dll", "D3D11CreateDevice", D3D11CreateDevice_hook);
CreateDeviceAndSwapChain.Register("d3d11.dll", "D3D11CreateDeviceAndSwapChain",
D3D11CreateDeviceAndSwapChain_hook);
// nvapi has some seriously awful ""feature"" where it can wrap CreateDevice with some other
// extra parameter. Since we don't want to hook nvapi when it calls out to d3d11.dll, we have to
// intercept it here.
#if ENABLED(RDOC_X64)
nvapi_QueryInterface.Initialize("nvapi_QueryInterface", "nvapi64.dll", nvapi_QueryInterface_hook);
#else
nvapi_QueryInterface.Initialize("nvapi_QueryInterface", "nvapi.dll", nvapi_QueryInterface_hook);
#endif
// these are hooked to prevent AMD extensions from activating and causing later crashes when not
// replayed correctly
LibraryHooks::RegisterLibraryHook(BIT_SPECIFIC_DLL("atidxx32.dll", "atidxx64.dll"), NULL);
AmdCreate11.Register(BIT_SPECIFIC_DLL("atidxx32.dll", "atidxx64.dll"), "AmdDxExtCreate11",
AmdCreate11_hook);
// we need to wrap nvcodec to handle unwrapping D3D11 pointers passed to it
#if ENABLED(RDOC_X64)
NvEncodeCreate.Initialize("NvEncodeAPICreateInstance", "nvEncodeAPI64.dll",
NvEncodeAPICreateInstance_hook);
#else
NvEncodeCreate.Initialize("NvEncodeAPICreateInstance", "nvEncodeAPI.dll",
NvEncodeAPICreateInstance_hook);
#endif
// nvapi has some seriously awful ""feature"" where it can wrap CreateDevice with some other
// extra parameter. Since we don't want to hook nvapi when it calls out to d3d11.dll, we have to
// intercept it here.
LibraryHooks::RegisterLibraryHook(BIT_SPECIFIC_DLL("nvapi.dll", "nvapi64.dll"), NULL);
nvapi_QueryInterface.Register(BIT_SPECIFIC_DLL("nvapi.dll", "nvapi64.dll"),
"nvapi_QueryInterface", nvapi_QueryInterface_hook);
return true;
// we need to wrap nvcodec to handle unwrapping D3D11 pointers passed to it
LibraryHooks::RegisterLibraryHook(BIT_SPECIFIC_DLL("nvEncodeAPI.dll", "nvEncodeAPI64.dll"), NULL);
NvEncodeCreate.Register(BIT_SPECIFIC_DLL("nvEncodeAPI.dll", "nvEncodeAPI64.dll"),
"NvEncodeAPICreateInstance", NvEncodeAPICreateInstance_hook);
}
private:
static D3D11Hook d3d11hooks;
Hook<PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN> CreateDeviceAndSwapChain;
Hook<PFN_D3D11_CREATE_DEVICE> CreateDevice;
HookedFunction<PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN> CreateDeviceAndSwapChain;
HookedFunction<PFN_D3D11_CREATE_DEVICE> CreateDevice;
// optional extension hooks
Hook<PFNAmdDxExtCreate11> AmdCreate11;
Hook<PFNNVQueryInterface> nvapi_QueryInterface;
Hook<PFN_NvEncodeAPICreateInstance> NvEncodeCreate;
HookedFunction<PFNAmdDxExtCreate11> AmdCreate11;
HookedFunction<PFNNVQueryInterface> nvapi_QueryInterface;
HookedFunction<PFN_NvEncodeAPICreateInstance> NvEncodeCreate;
// re-entrancy detection (can happen in rare cases with e.g. fraps)
bool m_InsideCreate;
+10 -10
View File
@@ -86,7 +86,7 @@ public:
class D3D12Hook : LibraryHook
{
public:
bool CreateHooks(const char *libName)
void RegisterHooks()
{
WrappedIDXGISwapChain4::RegisterD3DDeviceCallback(GetD3D12DeviceIfAlloc);
@@ -94,23 +94,23 @@ public:
if(GetD3DCompiler() == NULL)
{
RDCERR("Failed to load d3dcompiler_??.dll - not inserting D3D12 hooks.");
return false;
return;
}
CreateDevice.Initialize("D3D12CreateDevice", "d3d12.dll", D3D12CreateDevice_hook);
GetDebugInterface.Initialize("D3D12GetDebugInterface", "d3d12.dll", D3D12GetDebugInterface_hook);
EnableExperimentalFeatures.Initialize("D3D12EnableExperimentalFeatures", "d3d12.dll",
D3D12EnableExperimentalFeatures_hook);
LibraryHooks::RegisterLibraryHook("d3d12.dll", NULL);
return true;
CreateDevice.Register("d3d12.dll", "D3D12CreateDevice", D3D12CreateDevice_hook);
GetDebugInterface.Register("d3d12.dll", "D3D12GetDebugInterface", D3D12GetDebugInterface_hook);
EnableExperimentalFeatures.Register("d3d12.dll", "D3D12EnableExperimentalFeatures",
D3D12EnableExperimentalFeatures_hook);
}
private:
static D3D12Hook d3d12hooks;
Hook<PFN_D3D12_GET_DEBUG_INTERFACE> GetDebugInterface;
Hook<PFN_D3D12_CREATE_DEVICE> CreateDevice;
Hook<PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES> EnableExperimentalFeatures;
HookedFunction<PFN_D3D12_GET_DEBUG_INTERFACE> GetDebugInterface;
HookedFunction<PFN_D3D12_CREATE_DEVICE> CreateDevice;
HookedFunction<PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES> EnableExperimentalFeatures;
// re-entrancy detection (can happen in rare cases with e.g. fraps)
bool m_InsideCreate = false;
+4 -5
View File
@@ -31,17 +31,16 @@ typedef IDirect3D8 *(WINAPI *PFN_D3D8_CREATE)(UINT);
class D3D8Hook : LibraryHook
{
public:
bool CreateHooks(const char *libName)
void RegisterHooks()
{
Create8.Initialize("Direct3DCreate8", "d3d8.dll", Create8_hook);
return true;
LibraryHooks::RegisterLibraryHook("d3d8.dll", NULL);
Create8.Register("d3d8.dll", "Direct3DCreate8", Create8_hook);
}
private:
static D3D8Hook d3d8hooks;
Hook<PFN_D3D8_CREATE> Create8;
HookedFunction<PFN_D3D8_CREATE> Create8;
static IDirect3D8 *WINAPI Create8_hook(UINT SDKVersion)
{
+14 -14
View File
@@ -40,29 +40,29 @@ typedef IDirect3D9 *(WINAPI *PFN_D3D9_CREATE)(UINT);
class D3D9Hook : LibraryHook
{
public:
bool CreateHooks(const char *libName)
void RegisterHooks()
{
PERF_BeginEvent.Initialize("D3DPERF_BeginEvent", "d3d9.dll", PERF_BeginEvent_hook);
PERF_EndEvent.Initialize("D3DPERF_EndEvent", "d3d9.dll", PERF_EndEvent_hook);
PERF_SetMarker.Initialize("D3DPERF_SetMarker", "d3d9.dll", PERF_SetMarker_hook);
PERF_SetOptions.Initialize("D3DPERF_SetOptions", "d3d9.dll", PERF_SetOptions_hook);
PERF_GetStatus.Initialize("D3DPERF_GetStatus", "d3d9.dll", PERF_GetStatus_hook);
LibraryHooks::RegisterLibraryHook("d3d9.dll", NULL);
Create9.Initialize("Direct3DCreate9", "d3d9.dll", Create9_hook);
PERF_BeginEvent.Register("d3d9.dll", "D3DPERF_BeginEvent", PERF_BeginEvent_hook);
PERF_EndEvent.Register("d3d9.dll", "D3DPERF_EndEvent", PERF_EndEvent_hook);
PERF_SetMarker.Register("d3d9.dll", "D3DPERF_SetMarker", PERF_SetMarker_hook);
PERF_SetOptions.Register("d3d9.dll", "D3DPERF_SetOptions", PERF_SetOptions_hook);
PERF_GetStatus.Register("d3d9.dll", "D3DPERF_GetStatus", PERF_GetStatus_hook);
return true;
Create9.Register("d3d9.dll", "Direct3DCreate9", Create9_hook);
}
private:
static D3D9Hook d3d9hooks;
// D3DPERF api
Hook<PFN_BEGIN_EVENT> PERF_BeginEvent;
Hook<PFN_END_EVENT> PERF_EndEvent;
Hook<PFN_SET_MARKER_EVENT> PERF_SetMarker;
Hook<PFN_SET_OPTIONS> PERF_SetOptions;
Hook<PFN_GET_OPTIONS> PERF_GetStatus;
Hook<PFN_D3D9_CREATE> Create9;
HookedFunction<PFN_BEGIN_EVENT> PERF_BeginEvent;
HookedFunction<PFN_END_EVENT> PERF_EndEvent;
HookedFunction<PFN_SET_MARKER_EVENT> PERF_SetMarker;
HookedFunction<PFN_SET_OPTIONS> PERF_SetOptions;
HookedFunction<PFN_GET_OPTIONS> PERF_GetStatus;
HookedFunction<PFN_D3D9_CREATE> Create9;
static int WINAPI PERF_BeginEvent_hook(DWORD col, WCHAR *wszName)
{
+12 -12
View File
@@ -72,15 +72,15 @@ struct RenderDocAnalysis : IDXGraphicsAnalysis
class DXGIHook : LibraryHook
{
public:
bool CreateHooks(const char *libName)
void RegisterHooks()
{
CreateDXGIFactory.Initialize("CreateDXGIFactory", "dxgi.dll", CreateDXGIFactory_hook);
CreateDXGIFactory1.Initialize("CreateDXGIFactory1", "dxgi.dll", CreateDXGIFactory1_hook);
CreateDXGIFactory2.Initialize("CreateDXGIFactory2", "dxgi.dll", CreateDXGIFactory2_hook);
GetDebugInterface.Initialize("DXGIGetDebugInterface", "dxgi.dll", DXGIGetDebugInterface_hook);
GetDebugInterface1.Initialize("DXGIGetDebugInterface1", "dxgi.dll", DXGIGetDebugInterface1_hook);
LibraryHooks::RegisterLibraryHook("dxgi.dll", NULL);
return true;
CreateDXGIFactory.Register("dxgi.dll", "CreateDXGIFactory", CreateDXGIFactory_hook);
CreateDXGIFactory1.Register("dxgi.dll", "CreateDXGIFactory1", CreateDXGIFactory1_hook);
CreateDXGIFactory2.Register("dxgi.dll", "CreateDXGIFactory2", CreateDXGIFactory2_hook);
GetDebugInterface.Register("dxgi.dll", "DXGIGetDebugInterface", DXGIGetDebugInterface_hook);
GetDebugInterface1.Register("dxgi.dll", "DXGIGetDebugInterface1", DXGIGetDebugInterface1_hook);
}
private:
@@ -88,11 +88,11 @@ private:
RenderDocAnalysis m_RenderDocAnalysis;
Hook<PFN_CREATE_DXGI_FACTORY> CreateDXGIFactory;
Hook<PFN_CREATE_DXGI_FACTORY> CreateDXGIFactory1;
Hook<PFN_CREATE_DXGI_FACTORY2> CreateDXGIFactory2;
Hook<PFN_GET_DEBUG_INTERFACE> GetDebugInterface;
Hook<PFN_GET_DEBUG_INTERFACE1> GetDebugInterface1;
HookedFunction<PFN_CREATE_DXGI_FACTORY> CreateDXGIFactory;
HookedFunction<PFN_CREATE_DXGI_FACTORY> CreateDXGIFactory1;
HookedFunction<PFN_CREATE_DXGI_FACTORY2> CreateDXGIFactory2;
HookedFunction<PFN_GET_DEBUG_INTERFACE> GetDebugInterface;
HookedFunction<PFN_GET_DEBUG_INTERFACE1> GetDebugInterface1;
static HRESULT WINAPI CreateDXGIFactory_hook(__in REFIID riid, __out void **ppFactory)
{
+1 -1
View File
@@ -38,7 +38,7 @@ class OpenGLHook : LibraryHook
public:
OpenGLHook() {}
~OpenGLHook() {}
bool CreateHooks(const char *libName) { return false; }
bool RegisterHooks() { return false; }
virtual GLWindowingData MakeContext(GLWindowingData share)
{
RDCUNIMPLEMENTED("MakeContext");
+11 -10
View File
@@ -52,6 +52,7 @@ public:
bool CreateHooks(const char *libName);
void RegisterHooks() { CreateHooks("dummy"); }
void PopulateEGLFunctions()
{
if(!m_PopulatedHooks)
@@ -214,7 +215,7 @@ __attribute__((visibility("default"))) EGLContext eglCreateContext(EGLDisplay di
EGLContext shareContext,
EGLint const *attribList)
{
PosixHookReapply();
LibraryHooks::Refresh();
vector<EGLint> attribs;
@@ -374,7 +375,7 @@ __attribute__((visibility("default"))) __eglMustCastToProperFunctionPointerType
__eglMustCastToProperFunctionPointerType realFunc = NULL;
{
PosixScopedSuppressHooking suppress;
ScopedSuppressHooking suppress;
realFunc = eglhooks.real.GetProcAddress(func);
}
@@ -422,13 +423,13 @@ bool EGLHook::CreateHooks(const char *libName)
PosixHookFunction("eglGetProcAddress", (void *)&eglGetProcAddress);
// load the libEGL.so library and when loaded call libHooked which initialises GLES capture
PosixHookLibrary("libEGL.so", &libHooked);
PosixHookLibrary("libEGL.so.1", NULL);
PosixHookLibrary("libGL.so.1", NULL);
PosixHookLibrary("libGLESv1_CM.so", NULL);
PosixHookLibrary("libGLESv2.so", NULL);
PosixHookLibrary("libGLESv2.so.2", NULL);
PosixHookLibrary("libGLESv3.so", NULL);
LibraryHooks::RegisterLibraryHook("libEGL.so", &libHooked);
LibraryHooks::RegisterLibraryHook("libEGL.so.1", NULL);
LibraryHooks::RegisterLibraryHook("libGL.so.1", NULL);
LibraryHooks::RegisterLibraryHook("libGLESv1_CM.so", NULL);
LibraryHooks::RegisterLibraryHook("libGLESv2.so", NULL);
LibraryHooks::RegisterLibraryHook("libGLESv2.so.2", NULL);
LibraryHooks::RegisterLibraryHook("libGLESv3.so", NULL);
#if ENABLED(RDOC_ANDROID)
return true;
@@ -463,7 +464,7 @@ bool EGLHook::PopulateHooks()
m_PopulatedHooks = SharedPopulateHooks(dlsymFirst, [](const char *funcName) {
// on some android devices we need to hook dlsym, but eglGetProcAddress might call dlsym so we
// need to ensure we return the 'real' pointers
PosixScopedSuppressHooking suppress;
ScopedSuppressHooking suppress;
return (void *)eglGetProcAddress(funcName);
});
+5 -1
View File
@@ -63,13 +63,17 @@ public:
bool CreateHooks(const char *libName)
{
if(libName)
PosixHookLibrary("libGL.so", &libHooked);
{
LibraryHooks::RegisterLibraryHook("libGL.so", &libHooked);
LibraryHooks::RegisterLibraryHook("libGL.so.1", &libHooked);
}
SetupHooks();
return true;
}
void RegisterHooks() { CreateHooks("dummy"); }
// see callsite in glXSwapBuffers for explanation of why this is necessary
XID UnwrapGLXWindow(XID id)
{
@@ -1422,7 +1422,7 @@ bool SharedPopulateHooks(bool dlsymFirst, void *(*lookupFunc)(const char *))
#define HookInit(function) \
if(GL.function == NULL) \
{ \
PosixScopedSuppressHooking suppress; \
ScopedSuppressHooking suppress; \
if(dlsymFirst && GL.function == NULL) \
{ \
GL.function = \
@@ -1436,7 +1436,7 @@ bool SharedPopulateHooks(bool dlsymFirst, void *(*lookupFunc)(const char *))
#define HookExtension(funcPtrType, function) \
if(GL.function == NULL) \
{ \
PosixScopedSuppressHooking suppress; \
ScopedSuppressHooking suppress; \
if(dlsymFirst && GL.function == NULL) \
{ \
GL.function = (funcPtrType)PosixGetFunction(libGLdlsymHandle, STRINGIZE(function)); \
@@ -1447,7 +1447,7 @@ bool SharedPopulateHooks(bool dlsymFirst, void *(*lookupFunc)(const char *))
#define HookExtensionAlias(funcPtrType, function, alias) \
if(GL.function == NULL) \
{ \
PosixScopedSuppressHooking suppress; \
ScopedSuppressHooking suppress; \
if(dlsymFirst && GL.function == NULL) \
{ \
GL.function = (funcPtrType)PosixGetFunction(libGLdlsymHandle, STRINGIZE(alias)); \
+278 -272
View File
@@ -31,9 +31,9 @@
#include "hooks/hooks.h"
#include "strings/string_utils.h"
#define HookInit(function) \
CONCAT(function, _hook) \
.Initialize(STRINGIZE(function), "opengl32.dll", CONCAT(function, _hooked)); \
#define HookInit(function) \
CONCAT(function, _hook) \
.Register("opengl32.dll", STRINGIZE(function), CONCAT(function, _hooked)); \
GL.function = CONCAT(function, _hook)();
#define HookExtension(funcPtrType, function) \
@@ -85,7 +85,7 @@
for I in `seq 1 $N`; do echo -n ", t$I, p$I"; done;
echo ") \\";
echo -en " Hook<ret(WINAPI *)(";
echo -en " HookedFunction<ret(WINAPI *)(";
for I in `seq 1 $N`; do echo -n "t$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done;
echo ")> CONCAT(function, _hook); \\";
@@ -133,56 +133,56 @@
#undef far
#endif
#define HookWrapper0(ret, function) \
Hook<ret(WINAPI *)()> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(); \
static ret WINAPI CONCAT(function, _hooked)() \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(); \
#define HookWrapper0(ret, function) \
HookedFunction<ret(WINAPI *)()> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(); \
static ret WINAPI CONCAT(function, _hooked)() \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(); \
}
#define HookWrapper1(ret, function, t1, p1) \
Hook<ret(WINAPI *)(t1)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1); \
#define HookWrapper1(ret, function, t1, p1) \
HookedFunction<ret(WINAPI *)(t1)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1); \
}
#define HookWrapper2(ret, function, t1, p1, t2, p2) \
Hook<ret(WINAPI *)(t1, t2)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2); \
#define HookWrapper2(ret, function, t1, p1, t2, p2) \
HookedFunction<ret(WINAPI *)(t1, t2)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2); \
}
#define HookWrapper3(ret, function, t1, p1, t2, p2, t3, p3) \
Hook<ret(WINAPI *)(t1, t2, t3)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2, p3); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2, p3); \
#define HookWrapper3(ret, function, t1, p1, t2, p2, t3, p3) \
HookedFunction<ret(WINAPI *)(t1, t2, t3)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2, p3); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2, p3); \
}
#define HookWrapper4(ret, function, t1, p1, t2, p2, t3, p3, t4, p4) \
Hook<ret(WINAPI *)(t1, t2, t3, t4)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4) \
{ \
@@ -194,7 +194,7 @@
}
#define HookWrapper5(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \
{ \
@@ -206,7 +206,7 @@
}
#define HookWrapper6(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \
{ \
@@ -218,7 +218,7 @@
}
#define HookWrapper7(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \
{ \
@@ -230,7 +230,7 @@
}
#define HookWrapper8(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) \
{ \
@@ -243,7 +243,7 @@
#define HookWrapper9(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9) \
@@ -255,23 +255,24 @@
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9); \
}
#define HookWrapper10(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
#define HookWrapper10(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10) \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
}
#define HookWrapper11(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10, t11, p11) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)> CONCAT(function, \
_hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11) \
@@ -283,25 +284,26 @@
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \
}
#define HookWrapper12(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10, t11, p11, t12, p12) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
#define HookWrapper12(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10, t11, p11, t12, p12) \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12)> CONCAT( \
function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
}
#define HookWrapper13(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13)> CONCAT(function, \
_hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13)> CONCAT( \
function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
@@ -314,107 +316,108 @@
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \
}
#define HookWrapper14(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14)> CONCAT( \
function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13, t14); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
t14 p14) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
p14); \
}
#define HookWrapper15(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15)> CONCAT( \
function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13, t14, t15); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
t14 p14, t15 p15) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
p14, p15); \
}
#define HookWrapper16(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \
p16) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16)> CONCAT( \
#define HookWrapper14(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14) \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14)> CONCAT( \
function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13, t14, t15, t16); \
t12, t13, t14); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
t14 p14, t15 p15, t16 p16) \
t14 p14) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); \
return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
p14, p15, p16); \
p14); \
}
#define HookWrapper17(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \
p16, t17, p17) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17)> CONCAT( \
#define HookWrapper15(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15) \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15)> CONCAT( \
function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13, t14, t15, t16, t17); \
t12, t13, t14, t15); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
t14 p14, t15 p15, t16 p16, t17 p17) \
t14 p14, t15 p15) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, \
p17); \
return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
p14, p15, p16, p17); \
p14, p15); \
}
#define HookAliasWrapper0(ret, function, realfunc) \
Hook<ret(WINAPI *)()> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(); \
static ret WINAPI CONCAT(function, _hooked)() \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.realfunc(); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->realfunc(); \
#define HookWrapper16(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \
p16) \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16)> \
CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13, t14, t15, t16); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
t14 p14, t15 p15, t16 p16) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
p14, p15, p16); \
}
#define HookAliasWrapper1(ret, function, realfunc, t1, p1) \
Hook<ret(WINAPI *)(t1)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1) \
#define HookWrapper17(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \
p16, t17, p17) \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, \
t16, t17)> \
CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13, t14, t15, t16, t17); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
t14 p14, t15 p15, t16 p16, t17 p17) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, \
p17); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
p14, p15, p16, p17); \
}
#define HookAliasWrapper0(ret, function, realfunc) \
HookedFunction<ret(WINAPI *)()> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(); \
static ret WINAPI CONCAT(function, _hooked)() \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.realfunc(p1); \
return GL.realfunc(); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->realfunc(p1); \
return glhooks.GetDriver()->realfunc(); \
}
#define HookAliasWrapper1(ret, function, realfunc, t1, p1) \
HookedFunction<ret(WINAPI *)(t1)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.realfunc(p1); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->realfunc(p1); \
}
#define HookAliasWrapper2(ret, function, realfunc, t1, p1, t2, p2) \
Hook<ret(WINAPI *)(t1, t2)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2) \
{ \
@@ -426,7 +429,7 @@
}
#define HookAliasWrapper3(ret, function, realfunc, t1, p1, t2, p2, t3, p3) \
Hook<ret(WINAPI *)(t1, t2, t3)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3) \
{ \
@@ -438,7 +441,7 @@
}
#define HookAliasWrapper4(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4) \
Hook<ret(WINAPI *)(t1, t2, t3, t4)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4) \
{ \
@@ -450,7 +453,7 @@
}
#define HookAliasWrapper5(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \
{ \
@@ -462,7 +465,7 @@
}
#define HookAliasWrapper6(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \
{ \
@@ -475,7 +478,7 @@
#define HookAliasWrapper7(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, \
t7, p7) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \
{ \
@@ -488,7 +491,7 @@
#define HookAliasWrapper8(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, \
t7, p7, t8, p8) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) \
{ \
@@ -501,7 +504,7 @@
#define HookAliasWrapper9(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, \
t7, p7, t8, p8, t9, p9) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9) \
@@ -513,23 +516,24 @@
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9); \
}
#define HookAliasWrapper10(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
p6, t7, p7, t8, p8, t9, p9, t10, p10) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
#define HookAliasWrapper10(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
p6, t7, p7, t8, p8, t9, p9, t10, p10) \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
}
#define HookAliasWrapper11(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)> CONCAT(function, _hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)> CONCAT(function, \
_hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11) \
@@ -541,25 +545,26 @@
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \
}
#define HookAliasWrapper12(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12)> CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
#define HookAliasWrapper12(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12) \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12)> CONCAT( \
function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
}
#define HookAliasWrapper13(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13)> CONCAT(function, \
_hook); \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13)> CONCAT( \
function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
@@ -572,81 +577,82 @@
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \
}
#define HookAliasWrapper14(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \
t14, p14) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14)> CONCAT( \
function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13, t14); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
t14 p14) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
p14); \
}
#define HookAliasWrapper15(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \
t14, p14, t15, p15) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15)> CONCAT( \
function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13, t14, t15); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
t14 p14, t15 p15) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
p14, p15); \
}
#define HookAliasWrapper16(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
#define HookAliasWrapper14(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \
t14, p14, t15, p15, t16, p16) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16)> CONCAT( \
t14, p14) \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14)> CONCAT( \
function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13, t14, t15, t16); \
t12, t13, t14); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
t14 p14, t15 p15, t16 p16) \
t14 p14) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); \
return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
p14, p15, p16); \
p14); \
}
#define HookAliasWrapper17(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
#define HookAliasWrapper15(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \
t14, p14, t15, p15, t16, p16, t17, p17) \
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17)> CONCAT( \
t14, p14, t15, p15) \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15)> CONCAT( \
function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13, t14, t15, t16, t17); \
t12, t13, t14, t15); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
t14 p14, t15 p15, t16 p16, t17 p17) \
t14 p14, t15 p15) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, \
p17); \
return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
p14, p15, p16, p17); \
p14, p15); \
}
#define HookAliasWrapper16(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \
t14, p14, t15, p15, t16, p16) \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16)> \
CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13, t14, t15, t16); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
t14 p14, t15 p15, t16 p16) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
p14, p15, p16); \
}
#define HookAliasWrapper17(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \
t14, p14, t15, p15, t16, p16, t17, p17) \
HookedFunction<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, \
t16, t17)> \
CONCAT(function, _hook); \
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
t12, t13, t14, t15, t16, t17); \
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
t14 p14, t15 p15, t16 p16, t17 p17) \
{ \
SCOPED_LOCK(glLock); \
if(!glhooks.m_HaveContextCreation) \
return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, \
p17); \
gl_CurChunk = GLChunk::function; \
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
p14, p15, p16, p17); \
}
typedef BOOL(WINAPI *WGLMAKECURRENTPROC)(HDC, HGLRC);
@@ -673,11 +679,11 @@ public:
SetUnsupportedFunctionPointersToNULL();
}
~OpenGLHook() { delete m_GLDriver; }
bool CreateHooks(const char *libName)
void RegisterHooks()
{
SetupHooks();
LibraryHooks::RegisterLibraryHook("opengl32.dll", NULL);
return true;
SetupHooks();
}
static OpenGLHook glhooks;
@@ -901,19 +907,19 @@ private:
// and never being called by the app.
bool m_HaveContextCreation;
Hook<HGLRC(WINAPI *)(HDC)> wglCreateContext_hook;
Hook<BOOL(WINAPI *)(HGLRC)> wglDeleteContext_hook;
Hook<HGLRC(WINAPI *)(HDC, int)> wglCreateLayerContext_hook;
Hook<BOOL(WINAPI *)(HDC, HGLRC)> wglMakeCurrent_hook;
Hook<PROC(WINAPI *)(const char *)> wglGetProcAddress_hook;
Hook<BOOL(WINAPI *)(HDC)> SwapBuffers_hook;
Hook<BOOL(WINAPI *)(HDC)> wglSwapBuffers_hook;
Hook<BOOL(WINAPI *)(HDC, UINT)> wglSwapLayerBuffers_hook;
Hook<BOOL(WINAPI *)(UINT, CONST WGLSWAP *)> wglSwapMultipleBuffers_hook;
Hook<LONG(WINAPI *)(DEVMODEA *, DWORD)> ChangeDisplaySettingsA_hook;
Hook<LONG(WINAPI *)(DEVMODEW *, DWORD)> ChangeDisplaySettingsW_hook;
Hook<LONG(WINAPI *)(LPCSTR, DEVMODEA *, HWND, DWORD, LPVOID)> ChangeDisplaySettingsExA_hook;
Hook<LONG(WINAPI *)(LPCWSTR, DEVMODEW *, HWND, DWORD, LPVOID)> ChangeDisplaySettingsExW_hook;
HookedFunction<HGLRC(WINAPI *)(HDC)> wglCreateContext_hook;
HookedFunction<BOOL(WINAPI *)(HGLRC)> wglDeleteContext_hook;
HookedFunction<HGLRC(WINAPI *)(HDC, int)> wglCreateLayerContext_hook;
HookedFunction<BOOL(WINAPI *)(HDC, HGLRC)> wglMakeCurrent_hook;
HookedFunction<PROC(WINAPI *)(const char *)> wglGetProcAddress_hook;
HookedFunction<BOOL(WINAPI *)(HDC)> SwapBuffers_hook;
HookedFunction<BOOL(WINAPI *)(HDC)> wglSwapBuffers_hook;
HookedFunction<BOOL(WINAPI *)(HDC, UINT)> wglSwapLayerBuffers_hook;
HookedFunction<BOOL(WINAPI *)(UINT, CONST WGLSWAP *)> wglSwapMultipleBuffers_hook;
HookedFunction<LONG(WINAPI *)(DEVMODEA *, DWORD)> ChangeDisplaySettingsA_hook;
HookedFunction<LONG(WINAPI *)(DEVMODEW *, DWORD)> ChangeDisplaySettingsW_hook;
HookedFunction<LONG(WINAPI *)(LPCSTR, DEVMODEA *, HWND, DWORD, LPVOID)> ChangeDisplaySettingsExA_hook;
HookedFunction<LONG(WINAPI *)(LPCWSTR, DEVMODEW *, HWND, DWORD, LPVOID)> ChangeDisplaySettingsExW_hook;
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB_realfunc;
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB_realfunc;
@@ -1354,27 +1360,27 @@ private:
void SetupHooks()
{
wglCreateContext_hook.Initialize("wglCreateContext", "opengl32.dll", wglCreateContext_hooked);
wglDeleteContext_hook.Initialize("wglDeleteContext", "opengl32.dll", wglDeleteContext_hooked);
wglCreateLayerContext_hook.Initialize("wglCreateLayerContext", "opengl32.dll",
wglCreateLayerContext_hooked);
wglMakeCurrent_hook.Initialize("wglMakeCurrent", "opengl32.dll", wglMakeCurrent_hooked);
wglCreateContext_hook.Register("opengl32.dll", "wglCreateContext", wglCreateContext_hooked);
wglDeleteContext_hook.Register("opengl32.dll", "wglDeleteContext", wglDeleteContext_hooked);
wglCreateLayerContext_hook.Register("opengl32.dll", "wglCreateLayerContext",
wglCreateLayerContext_hooked);
wglMakeCurrent_hook.Register("opengl32.dll", "wglMakeCurrent", wglMakeCurrent_hooked);
wglGetProcAddress_hook.Initialize("wglGetProcAddress", "opengl32.dll", wglGetProcAddress_hooked);
wglSwapBuffers_hook.Initialize("wglSwapBuffers", "opengl32.dll", wglSwapBuffers_hooked);
wglSwapLayerBuffers_hook.Initialize("wglSwapLayerBuffers", "opengl32.dll",
wglSwapLayerBuffers_hooked);
wglSwapMultipleBuffers_hook.Initialize("wglSwapMultipleBuffers", "opengl32.dll",
wglSwapMultipleBuffers_hooked);
SwapBuffers_hook.Initialize("SwapBuffers", "gdi32.dll", SwapBuffers_hooked);
ChangeDisplaySettingsA_hook.Initialize("ChangeDisplaySettingsA", "user32.dll",
ChangeDisplaySettingsA_hooked);
ChangeDisplaySettingsW_hook.Initialize("ChangeDisplaySettingsW", "user32.dll",
ChangeDisplaySettingsW_hooked);
ChangeDisplaySettingsExA_hook.Initialize("ChangeDisplaySettingsExA", "user32.dll",
ChangeDisplaySettingsExA_hooked);
ChangeDisplaySettingsExW_hook.Initialize("ChangeDisplaySettingsExW", "user32.dll",
ChangeDisplaySettingsExW_hooked);
wglGetProcAddress_hook.Register("opengl32.dll", "wglGetProcAddress", wglGetProcAddress_hooked);
wglSwapBuffers_hook.Register("opengl32.dll", "wglSwapBuffers", wglSwapBuffers_hooked);
wglSwapLayerBuffers_hook.Register("opengl32.dll", "wglSwapLayerBuffers",
wglSwapLayerBuffers_hooked);
wglSwapMultipleBuffers_hook.Register("opengl32.dll", "wglSwapMultipleBuffers",
wglSwapMultipleBuffers_hooked);
SwapBuffers_hook.Register("gdi32.dll", "SwapBuffers", SwapBuffers_hooked);
ChangeDisplaySettingsA_hook.Register("user32.dll", "ChangeDisplaySettingsA",
ChangeDisplaySettingsA_hooked);
ChangeDisplaySettingsW_hook.Register("user32.dll", "ChangeDisplaySettingsW",
ChangeDisplaySettingsW_hooked);
ChangeDisplaySettingsExA_hook.Register("user32.dll", "ChangeDisplaySettingsExA",
ChangeDisplaySettingsExA_hooked);
ChangeDisplaySettingsExW_hook.Register("user32.dll", "ChangeDisplaySettingsExW",
ChangeDisplaySettingsExW_hooked);
DLLExportHooks();
}
+1 -1
View File
@@ -24,7 +24,7 @@
#include "gl_library_egl.h"
#include <dlfcn.h>
#include "os/posix/posix_hook.h"
#include "hooks/hooks.h"
bool EGLPointers::LoadSymbolsFrom(void *lib_handle)
{
+3 -3
View File
@@ -48,16 +48,16 @@
class VulkanHook : LibraryHook
{
VulkanHook() {}
bool CreateHooks(const char *libName)
void RegisterHooks()
{
// we don't register any library or function hooks because we use the layer system
// we assume the implicit layer is registered - the UI will prompt the user about installing it.
Process::RegisterEnvironmentModification(EnvironmentModification(
EnvMod::Set, EnvSep::NoSep, "ENABLE_VULKAN_RENDERDOC_CAPTURE", "1"));
// check options to set further variables, and apply
OptionsUpdated();
return true;
}
void OptionsUpdated()
+44 -18
View File
@@ -26,35 +26,61 @@
#include "hooks.h"
#include "common/common.h"
LibraryHooks &LibraryHooks::GetInstance()
static std::vector<LibraryHook *> &LibList()
{
static LibraryHooks instance;
return instance;
static std::vector<LibraryHook *> libs;
return libs;
}
void LibraryHooks::RegisterLibrary(LibraryHook *lib)
LibraryHook::LibraryHook()
{
m_Libraries.push_back(lib);
LibList().push_back(this);
}
void LibraryHooks::CreateHooks()
void LibraryHooks::RegisterHooks()
{
HOOKS_BEGIN();
for(LibraryHook *lib : m_Libraries)
lib->CreateHooks("dummy");
HOOKS_END();
}
BeginHookRegistration();
void LibraryHooks::RemoveHooks()
{
if(m_HooksRemoved)
return;
m_HooksRemoved = true;
HOOKS_REMOVE();
for(LibraryHook *lib : LibList())
lib->RegisterHooks();
EndHookRegistration();
}
void LibraryHooks::OptionsUpdated()
{
for(LibraryHook *lib : m_Libraries)
for(LibraryHook *lib : LibList())
lib->OptionsUpdated();
}
////////////////////////////////////////////////////////////////////////
// Very temporary compatibility layer with previous function interface.
//
// PosixHookFunction just calls LibraryHooks::RegisterFunctionHook and
// stores the resulting pointer in a map to look up later in
// PosixGetFunction
////////////////////////////////////////////////////////////////////////
static std::map<std::string, void **> origLookup;
void PosixHookFunction(const char *name, void *hook)
{
void **orig = origLookup[name];
if(orig == NULL)
{
orig = origLookup[name] = new void *;
*orig = NULL;
}
LibraryHooks::RegisterFunctionHook("", FunctionHook(name, orig, hook));
}
void *PosixGetFunction(void *handle, const char *name)
{
void **orig = origLookup[name];
if(orig && *orig)
return *orig;
ScopedSuppressHooking suppress;
return Process::GetFunctionAddress(handle, name);
}
+175 -62
View File
@@ -25,84 +25,197 @@
#pragma once
#include <map>
using std::map;
#include "os/os_specific.h"
// include os-specific hooking mechanisms here
typedef std::function<void(void *)> FunctionLoadCallback;
#if ENABLED(RDOC_WIN32)
struct FunctionHook
{
FunctionHook() : orig(NULL), hook(NULL) {}
FunctionHook(const char *f, void **o, void *d) : function(f), orig(o), hook(d) {}
bool operator<(const FunctionHook &h) const { return function < h.function; }
std::string function;
void **orig;
void *hook;
};
#include "os/win32/win32_hook.h"
// == Hooking workflow overview ==
//
// Each subsystem that wants to hook libraries creates a LibraryHook instance. That registers with
// LibraryHooks via the singleton in global constructors, but does nothing initially.
//
// Early in init, during RenderDoc's initialisation, the last thing that happens is a call to
// LibraryHooks::RegisterHooks(). This iterates through the LibraryHook instances and calls
// RegisterHooks on each of them.
//
// Each subsystem should call LibraryHooks::RegisterLibraryHook() for the filename of each library
// it wants to hook, then LibraryHooks::RegisterFunctionHook() for each function it wants to hook
// within that library. Note that not all platforms will use all the information provided, but only
// in a way that's invisible to the user. These are lightweight calls to register the hooks, and
// don't do any work yet.
//
// A registered library hook can get an optional callback when that library is first loaded.
//
// Similarly a registered function hook can provide a function pointer location which will be filled
// out with the function pointer to call onwards. This may just be the real implementation, or a
// trampoline, depending on the platform hooking method.
//
// Once all of this is completed, these hooks will be applied and activated as necessary. If any
// libraries are already loaded, library callbacks will fire here. Similarly function hook original
// pointers will be filled out if they are already available. Library callbacks will fire precisely
// once, the first time the library is loaded.
//
// NOTE: An important result of the behaviour above is that original function pointers are not
// necessarily available until the function is actually hooked. The hooking will automatically
// propagate all functions hooked in a library once it's loaded, and since some platforms may
// trampoline-hook target functions it is *not* safe to just get the target function's pointer as
// this may then call back into hooks. The only exception to this is with a library-specific
// function for fetching pointers such as GetProcAddress on OpenGL/Vulkan. However in this case care
// must be taken to suppress any effect of function interception by calling the relevant suppression
// functions. This ensures that if the API-specific GetProcAddress calls into the platform function
// fetch, it doesn't form an infinite loop.
//
// Also in the case that a function may come from many libraries, or it has multiple aliased names,
// the order of registration is important. The hooking implementations will always follow the order
// provided as a priority list, so if you register libFoo before libBar, any functions in libFoo
// have precedence. Similarly if you register foofunc() before barfunc() but pointed to the same
// pointer location for storing the original function pointer, barfunc()'s pointer will not
// overwrite foofunc() if it exists.
//
// == Hooking details (platform-specific) ==
//
// The method of hooking varies by platform but follows the same general pattern. During
// registration we build up lists of which libraries and functions are to be hooked. Once the
// registration is complete we apply all of the hooks.
//
// NOTE: The library name for function hooks is only used on windows, since on linux/android
// namespace resolution is a bit fuzzier. At the time of writing there are no cases where two
// libraries have the same function that aren't functionally equivalent.
//
// - Windows -
// On windows this involves iterating over all loaded libraries and hooking their IAT tables. We
// also hook internally any functions for dynamically loading libraries or fetching functions, so
// that we can continue to re-wrap any newly loaded libraries.
//
// Loaded libraries at startup (most likely because the exe linked against them) have their
// callbacks fired immediately. Otherwise any time a new library is found on a subsequent iteration
// from a LoadLibrary-type call we fire the callback.
//
// Whenever a library is newly found, we hook all the entry points and update any original function
// pointers that are set to NULL.
//
// - Linux -
// On linux we rely on exporting all hooked symbols, and using LD_PRELOAD to load our library first
// in resolution order. All we do is hook dlopen so that when a new library is loaded we can
// redirect the returned library handle to ourselves, as well as process any pending function hooks.
//
// - Android -
// On android the implementation varies depending on whether we're using interceptor-lib or not.
// This is optional at build time but produces more reliable results:
//
// Without interceptor-lib:
// The implementation is similar to windows. Since we don't have LD_PRELOAD we need to patch import
// tables of any loaded libraries. We also cannot reliably hook dlopen on android to redirect the
// library handle to ourselves, so instead we hook dlsym and check to see if it corresponds to a
// function we're intercepting. This is the need for the 'suppress hooking' function, since if
// eglGetProcAddress calls into dlsym we don't want to intercept that dlsym and return our own
// function.
//
// With interceptor-lib:
// Instead of patching imports we overwrite the assembly at each entry point in the *target*
// library, and patch it to call into our hooks. Then we create trampolines to restore the original
// function for onwards-calling.
//
// To ensure sanity, we always load all registered libraries in the first hook applying phase. This
// ensures that we don't end up in a weird situation where one library is loaded, not all functions
// are hooked, the user code tries to populate any missing functions and then later another library
// is loaded and we patch it after having requested function pointers. Ensuring all libraries that
// we *might* patch are loaded ASAP, everything is consistent since after that any functions that
// don't have trampolines provided will never be trampolined in the future.
//
// Sometimes interceptor-lib can fail, at which point we fall back to the path above for those
// functions and try to follow and patch any imports to them.
template <typename FuncType>
class Hook
struct LibraryHook;
// this singleton allows you to compile in code that defines a hook for a given library
// (and it will be registered). Then when the renderdoc library is initialised in the target
// program RegisterHooks() will be called to set up the hooks.
class LibraryHooks
{
public:
Hook() { orig_funcptr = NULL; }
~Hook() {}
// generic, implemented in hooks.cpp to iterate over all registered libraries
static void RegisterHooks();
static void OptionsUpdated();
// platform specific implementations
// Removes hooks (where possible) and restores everything to an un-hooked state
static void RemoveHooks();
// refreshes hooks, useful on android where hooking can be unreliable
static void Refresh();
// Ignore this library - i.e. do not hook any calls it makes. Useful in the case where a library
// might call in to hooked APIs but we want to treat it as a black box.
static void IgnoreLibrary(const char *libraryName);
// register a library for hooking, providing an optional callback to be called the first time the
// library has been loaded and all functions in it hooked.
static void RegisterLibraryHook(const char *libraryName, FunctionLoadCallback loadedCallback);
// registers a function to be hooked, and an optional location of where to store the original
// onward function pointer
static void RegisterFunctionHook(const char *libraryName, const FunctionHook &hook);
// detect if an identifier is present in the current process - used as a marker to indicate
// replay-type programs.
static bool Detect(const char *identifier);
private:
static void BeginHookRegistration();
static void EndHookRegistration();
};
// defines the interface that a library hooking class will implement.
struct LibraryHook
{
LibraryHook();
virtual void RegisterHooks() = 0;
virtual void OptionsUpdated() {}
private:
friend class LibraryHooks;
static std::vector<LibraryHook *> m_Libraries;
};
template <typename FuncType>
class HookedFunction
{
public:
HookedFunction() { orig_funcptr = NULL; }
~HookedFunction() {}
FuncType operator()() { return (FuncType)orig_funcptr; }
void SetFuncPtr(void *ptr) { orig_funcptr = ptr; }
void Initialize(const char *function, const char *module_name, void *destination_function_ptr)
void Register(const char *module_name, const char *function, void *destination_function_ptr)
{
orig_funcptr = Process::GetFunctionAddress(Process::LoadModule(module_name), function);
Win32_IAT_Hook(&orig_funcptr, module_name, function, destination_function_ptr);
LibraryHooks::RegisterFunctionHook(
module_name, FunctionHook(function, &orig_funcptr, destination_function_ptr));
}
private:
void *orig_funcptr;
};
#define HOOKS_BEGIN() Win32_IAT_BeginHooks()
#define HOOKS_END() Win32_IAT_EndHooks()
#define HOOKS_REMOVE() Win32_IAT_RemoveHooks()
#define HOOKS_IDENTIFY(identifier) Win32_HookDetect(identifier)
#elif ENABLED(RDOC_POSIX)
#include "os/posix/posix_hook.h"
// just need this for dlsym
#include <dlfcn.h>
#define HOOKS_BEGIN() PosixHookInit()
#define HOOKS_END() PosixHookApply()
#define HOOKS_REMOVE()
#define HOOKS_IDENTIFY(identifier) PosixHookDetect(identifier)
#else
#error "undefined platform"
#endif
struct LibraryHook;
// this singleton allows you to compile in code that defines a hook for a given library
// (and it will be registered). Then when the renderdoc library is initialised in the target
// program CreateHooks() will be called to set up the hooks.
class LibraryHooks
struct ScopedSuppressHooking
{
public:
LibraryHooks() : m_HooksRemoved(false) {}
static LibraryHooks &GetInstance();
void RegisterLibrary(LibraryHook *lib);
void CreateHooks();
void OptionsUpdated();
void RemoveHooks();
private:
bool m_HooksRemoved;
std::vector<LibraryHook *> m_Libraries;
ScopedSuppressHooking();
~ScopedSuppressHooking();
};
// defines the interface that a library hooking class will implement.
struct LibraryHook
{
LibraryHook() { LibraryHooks::GetInstance().RegisterLibrary(this); }
virtual bool CreateHooks(const char *dummy) = 0;
virtual void OptionsUpdated() {}
};
////////////////////////////////////////////////////////////////////////
// Very temporary compatibility layer with previous function interface.
////////////////////////////////////////////////////////////////////////
void PosixHookFunction(const char *name, void *hook);
void *PosixGetFunction(void *handle, const char *name);
+199 -149
View File
@@ -25,7 +25,7 @@
#include "3rdparty/plthook/plthook.h"
#include "common/common.h"
#include "common/threading.h"
#include "os/posix/posix_hook.h"
#include "hooks/hooks.h"
#include <android/dlext.h>
#include <dlfcn.h>
@@ -34,6 +34,7 @@
#include <stddef.h>
#include <sys/mman.h>
#include <unistd.h>
#include <algorithm>
#include <map>
#include <set>
@@ -72,37 +73,32 @@
#error unsupported OS
#endif
void PosixHookInit()
{
}
bool PosixHookDetect(const char *identifier)
{
return dlsym(RTLD_DEFAULT, identifier) != NULL;
}
class HookingInfo
{
public:
void AddFunctionHook(const std::string &name, void *hook)
void AddFunctionHook(const FunctionHook &hook)
{
SCOPED_LOCK(lock);
funchooks[name] = hook;
funchooks.push_back(hook);
// add to map to speed-up lookup in GetFunctionHook
funchook_map[hook.function] = hook;
}
void AddLibHook(const std::string &name)
{
SCOPED_LOCK(lock);
libhooks.insert(name);
if(std::find(libhooks.begin(), libhooks.end(), name) == libhooks.end())
libhooks.push_back(name);
}
void AddHookCallback(const std::string &name, dlopenCallback hook)
void AddHookCallback(const std::string &name, FunctionLoadCallback callback)
{
SCOPED_LOCK(lock);
hookcallbacks[name] = hook;
hookcallbacks[name].push_back(callback);
}
std::map<std::string, void *> GetFunctionHooks()
std::vector<FunctionHook> GetFunctionHooks()
{
SCOPED_LOCK(lock);
return funchooks;
@@ -113,24 +109,25 @@ public:
SCOPED_LOCK(lock);
libhooks.clear();
funchooks.clear();
funchook_map.clear();
}
std::set<std::string> GetLibHooks()
std::vector<std::string> GetLibHooks()
{
SCOPED_LOCK(lock);
return libhooks;
}
std::map<std::string, dlopenCallback> GetHookCallbacks()
std::map<std::string, std::vector<FunctionLoadCallback>> GetHookCallbacks()
{
SCOPED_LOCK(lock);
return hookcallbacks;
}
void *GetFunctionHook(const std::string &name)
FunctionHook GetFunctionHook(const std::string &name)
{
SCOPED_LOCK(lock);
return funchooks[name];
return funchook_map[name];
}
bool IsLibHook(const std::string &path)
@@ -196,27 +193,15 @@ public:
hooked_soname_already.insert(soname);
}
void SetTrampoline(const std::string &funcname, void *trampoline)
{
SCOPED_LOCK(lock);
trampolines[funcname] = trampoline;
}
void *GetTrampoline(const std::string &funcname)
{
SCOPED_LOCK(lock);
return trampolines[funcname];
}
private:
std::set<std::string> hooked_soname_already;
std::set<void *> hooked_handle_already;
std::map<std::string, void *> funchooks;
std::set<std::string> libhooks;
std::vector<FunctionHook> funchooks;
std::map<std::string, FunctionHook> funchook_map;
std::vector<std::string> libhooks;
std::map<std::string, dlopenCallback> hookcallbacks;
std::map<std::string, void *> trampolines;
std::map<std::string, std::vector<FunctionLoadCallback>> hookcallbacks;
Threading::CriticalSection lock;
};
@@ -227,37 +212,6 @@ HookingInfo &GetHookInfo()
return hookinfo;
}
void PosixHookFunction(const char *name, void *hook)
{
GetHookInfo().AddFunctionHook(name, hook);
}
void PosixHookLibrary(const char *name, dlopenCallback cb)
{
GetHookInfo().AddLibHook(name);
if(cb)
{
GetHookInfo().AddHookCallback(name, cb);
dlopen(name, RTLD_NOW);
}
}
void *PosixGetFunction(void *handle, const char *name)
{
// when we're not using interceptor-lib, this will always return NULL
void *ret = GetHookInfo().GetTrampoline(name);
if(ret)
{
HOOK_DEBUG_PRINT("Returning trampoline %p for %s", ret, name);
return ret;
}
HOOK_DEBUG_PRINT("No trampoline for %s, going to dlsym", name);
PosixScopedSuppressHooking suppress;
return dlsym(handle, name);
}
void *intercept_dlopen(const char *filename, int flag)
{
if(GetHookInfo().IsLibHook(filename))
@@ -397,8 +351,8 @@ static int dl_iterate_callback(struct dl_phdr_info *info, size_t size, void *dat
HOOK_DEBUG_PRINT("[%i] %s at %p (ptr to %p)", i, importname, import, *import);
void *repl = GetHookInfo().GetFunctionHook(importname);
if(repl)
const FunctionHook repl = GetHookInfo().GetFunctionHook(importname);
if(repl.hook)
{
HOOK_DEBUG_PRINT("replacing %s!", importname);
@@ -426,7 +380,10 @@ static int dl_iterate_callback(struct dl_phdr_info *info, size_t size, void *dat
HOOK_DEBUG_PRINT("Not in relro! - %p vs %p vs %p", relro_base, import, relro_end);
}
*import = repl;
// note we don't save the orig function here, since we want to apply our library priorities
// and we don't know what order these headers will be iterated in. See EndHookRegistration
// for where we iterate and fetch all the function pointers we want.
*import = repl.hook;
if(pagebase)
{
@@ -450,11 +407,6 @@ static int dl_iterate_callback(struct dl_phdr_info *info, size_t size, void *dat
return 0;
}
void PosixHookReapply()
{
dl_iterate_phdr(dl_iterate_callback, NULL);
}
// android has a special dlopen that passes the caller address in.
typedef void *(*pfn__loader_dlopen)(const char *filename, int flags, const void *caller_addr);
@@ -525,37 +477,16 @@ extern "C" __attribute__((visibility("default"))) void *hooked_android_dlopen_ex
return ret;
}
PosixScopedSuppressHooking::PosixScopedSuppressHooking()
{
if(suppressTLS == 0)
return;
uintptr_t old = (uintptr_t)Threading::GetTLSValue(suppressTLS);
Threading::SetTLSValue(suppressTLS, (void *)(old + 1));
}
PosixScopedSuppressHooking::~PosixScopedSuppressHooking()
{
if(suppressTLS == 0)
return;
uintptr_t old = (uintptr_t)Threading::GetTLSValue(suppressTLS);
Threading::SetTLSValue(suppressTLS, (void *)(old - 1));
}
bool hooks_suppressed()
{
return (uintptr_t)Threading::GetTLSValue(suppressTLS) > 0;
}
bool hooks_suppressed();
extern "C" __attribute__((visibility("default"))) void *hooked_dlsym(void *handle, const char *symbol)
{
if(handle == NULL || symbol == NULL || hooks_suppressed())
return dlsym(handle, symbol);
void *repl = GetHookInfo().GetFunctionHook(symbol);
const FunctionHook repl = GetHookInfo().GetFunctionHook(symbol);
if(repl == NULL)
if(repl.hook == NULL)
return dlsym(handle, symbol);
if(!GetHookInfo().IsHooked(handle))
@@ -568,8 +499,8 @@ extern "C" __attribute__((visibility("default"))) void *hooked_dlsym(void *handl
if(GetHookInfo().IsLibHook(handle))
{
HOOK_DEBUG_PRINT("identified dlsym(%s) we want to interpose! returning %p", symbol, repl);
return repl;
HOOK_DEBUG_PRINT("identified dlsym(%s) we want to interpose! returning %p", symbol, repl.hook);
return repl.hook;
}
void *ret = dlsym(handle, symbol);
@@ -579,7 +510,7 @@ extern "C" __attribute__((visibility("default"))) void *hooked_dlsym(void *handl
return ret;
}
static void PosixHookApplyCommon()
static void InstallHooksCommon()
{
suppressTLS = Threading::AllocateTLSSlot();
@@ -596,15 +527,16 @@ static void PosixHookApplyCommon()
if(loader_dlopen)
{
PosixHookFunction("dlopen", (void *)&hooked_dlopen);
LibraryHooks::RegisterFunctionHook("", FunctionHook("dlopen", NULL, (void *)&hooked_dlopen));
}
else
{
RDCWARN("Couldn't find __loader_dlopen, falling back to slow path for dlopen hooking");
PosixHookFunction("dlsym", (void *)&hooked_dlsym);
LibraryHooks::RegisterFunctionHook("", FunctionHook("dlsym", NULL, (void *)&hooked_dlsym));
}
PosixHookFunction("android_dlopen_ext", (void *)&hooked_android_dlopen_ext);
LibraryHooks::RegisterFunctionHook(
"", FunctionHook("android_dlopen_ext", NULL, (void *)&hooked_android_dlopen_ext));
}
#if defined(RENDERDOC_HAVE_INTERCEPTOR_LIB)
@@ -616,25 +548,25 @@ void intercept_error(void *, const char *error_msg)
#include "3rdparty/interceptor-lib/include/interceptor.h"
void PosixHookApply()
void PatchHookedFunctions()
{
RDCLOG("Applying hooks with interceptor-lib");
// see below - Huawei workaround
#if defined(__LP64__)
PosixHookLibrary("/system/lib64/libhwgl.so", NULL);
LibraryHooks::RegisterLibraryHook("/system/lib64/libhwgl.so", NULL);
#else
PosixHookLibrary("/system/lib/libhwgl.so", NULL);
LibraryHooks::RegisterLibraryHook("/system/lib/libhwgl.so", NULL);
#endif
std::set<std::string> libs = GetHookInfo().GetLibHooks();
std::map<std::string, void *> funchooks = GetHookInfo().GetFunctionHooks();
std::vector<std::string> libs = GetHookInfo().GetLibHooks();
std::vector<FunctionHook> funchooks = GetHookInfo().GetFunctionHooks();
// we just leak this
void *intercept = InitializeInterceptor();
std::set<std::string> fallbacklibs;
std::set<std::pair<std::string, void *>> fallbackhooks;
std::set<FunctionHook> fallbackhooks;
for(const std::string &lib : libs)
{
@@ -650,9 +582,11 @@ void PosixHookApply()
HOOK_DEBUG_PRINT("Hooking %s = %p", lib.c_str(), handle);
for(const std::pair<std::string, void *> &hook : funchooks)
std::set<void *> foundfunctions;
for(const FunctionHook &hook : funchooks)
{
void *oldfunc = dlsym(handle, hook.first.c_str());
void *oldfunc = dlsym(handle, hook.function.c_str());
// UNTESTED workaround taken directly from GAPID, in installer.cpp. Quoted comment:
/*
@@ -662,24 +596,30 @@ void PosixHookApply()
// so try to intercept the internal implementation instead.
*/
if(huawei && oldfunc == NULL)
oldfunc = dlsym(handle, ("hw_" + hook.first).c_str());
oldfunc = dlsym(handle, ("hw_" + hook.function).c_str());
if(GetHookInfo().IsHooked(oldfunc))
continue;
if(!oldfunc)
{
HOOK_DEBUG_PRINT("%s didn't have %s", lib.c_str(), hook.first.c_str());
HOOK_DEBUG_PRINT("%s didn't have %s", lib.c_str(), hook.function.c_str());
continue;
}
HOOK_DEBUG_PRINT("Hooking %s::%s = %p with %p", lib.c_str(), hook.first.c_str(), oldfunc,
hook.second);
HOOK_DEBUG_PRINT("Hooking %s::%s = %p with %p", lib.c_str(), hook.function.c_str(), oldfunc,
hook.hook);
void *trampoline = NULL;
bool success =
InterceptFunction(intercept, oldfunc, hook.second, &trampoline, &intercept_error);
bool success = InterceptFunction(intercept, oldfunc, hook.hook, &trampoline, &intercept_error);
if(!hook.orig)
RDCWARN("No original pointer for hook of '%s' - trampoline will be lost!",
hook.function.c_str());
if(hook.orig && *hook.orig == NULL)
*hook.orig = trampoline;
if(success)
{
@@ -687,24 +627,15 @@ void PosixHookApply()
}
else
{
RDCERR("Failed to hook %s::%s!", lib.c_str(), hook.first.c_str());
RDCERR("Failed to hook %s::%s!", lib.c_str(), hook.function.c_str());
fallbacklibs.insert(lib);
fallbackhooks.insert(hook);
}
GetHookInfo().SetHooked(oldfunc);
GetHookInfo().SetTrampoline(hook.first, trampoline);
}
}
std::map<std::string, dlopenCallback> callbacks = GetHookInfo().GetHookCallbacks();
for(const std::pair<std::string, dlopenCallback> &cb : callbacks)
{
HOOK_DEBUG_PRINT("Calling complete callback for %s", cb.first.c_str());
cb.second(dlopen(cb.first.c_str(), RTLD_GLOBAL));
}
// we still need to hook android_dlopen_ext with interceptor-lib so that we can intercept the
// vulkan loader's attempts to load our library and prevent it from loading a second copy (!!)
// into the process.
@@ -718,34 +649,153 @@ void PosixHookApply()
GetHookInfo().AddLibHook(l);
}
for(const std::pair<std::string, void *> &hook : fallbackhooks)
for(const FunctionHook &hook : fallbackhooks)
{
RDCLOG("Falling back to PLT hooking for %s", hook.first.c_str());
GetHookInfo().AddFunctionHook(hook.first, hook.second);
RDCLOG("Falling back to PLT hooking for %s", hook.function.c_str());
GetHookInfo().AddFunctionHook(hook);
}
// this already hooks dlopen (if possible) and android_dlopen_ext, which is enough
PosixHookApplyCommon();
PosixHookReapply();
}
#else
void PosixHookApply()
void PatchHookedFunctions()
{
RDCLOG("Applying hooks with PLT hooks");
PosixHookApplyCommon();
PosixHookReapply();
std::map<std::string, dlopenCallback> callbacks = GetHookInfo().GetHookCallbacks();
for(const std::pair<std::string, dlopenCallback> &cb : callbacks)
{
HOOK_DEBUG_PRINT("Calling complete callback for %s", cb.first.c_str());
cb.second(dlopen(cb.first.c_str(), RTLD_GLOBAL));
}
}
#endif
bool LibraryHooks::Detect(const char *identifier)
{
return dlsym(RTLD_DEFAULT, identifier) != NULL;
}
void LibraryHooks::RemoveHooks()
{
RDCERR("Removing hooks is not possible on this platform");
}
void LibraryHooks::BeginHookRegistration()
{
// nothing to do
}
void LibraryHooks::RegisterFunctionHook(const char *libraryName, const FunctionHook &hook)
{
// we don't use the library name on android
(void)libraryName;
HOOK_DEBUG_PRINT("Registering function hook for %s: %p", hook.function.c_str(), hook.hook);
GetHookInfo().AddFunctionHook(hook);
}
void LibraryHooks::RegisterLibraryHook(const char *name, FunctionLoadCallback cb)
{
GetHookInfo().AddLibHook(name);
HOOK_DEBUG_PRINT("Registering library hook for %s %s", name, cb ? "with callback" : "");
// open the library immediately if we can
dlopen(name, RTLD_NOW);
if(cb)
GetHookInfo().AddHookCallback(name, cb);
}
void LibraryHooks::IgnoreLibrary(const char *libraryName)
{
}
void LibraryHooks::EndHookRegistration()
{
HOOK_DEBUG_PRINT("EndHookRegistration");
// ensure we load all libraries we can immediately, so they are immediately hooked and don't get
// loaded later.
std::vector<std::string> libs = GetHookInfo().GetLibHooks();
for(const std::string &lib : libs)
{
void *handle = dlopen(lib.c_str(), RTLD_GLOBAL);
HOOK_DEBUG_PRINT("%s: %p", lib.c_str(), handle);
}
PatchHookedFunctions();
// this already hooks dlopen (if possible) and android_dlopen_ext, which is enough
InstallHooksCommon();
LibraryHooks::Refresh();
// iterate our list of libraries and look up the original pointer for any that we don't already
// have. If we have interceptor-lib this will only be for functions that failed to generate a
// trampoline and we're PLT hooking - without interceptor-lib this will be all functions, but it
// will allow us to control the order/priority.
std::vector<std::string> libraryHooks = GetHookInfo().GetLibHooks();
std::vector<FunctionHook> functionHooks = GetHookInfo().GetFunctionHooks();
RDCLOG("Fetching %zu original function pointers over %zu libraries", functionHooks.size(),
libraryHooks.size());
for(auto it = libraryHooks.begin(); it != libraryHooks.end(); ++it)
{
void *handle = dlopen(it->c_str(), RTLD_NOLOAD | RTLD_GLOBAL);
if(handle)
{
for(FunctionHook &hook : functionHooks)
{
if(hook.orig && *hook.orig == NULL)
*hook.orig = dlsym(handle, hook.function.c_str());
}
}
}
RDCLOG("Finished");
// call the callbacks for any libraries that loaded now. If the library wasn't loaded above then
// it can't be loaded, since we only hook system libraries.
std::map<std::string, std::vector<FunctionLoadCallback>> callbacks =
GetHookInfo().GetHookCallbacks();
for(const std::pair<std::string, std::vector<FunctionLoadCallback>> &cb : callbacks)
{
void *handle = dlopen(cb.first.c_str(), RTLD_GLOBAL);
if(handle)
{
HOOK_DEBUG_PRINT("Calling callbacks for %s", cb.first.c_str());
for(FunctionLoadCallback callback : cb.second)
if(callback)
callback(handle);
}
}
RDCLOG("Called library callbacks - hook registration complete");
}
void LibraryHooks::Refresh()
{
RDCLOG("Refreshing android hooks...");
dl_iterate_phdr(dl_iterate_callback, NULL);
RDCLOG("Refreshed");
}
ScopedSuppressHooking::ScopedSuppressHooking()
{
if(suppressTLS == 0)
return;
uintptr_t old = (uintptr_t)Threading::GetTLSValue(suppressTLS);
Threading::SetTLSValue(suppressTLS, (void *)(old + 1));
}
ScopedSuppressHooking::~ScopedSuppressHooking()
{
if(suppressTLS == 0)
return;
uintptr_t old = (uintptr_t)Threading::GetTLSValue(suppressTLS);
Threading::SetTLSValue(suppressTLS, (void *)(old - 1));
}
bool hooks_suppressed()
{
return (uintptr_t)Threading::GetTLSValue(suppressTLS) > 0;
}
+23 -20
View File
@@ -22,46 +22,49 @@
* THE SOFTWARE.
******************************************************************************/
#include "os/posix/posix_hook.h"
#include "hooks/hooks.h"
#include <dlfcn.h>
#include <stddef.h>
void PosixHookInit()
void LibraryHooks::BeginHookRegistration()
{
// nothing to do
}
void LibraryHooks::RegisterLibraryHook(char const *, FunctionLoadCallback cb)
{
if(cb)
RDCERR("Hooking on apple not complete - function load callback not implemented");
}
void LibraryHooks::IgnoreLibrary(const char *libraryName)
{
}
bool PosixHookDetect(const char *identifier)
void LibraryHooks::EndHookRegistration()
{
}
bool LibraryHooks::Detect(const char *identifier)
{
return dlsym(RTLD_DEFAULT, identifier) != NULL;
}
void PosixHookLibrary(const char *name, dlopenCallback cb)
void LibraryHooks::RemoveHooks()
{
RDCERR("Removing hooks is not possible on this platform");
}
// android only hooking functions, not used on apple
PosixScopedSuppressHooking::PosixScopedSuppressHooking()
ScopedSuppressHooking::ScopedSuppressHooking()
{
}
PosixScopedSuppressHooking::~PosixScopedSuppressHooking()
ScopedSuppressHooking::~ScopedSuppressHooking()
{
}
void PosixHookApply()
void LibraryHooks::Refresh()
{
}
void PosixHookReapply()
{
}
void PosixHookFunction(char const *, void *)
{
}
void *PosixGetFunction(void *handle, const char *name)
{
return dlsym(handle, name);
}
+117 -65
View File
@@ -24,43 +24,22 @@
#include <dlfcn.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <string>
#include "3rdparty/plthook/plthook.h"
#include "common/threading.h"
#include "hooks/hooks.h"
#include "os/os_specific.h"
#include "os/posix/posix_hook.h"
#include "strings/string_utils.h"
// depending on symbol resolution, dlopen could get called really early.
// until we've initialised, just skip any fancy stuff
static uint32_t hookInited = 0;
#define HOOK_MAGIC_NUMBER 0xAAF00F00
void PosixHookInit()
{
hookInited = HOOK_MAGIC_NUMBER;
}
bool PosixHookDetect(const char *identifier)
{
return dlsym(RTLD_DEFAULT, identifier) != NULL;
}
// need to lock around use of realdlopen and libraryHooks
Threading::CriticalSection libLock;
static std::map<std::string, dlopenCallback> libraryHooks;
void PosixHookLibrary(const char *name, dlopenCallback cb)
{
if(cb == NULL)
return;
SCOPED_LOCK(libLock);
libraryHooks[name] = cb;
}
static std::map<std::string, std::vector<FunctionLoadCallback>> libraryCallbacks;
static std::vector<std::string> libraryHooks;
static std::vector<FunctionHook> functionHooks;
void *intercept_dlopen(const char *filename, int flag, void *ret);
void plthook_lib(void *handle);
typedef void *(*DLOPENPROC)(const char *, int);
@@ -68,7 +47,7 @@ DLOPENPROC realdlopen = NULL;
__attribute__((visibility("default"))) void *dlopen(const char *filename, int flag)
{
if(hookInited != HOOK_MAGIC_NUMBER)
if(!realdlopen)
{
DLOPENPROC passthru = (DLOPENPROC)dlsym(RTLD_NEXT, "dlopen");
@@ -80,28 +59,12 @@ __attribute__((visibility("default"))) void *dlopen(const char *filename, int fl
return ret;
}
SCOPED_LOCK(libLock);
if(realdlopen == NULL)
realdlopen = (DLOPENPROC)dlsym(RTLD_NEXT, "dlopen");
void *ret = realdlopen(filename, flag);
if(filename && ret)
{
if(flag & RTLD_DEEPBIND)
plthook_lib(ret);
for(auto it = libraryHooks.begin(); it != libraryHooks.end(); ++it)
{
if(strstr(filename, it->first.c_str()))
{
RDCDEBUG("Redirecting dlopen to ourselves for %s", filename);
it->second(ret);
ret = realdlopen("librenderdoc.so", flag);
}
}
SCOPED_LOCK(libLock);
ret = intercept_dlopen(filename, flag, ret);
}
return ret;
@@ -120,28 +83,117 @@ void plthook_lib(void *handle)
plthook_close(plthook);
}
void *intercept_dlopen(const char *filename, int flag, void *ret)
{
if(flag & RTLD_DEEPBIND)
plthook_lib(ret);
std::string base = basename(filename);
for(auto it = libraryHooks.begin(); it != libraryHooks.end(); ++it)
{
const std::string &libName = *it;
if(*it == base)
{
RDCDEBUG("Redirecting dlopen to ourselves for %s", filename);
for(FunctionHook &hook : functionHooks)
{
if(hook.orig && *hook.orig == NULL)
*hook.orig = dlsym(ret, hook.function.c_str());
}
for(FunctionLoadCallback cb : libraryCallbacks[libName])
if(cb)
cb(ret);
// don't call the callbacks again
libraryCallbacks[libName].clear();
ret = realdlopen("librenderdoc.so", flag);
break;
}
}
return ret;
}
void LibraryHooks::BeginHookRegistration()
{
realdlopen = (DLOPENPROC)dlsym(RTLD_NEXT, "dlopen");
}
bool LibraryHooks::Detect(const char *identifier)
{
return dlsym(RTLD_DEFAULT, identifier) != NULL;
}
void LibraryHooks::RemoveHooks()
{
RDCERR("Removing hooks is not possible on this platform");
}
void LibraryHooks::EndHookRegistration()
{
// iterate over the libraries and see which ones are already loaded, process function hooks for
// them and call callbacks.
for(auto it = libraryHooks.begin(); it != libraryHooks.end(); ++it)
{
std::string libName = *it;
void *handle = realdlopen(libName.c_str(), RTLD_NOW | RTLD_NOLOAD | RTLD_GLOBAL);
if(handle)
{
for(FunctionHook &hook : functionHooks)
{
if(hook.orig && *hook.orig == NULL)
*hook.orig = dlsym(handle, hook.function.c_str());
}
for(FunctionLoadCallback cb : libraryCallbacks[libName])
if(cb)
cb(handle);
// don't call callbacks again if the library is dlopen'd again
libraryCallbacks[libName].clear();
}
}
}
void LibraryHooks::Refresh()
{
// don't need to refresh on linux
}
void LibraryHooks::RegisterFunctionHook(const char *libraryName, const FunctionHook &hook)
{
// we don't use the library name
(void)libraryName;
SCOPED_LOCK(libLock);
functionHooks.push_back(hook);
}
void LibraryHooks::RegisterLibraryHook(char const *name, FunctionLoadCallback cb)
{
if(cb == NULL)
return;
SCOPED_LOCK(libLock);
if(std::find(libraryHooks.begin(), libraryHooks.end(), name) == libraryHooks.end())
libraryHooks.push_back(name);
libraryCallbacks[name].push_back(cb);
}
void LibraryHooks::IgnoreLibrary(const char *libraryName)
{
}
// android only hooking functions, not used on linux
PosixScopedSuppressHooking::PosixScopedSuppressHooking()
ScopedSuppressHooking::ScopedSuppressHooking()
{
}
PosixScopedSuppressHooking::~PosixScopedSuppressHooking()
ScopedSuppressHooking::~ScopedSuppressHooking()
{
}
void PosixHookApply()
{
}
void PosixHookReapply()
{
}
void PosixHookFunction(char const *, void *)
{
}
void *PosixGetFunction(void *handle, const char *name)
{
return dlsym(handle, name);
}
-51
View File
@@ -1,51 +0,0 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2016-2018 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#pragma once
typedef void (*dlopenCallback)(void *realLib);
void PosixHookInit();
// if this name is dlopen'd, the real library will be passed
// to the callback and librenderdoc.so will be returned to user code
void PosixHookLibrary(const char *name, dlopenCallback cb);
void PosixHookFunction(const char *name, void *hook);
void *PosixGetFunction(void *handle, const char *name);
void PosixHookApply();
// this is needed on android, when we are PLT hooking to ensure hooks are applied as soon as
// possible.
void PosixHookReapply();
struct PosixScopedSuppressHooking
{
PosixScopedSuppressHooking();
~PosixScopedSuppressHooking();
};
bool PosixHookDetect(const char *identifier);
+2 -2
View File
@@ -34,7 +34,7 @@ void library_loaded()
string curfile;
FileIO::GetExecutableFilename(curfile);
if(HOOKS_IDENTIFY("renderdoc__replay__marker"))
if(LibraryHooks::Detect("renderdoc__replay__marker"))
{
RDCDEBUG("Not creating hooks - in replay app");
@@ -68,7 +68,7 @@ void library_loaded()
RDCLOG("Loading into %s", curfile.c_str());
LibraryHooks::GetInstance().CreateHooks();
LibraryHooks::RegisterHooks();
}
}
+53 -50
View File
@@ -77,54 +77,57 @@ public:
m_WSARefCount = 1;
}
bool CreateHooks(const char *libName)
void RegisterHooks()
{
RDCLOG("Registering Win32 system hooks");
// register libraries that we care about. We don't need a callback when they are loaded
LibraryHooks::RegisterLibraryHook("kernel32.dll", NULL);
LibraryHooks::RegisterLibraryHook("advapi32.dll", NULL);
LibraryHooks::RegisterLibraryHook("api-ms-win-core-processthreads-l1-1-0.dll", NULL);
LibraryHooks::RegisterLibraryHook("api-ms-win-core-processthreads-l1-1-1.dll", NULL);
LibraryHooks::RegisterLibraryHook("api-ms-win-core-processthreads-l1-1-2.dll", NULL);
LibraryHooks::RegisterLibraryHook("ws2_32.dll", NULL);
// we want to hook CreateProcess purely so that we can recursively insert our hooks (if we so
// wish)
CreateProcessA.Initialize("CreateProcessA", "kernel32.dll", CreateProcessA_hook);
CreateProcessW.Initialize("CreateProcessW", "kernel32.dll", CreateProcessW_hook);
CreateProcessA.Register("kernel32.dll", "CreateProcessA", CreateProcessA_hook);
CreateProcessW.Register("kernel32.dll", "CreateProcessW", CreateProcessW_hook);
CreateProcessAsUserA.Initialize("CreateProcessAsUserA", "advapi32.dll",
CreateProcessAsUserA_hook);
CreateProcessAsUserW.Initialize("CreateProcessAsUserW", "advapi32.dll",
CreateProcessAsUserW_hook);
CreateProcessAsUserA.Register("advapi32.dll", "CreateProcessAsUserA", CreateProcessAsUserA_hook);
CreateProcessAsUserW.Register("advapi32.dll", "CreateProcessAsUserW", CreateProcessAsUserW_hook);
CreateProcessWithLogonW.Initialize("CreateProcessWithLogonW", "advapi32.dll",
CreateProcessWithLogonW_hook);
CreateProcessWithLogonW.Register("advapi32.dll", "CreateProcessWithLogonW",
CreateProcessWithLogonW_hook);
// handle API set exports if they exist. These don't really exist so we don't have to worry
// about double hooking, and also they call into the 'real' implementation in kernelbase.dll
API110CreateProcessA.Initialize("CreateProcessA", "api-ms-win-core-processthreads-l1-1-0.dll",
API110CreateProcessA_hook);
API110CreateProcessW.Initialize("CreateProcessW", "api-ms-win-core-processthreads-l1-1-0.dll",
API110CreateProcessW_hook);
API110CreateProcessAsUserW.Initialize("CreateProcessAsUserW",
"api-ms-win-core-processthreads-l1-1-0.dll",
API110CreateProcessAsUserW_hook);
API110CreateProcessA.Register("api-ms-win-core-processthreads-l1-1-0.dll", "CreateProcessA",
API110CreateProcessA_hook);
API110CreateProcessW.Register("api-ms-win-core-processthreads-l1-1-0.dll", "CreateProcessW",
API110CreateProcessW_hook);
API110CreateProcessAsUserW.Register("api-ms-win-core-processthreads-l1-1-0.dll",
"CreateProcessAsUserW", API110CreateProcessAsUserW_hook);
API111CreateProcessA.Initialize("CreateProcessA", "api-ms-win-core-processthreads-l1-1-1.dll",
API111CreateProcessA_hook);
API111CreateProcessW.Initialize("CreateProcessW", "api-ms-win-core-processthreads-l1-1-1.dll",
API111CreateProcessW_hook);
API111CreateProcessAsUserW.Initialize("CreateProcessAsUserW",
"api-ms-win-core-processthreads-l1-1-0.dll",
API111CreateProcessAsUserW_hook);
API111CreateProcessA.Register("api-ms-win-core-processthreads-l1-1-1.dll", "CreateProcessA",
API111CreateProcessA_hook);
API111CreateProcessW.Register("api-ms-win-core-processthreads-l1-1-1.dll", "CreateProcessW",
API111CreateProcessW_hook);
API111CreateProcessAsUserW.Register("api-ms-win-core-processthreads-l1-1-0.dll",
"CreateProcessAsUserW", API111CreateProcessAsUserW_hook);
API112CreateProcessA.Initialize("CreateProcessA", "api-ms-win-core-processthreads-l1-1-2.dll",
API112CreateProcessA_hook);
API112CreateProcessW.Initialize("CreateProcessW", "api-ms-win-core-processthreads-l1-1-2.dll",
API112CreateProcessW_hook);
API112CreateProcessAsUserW.Initialize("CreateProcessAsUserW",
"api-ms-win-core-processthreads-l1-1-0.dll",
API112CreateProcessAsUserW_hook);
API112CreateProcessA.Register("api-ms-win-core-processthreads-l1-1-2.dll", "CreateProcessA",
API112CreateProcessA_hook);
API112CreateProcessW.Register("api-ms-win-core-processthreads-l1-1-2.dll", "CreateProcessW",
API112CreateProcessW_hook);
API112CreateProcessAsUserW.Register("api-ms-win-core-processthreads-l1-1-0.dll",
"CreateProcessAsUserW", API112CreateProcessAsUserW_hook);
WSAStartup.Initialize("WSAStartup", "ws2_32.dll", WSAStartup_hook);
WSACleanup.Initialize("WSACleanup", "ws2_32.dll", WSACleanup_hook);
WSAStartup.Register("ws2_32.dll", "WSAStartup", WSAStartup_hook);
WSACleanup.Register("ws2_32.dll", "WSACleanup", WSACleanup_hook);
m_RecurseSlot = Threading::AllocateTLSSlot();
Threading::SetTLSValue(m_RecurseSlot, NULL);
return true;
}
private:
@@ -144,27 +147,27 @@ private:
return true;
}
void EndRecurse() { Threading::SetTLSValue(m_RecurseSlot, NULL); }
Hook<PFN_CREATE_PROCESS_A> CreateProcessA;
Hook<PFN_CREATE_PROCESS_W> CreateProcessW;
HookedFunction<PFN_CREATE_PROCESS_A> CreateProcessA;
HookedFunction<PFN_CREATE_PROCESS_W> CreateProcessW;
Hook<PFN_CREATE_PROCESS_A> API110CreateProcessA;
Hook<PFN_CREATE_PROCESS_W> API110CreateProcessW;
Hook<PFN_CREATE_PROCESS_A> API111CreateProcessA;
Hook<PFN_CREATE_PROCESS_W> API111CreateProcessW;
Hook<PFN_CREATE_PROCESS_A> API112CreateProcessA;
Hook<PFN_CREATE_PROCESS_W> API112CreateProcessW;
HookedFunction<PFN_CREATE_PROCESS_A> API110CreateProcessA;
HookedFunction<PFN_CREATE_PROCESS_W> API110CreateProcessW;
HookedFunction<PFN_CREATE_PROCESS_A> API111CreateProcessA;
HookedFunction<PFN_CREATE_PROCESS_W> API111CreateProcessW;
HookedFunction<PFN_CREATE_PROCESS_A> API112CreateProcessA;
HookedFunction<PFN_CREATE_PROCESS_W> API112CreateProcessW;
Hook<PFN_CREATE_PROCESS_AS_USER_A> CreateProcessAsUserA;
Hook<PFN_CREATE_PROCESS_AS_USER_W> CreateProcessAsUserW;
HookedFunction<PFN_CREATE_PROCESS_AS_USER_A> CreateProcessAsUserA;
HookedFunction<PFN_CREATE_PROCESS_AS_USER_W> CreateProcessAsUserW;
Hook<PFN_CREATE_PROCESS_AS_USER_W> API110CreateProcessAsUserW;
Hook<PFN_CREATE_PROCESS_AS_USER_W> API111CreateProcessAsUserW;
Hook<PFN_CREATE_PROCESS_AS_USER_W> API112CreateProcessAsUserW;
HookedFunction<PFN_CREATE_PROCESS_AS_USER_W> API110CreateProcessAsUserW;
HookedFunction<PFN_CREATE_PROCESS_AS_USER_W> API111CreateProcessAsUserW;
HookedFunction<PFN_CREATE_PROCESS_AS_USER_W> API112CreateProcessAsUserW;
Hook<PFN_CREATE_PROCESS_WITH_LOGON_W> CreateProcessWithLogonW;
HookedFunction<PFN_CREATE_PROCESS_WITH_LOGON_W> CreateProcessWithLogonW;
Hook<PFN_WSASTARTUP> WSAStartup;
Hook<PFN_WSACLEANUP> WSACleanup;
HookedFunction<PFN_WSASTARTUP> WSAStartup;
HookedFunction<PFN_WSACLEANUP> WSACleanup;
static int WSAAPI WSAStartup_hook(WORD wVersionRequested, LPWSADATA lpWSAData)
{
+151 -88
View File
@@ -30,8 +30,10 @@
#include <algorithm>
#include <functional>
#include <map>
#include <set>
#include <vector>
#include "common/threading.h"
#include "hooks/hooks.h"
#include "os/os_specific.h"
#include "strings/string_utils.h"
@@ -44,74 +46,58 @@ using std::map;
map<void **, void *> s_InstalledHooks;
Threading::CriticalSection installedLock;
struct FunctionHook
bool ApplyHook(FunctionHook &hook, void **IATentry, bool &already)
{
FunctionHook(const char *f, void **o, void *d)
: function(f), origptr(o), hookptr(d), excludeModule(NULL)
DWORD oldProtection = PAGE_EXECUTE;
if(*IATentry == hook.hook)
{
}
bool operator<(const FunctionHook &h) { return function < h.function; }
bool ApplyHook(void **IATentry, bool &already)
{
DWORD oldProtection = PAGE_EXECUTE;
if(*IATentry == hookptr)
{
already = true;
return true;
}
#if ENABLED(VERBOSE_DEBUG_HOOK)
RDCDEBUG("Patching IAT for %s: %p to %p", function.c_str(), IATentry, hookptr);
#endif
{
SCOPED_LOCK(installedLock);
if(s_InstalledHooks.find(IATentry) == s_InstalledHooks.end())
s_InstalledHooks[IATentry] = *IATentry;
}
BOOL success = TRUE;
success = VirtualProtect(IATentry, sizeof(void *), PAGE_READWRITE, &oldProtection);
if(!success)
{
RDCERR("Failed to make IAT entry writeable 0x%p", IATentry);
return false;
}
if(origptr && *origptr == NULL)
*origptr = *IATentry;
*IATentry = hookptr;
success = VirtualProtect(IATentry, sizeof(void *), oldProtection, &oldProtection);
if(!success)
{
RDCERR("Failed to restore IAT entry protection 0x%p", IATentry);
return false;
}
already = true;
return true;
}
string function;
void **origptr;
void *hookptr;
HMODULE excludeModule;
};
#if ENABLED(VERBOSE_DEBUG_HOOK)
RDCDEBUG("Patching IAT for %s: %p to %p", function.c_str(), IATentry, hookptr);
#endif
{
SCOPED_LOCK(installedLock);
if(s_InstalledHooks.find(IATentry) == s_InstalledHooks.end())
s_InstalledHooks[IATentry] = *IATentry;
}
BOOL success = TRUE;
success = VirtualProtect(IATentry, sizeof(void *), PAGE_READWRITE, &oldProtection);
if(!success)
{
RDCERR("Failed to make IAT entry writeable 0x%p", IATentry);
return false;
}
*IATentry = hook.hook;
success = VirtualProtect(IATentry, sizeof(void *), oldProtection, &oldProtection);
if(!success)
{
RDCERR("Failed to restore IAT entry protection 0x%p", IATentry);
return false;
}
return true;
}
struct DllHookset
{
DllHookset() : module(NULL), OrdinalBase(0) {}
HMODULE module;
HMODULE module = NULL;
bool hooksfetched = false;
// if we have multiple copies of the dll loaded (unlikely), the other module handles will be
// stored here
vector<HMODULE> altmodules;
vector<FunctionHook> FunctionHooks;
DWORD OrdinalBase;
DWORD OrdinalBase = 0;
vector<string> OrdinalNames;
std::vector<FunctionLoadCallback> Callbacks;
void FetchOrdinalNames()
{
@@ -172,8 +158,12 @@ struct CachedHookData
Threading::CriticalSection lock;
char lowername[512];
std::set<std::string> ignores;
bool missedOrdinals;
volatile int32_t posthooking = 0;
void ApplyHooks(const char *modName, HMODULE module)
{
{
@@ -210,6 +200,18 @@ struct CachedHookData
if(it->second.module == NULL)
{
it->second.module = module;
it->second.hooksfetched = true;
// fetch all function hooks here, since we want to fill out the original function pointer
// even in case nothing imports from that function (which means it would not get filled
// out through FunctionHook::ApplyHook)
for(FunctionHook &hook : it->second.FunctionHooks)
{
if(hook.orig && *hook.orig == NULL)
*hook.orig = GetProcAddress(module, hook.function.c_str());
}
it->second.FetchOrdinalNames();
}
else if(it->second.module != module)
@@ -264,6 +266,9 @@ struct CachedHookData
strstr(lowername, "nvopencl") == lowername || strstr(lowername, "nvapi") == lowername)
return;
if(ignores.find(lowername) != ignores.end())
return;
byte *baseAddress = (byte *)module;
// the module could have been unloaded after our toolhelp snapshot, especially if we spent a
@@ -375,13 +380,13 @@ struct CachedHookData
importName, hook_find());
if(found != hookset->FunctionHooks.end() &&
!strcmp(found->function.c_str(), importName) && found->excludeModule != module)
!strcmp(found->function.c_str(), importName) && ownmodule != module)
{
bool already = false;
bool applied;
{
SCOPED_LOCK(lock);
applied = found->ApplyHook(IATentry, already);
applied = ApplyHook(*found, IATentry, already);
}
// if we failed, or if it's already set and we're not doing a missedOrdinals
@@ -438,13 +443,13 @@ struct CachedHookData
hookset->FunctionHooks.end(), importName, hook_find());
if(found != hookset->FunctionHooks.end() &&
!strcmp(found->function.c_str(), importName) && found->excludeModule != module)
!strcmp(found->function.c_str(), importName) && ownmodule != module)
{
bool already = false;
bool applied;
{
SCOPED_LOCK(lock);
applied = found->ApplyHook(IATentry, already);
applied = ApplyHook(*found, IATentry, already);
}
// if we failed, or if it's already set and we're not doing a missedOrdinals
@@ -550,6 +555,42 @@ static void HookAllModules()
{
ForAllModules(
[](const MODULEENTRY32 &me32) { s_HookData->ApplyHooks(me32.szModule, me32.hModule); });
// check if we're already in this section of code, and if so don't go in again.
int32_t prev = Atomic::CmpExch32(&s_HookData->posthooking, 0, 1);
if(prev != 0)
return;
// for all loaded modules, call callbacks now
for(auto it = s_HookData->DllHooks.begin(); it != s_HookData->DllHooks.end(); ++it)
{
if(it->second.module == NULL)
continue;
if(!it->second.hooksfetched)
{
it->second.hooksfetched = true;
// fetch all function hooks here, if we didn't above (perhaps because this library was
// late-loaded)
for(FunctionHook &hook : it->second.FunctionHooks)
{
if(hook.orig && *hook.orig == NULL)
*hook.orig = GetProcAddress(it->second.module, hook.function.c_str());
}
}
std::vector<FunctionLoadCallback> callbacks;
// don't call callbacks next time
callbacks.swap(it->second.Callbacks);
for(FunctionLoadCallback cb : callbacks)
if(cb)
cb(it->second.module);
}
Atomic::CmpExch32(&s_HookData->posthooking, 1, 0);
}
static bool IsAPISet(const wchar_t *filename)
@@ -724,8 +765,7 @@ FARPROC WINAPI Hooked_GetProcAddress(HMODULE mod, LPCSTR func)
std::lower_bound(it->second.FunctionHooks.begin(), it->second.FunctionHooks.end(), search);
if(found != it->second.FunctionHooks.end() && !(search < *found))
{
if(found->origptr && *found->origptr == NULL)
*found->origptr = (void *)GetProcAddress(mod, func);
FARPROC realfunc = GetProcAddress(mod, func);
#if ENABLED(VERBOSE_DEBUG_HOOK)
RDCDEBUG("Found hooked function, returning hook pointer %p", found->hookptr);
@@ -733,10 +773,10 @@ FARPROC WINAPI Hooked_GetProcAddress(HMODULE mod, LPCSTR func)
SetLastError(S_OK);
if(found->origptr && *found->origptr == NULL)
if(realfunc == NULL)
return NULL;
return (FARPROC)found->hookptr;
return (FARPROC)found->hook;
}
}
}
@@ -750,7 +790,37 @@ FARPROC WINAPI Hooked_GetProcAddress(HMODULE mod, LPCSTR func)
return GetProcAddress(mod, func);
}
void Win32_IAT_BeginHooks()
void LibraryHooks::RegisterFunctionHook(const char *libraryName, const FunctionHook &hook)
{
if(!_stricmp(libraryName, "kernel32.dll"))
{
if(hook.function == "LoadLibraryA" || hook.function == "LoadLibraryW" ||
hook.function == "LoadLibraryExA" || hook.function == "LoadLibraryExW" ||
hook.function == "GetProcAddress")
{
RDCERR("Cannot hook LoadLibrary* or GetProcAddress, as these are hooked internally");
return;
}
}
s_HookData->DllHooks[strlower(string(libraryName))].FunctionHooks.push_back(hook);
}
void LibraryHooks::RegisterLibraryHook(const char *libraryName, FunctionLoadCallback loadedCallback)
{
s_HookData->DllHooks[strlower(string(libraryName))].Callbacks.push_back(loadedCallback);
}
void LibraryHooks::IgnoreLibrary(const char *libraryName)
{
std::string lowername = libraryName;
for(size_t i = 0; i < lowername.size(); i++)
lowername[i] = (char)tolower(lowername[i]);
s_HookData->ignores.insert(lowername);
}
void LibraryHooks::BeginHookRegistration()
{
s_HookData = new CachedHookData;
RDCASSERT(s_HookData->DllHooks.empty());
@@ -785,15 +855,11 @@ void Win32_IAT_BeginHooks()
GetModuleHandleEx(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCTSTR)&s_HookData, &s_HookData->ownmodule);
for(auto it = s_HookData->DllHooks.begin(); it != s_HookData->DllHooks.end(); ++it)
for(size_t i = 0; i < it->second.FunctionHooks.size(); i++)
it->second.FunctionHooks[i].excludeModule = s_HookData->ownmodule;
}
// hook all functions for currently loaded modules.
// some of these hooks (as above) will hook LoadLibrary/GetProcAddress, to protect
void Win32_IAT_EndHooks()
void LibraryHooks::EndHookRegistration()
{
for(auto it = s_HookData->DllHooks.begin(); it != s_HookData->DllHooks.end(); ++it)
std::sort(it->second.FunctionHooks.begin(), it->second.FunctionHooks.end());
@@ -818,7 +884,12 @@ void Win32_IAT_EndHooks()
}
}
void Win32_IAT_RemoveHooks()
void LibraryHooks::Refresh()
{
// don't need to refresh on windows
}
void LibraryHooks::RemoveHooks()
{
for(auto it = s_InstalledHooks.begin(); it != s_InstalledHooks.end(); ++it)
{
@@ -845,24 +916,7 @@ void Win32_IAT_RemoveHooks()
}
}
void Win32_IAT_Hook(void **orig_function_ptr, const char *module_name, const char *function,
void *destination_function_ptr)
{
if(!_stricmp(module_name, "kernel32.dll"))
{
if(!strcmp(function, "LoadLibraryA") || !strcmp(function, "LoadLibraryW") ||
!strcmp(function, "LoadLibraryExA") || !strcmp(function, "LoadLibraryExW") ||
!strcmp(function, "GetProcAddress"))
{
RDCERR("Cannot hook LoadLibrary* or GetProcAddress, as these are hooked internally");
return;
}
}
s_HookData->DllHooks[strlower(string(module_name))].FunctionHooks.push_back(
FunctionHook(function, orig_function_ptr, destination_function_ptr));
}
bool Win32_HookDetect(const char *identifier)
bool LibraryHooks::Detect(const char *identifier)
{
bool ret = false;
ForAllModules([&ret, identifier](const MODULEENTRY32 &me32) {
@@ -870,4 +924,13 @@ bool Win32_HookDetect(const char *identifier)
ret = true;
});
return ret;
}
// android only hooking functions, not used on win32
ScopedSuppressHooking::ScopedSuppressHooking()
{
}
ScopedSuppressHooking::~ScopedSuppressHooking()
{
}
-34
View File
@@ -1,34 +0,0 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2015-2018 Baldur Karlsson
* Copyright (c) 2014 Crytek
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#pragma once
void Win32_IAT_Hook(void **orig_function_ptr, const char *module_name, const char *function,
void *destination_function_ptr);
void Win32_IAT_BeginHooks();
void Win32_IAT_EndHooks();
void Win32_IAT_RemoveHooks();
bool Win32_HookDetect(const char *identifier);
+2 -2
View File
@@ -49,7 +49,7 @@ static BOOL add_hooks()
}
// search for an exported symbol with this name, typically renderdoc__replay__marker
if(HOOKS_IDENTIFY(STRINGIZE(RDOC_DLL_FILE) "__replay__marker"))
if(LibraryHooks::Detect(STRINGIZE(RDOC_DLL_FILE) "__replay__marker"))
{
RDCDEBUG("Not creating hooks - in replay app");
@@ -64,7 +64,7 @@ static BOOL add_hooks()
RDCLOG("Loading into %ls", curFile);
LibraryHooks::GetInstance().CreateHooks();
LibraryHooks::RegisterHooks();
return TRUE;
}
-4
View File
@@ -195,9 +195,6 @@
<ClInclude Include="maths\quat.h" />
<ClInclude Include="maths\vec.h" />
<ClInclude Include="os\os_specific.h" />
<ClInclude Include="os\posix\posix_hook.h">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="os\posix\posix_network.h">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClInclude>
@@ -205,7 +202,6 @@
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="os\win32\dia2_stubs.h" />
<ClInclude Include="os\win32\win32_hook.h" />
<ClInclude Include="os\win32\win32_specific.h" />
<ClInclude Include="replay\replay_driver.h" />
<ClInclude Include="replay\replay_controller.h" />
-6
View File
@@ -198,9 +198,6 @@
<ClInclude Include="data\hlsl\debugcbuffers.h">
<Filter>Resources\hlsl</Filter>
</ClInclude>
<ClInclude Include="os\win32\win32_hook.h">
<Filter>OS\Win32</Filter>
</ClInclude>
<ClInclude Include="api\replay\basic_types.h">
<Filter>API\Replay</Filter>
</ClInclude>
@@ -270,9 +267,6 @@
<ClInclude Include="os\win32\win32_specific.h">
<Filter>OS\Win32</Filter>
</ClInclude>
<ClInclude Include="os\posix\posix_hook.h">
<Filter>OS\Posix</Filter>
</ClInclude>
<ClInclude Include="os\posix\posix_specific.h">
<Filter>OS\Posix</Filter>
</ClInclude>
+1 -1
View File
@@ -52,7 +52,7 @@ static void MaskOverlayBits(uint32_t And, uint32_t Or)
static void Shutdown()
{
RenderDoc::Inst().Shutdown();
LibraryHooks::GetInstance().RemoveHooks();
LibraryHooks::RemoveHooks();
}
static void UnloadCrashHandler()