Add x64 Windows support to DHooks (#2154)

* Add x64 Windows support

* undo changes of hook.cpp

* undo changes of hook.h

* undo changes of extension.cpp

* undo changes of listeners.cpp

* undo changes of signatures.cpp

* fix dhooks on x86

* Fix-up dhooks buildscript

---------

Co-authored-by: Kenzzer <kenzzer@users.noreply.github.com>
This commit is contained in:
Benoist 2024-09-11 01:26:30 +02:00 committed by GitHub
parent 4e6d66b721
commit 4e15a92984
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 283 additions and 100 deletions

View File

@ -4,8 +4,11 @@ import os
for cxx in builder.targets: for cxx in builder.targets:
binary = SM.ExtLibrary(builder, cxx, 'dhooks.ext') binary = SM.ExtLibrary(builder, cxx, 'dhooks.ext')
# Only x86 on Linux and Windows is supported. # mac isn't supported
if binary.compiler.target.platform == 'mac' or binary.compiler.target.arch != 'x86': if binary.compiler.target.platform == 'mac':
continue
# Presently only x86_64 on Windows is supported
if binary.compiler.target.arch == 'x86_64' and binary.compiler.target.platform != 'windows':
continue continue
binary.compiler.defines += [ binary.compiler.defines += [
@ -21,10 +24,8 @@ for cxx in builder.targets:
os.path.join(SM.mms_root, 'core', 'sourcehook'), os.path.join(SM.mms_root, 'core', 'sourcehook'),
os.path.join(builder.sourcePath, 'extensions', 'dhooks'), os.path.join(builder.sourcePath, 'extensions', 'dhooks'),
os.path.join(builder.sourcePath, 'public', 'jit'), os.path.join(builder.sourcePath, 'public', 'jit'),
os.path.join(builder.sourcePath, 'public', 'jit', 'x86'),
os.path.join(builder.sourcePath, 'sourcepawn', 'include'), os.path.join(builder.sourcePath, 'sourcepawn', 'include'),
os.path.join(builder.sourcePath, 'sourcepawn', 'vm'), os.path.join(builder.sourcePath, 'sourcepawn', 'vm'),
os.path.join(builder.sourcePath, 'sourcepawn', 'vm', 'x86'),
os.path.join(builder.sourcePath, 'extensions', 'dhooks', 'DynamicHooks'), os.path.join(builder.sourcePath, 'extensions', 'dhooks', 'DynamicHooks'),
] ]
@ -48,14 +49,20 @@ for cxx in builder.targets:
'libudis86/syn-intel.c', 'libudis86/syn-intel.c',
'libudis86/syn.c', 'libudis86/syn.c',
'libudis86/udis86.c', 'libudis86/udis86.c',
'../../sourcepawn/vm/x86/assembler-x86.cpp', # Dynamic Hooks
os.path.join('DynamicHooks', 'registers.cpp')
] ]
if binary.compiler.target.arch == 'x86':
binary.sources += ['../../sourcepawn/vm/x86/assembler-x86.cpp']
binary.compiler.cxxincludes += [
os.path.join(builder.sourcePath, 'public', 'jit', 'x86'),
os.path.join(builder.sourcePath, 'sourcepawn', 'vm', 'x86')
]
# DynamicHooks # DynamicHooks
binary.sources += [ binary.sources += [
os.path.join('DynamicHooks', 'hook.cpp'), os.path.join('DynamicHooks', 'hook.cpp'),
os.path.join('DynamicHooks', 'manager.cpp'), os.path.join('DynamicHooks', 'manager.cpp'),
os.path.join('DynamicHooks', 'registers.cpp'),
os.path.join('DynamicHooks', 'conventions', 'x86MsCdecl.cpp'), os.path.join('DynamicHooks', 'conventions', 'x86MsCdecl.cpp'),
os.path.join('DynamicHooks', 'conventions', 'x86MsStdcall.cpp'), os.path.join('DynamicHooks', 'conventions', 'x86MsStdcall.cpp'),
os.path.join('DynamicHooks', 'conventions', 'x86MsFastcall.cpp'), os.path.join('DynamicHooks', 'conventions', 'x86MsFastcall.cpp'),
@ -66,4 +73,10 @@ for cxx in builder.targets:
else: else:
binary.sources += [os.path.join('DynamicHooks', 'conventions', 'x86GccThiscall.cpp')] binary.sources += [os.path.join('DynamicHooks', 'conventions', 'x86GccThiscall.cpp')]
# Dynamic detour is only supported on x86
binary.compiler.defines += ['DHOOKS_DYNAMIC_DETOUR']
elif binary.compiler.target.arch == 'x86_64':
binary.compiler.defines += ['PLATFORM_X64']
SM.extensions += [builder.Add(binary)] SM.extensions += [builder.Add(binary)]

View File

@ -111,7 +111,7 @@ The data type you would like to get the size of.
@param <alignment>: @param <alignment>:
The alignment that should be used. The alignment that should be used.
*/ */
inline int GetDataTypeSize(DataTypeSized_t type, int iAlignment=4) inline size_t GetDataTypeSize(DataTypeSized_t type, int iAlignment=4)
{ {
switch(type.type) switch(type.type)
{ {
@ -257,9 +257,9 @@ public:
int size = GetArgStackSize() + GetArgRegisterSize(); int size = GetArgStackSize() + GetArgRegisterSize();
std::unique_ptr<uint8_t[]> pSavedCallArguments = std::make_unique<uint8_t[]>(size); std::unique_ptr<uint8_t[]> pSavedCallArguments = std::make_unique<uint8_t[]>(size);
size_t offset = 0; size_t offset = 0;
for (size_t i = 0; i < m_vecArgTypes.size(); i++) { for (unsigned int i = 0; i < m_vecArgTypes.size(); i++) {
DataTypeSized_t &type = m_vecArgTypes[i]; DataTypeSized_t &type = m_vecArgTypes[i];
memcpy((void *)((unsigned long)pSavedCallArguments.get() + offset), GetArgumentPtr(i, pRegisters), type.size); memcpy((void *)((uintptr_t)pSavedCallArguments.get() + offset), GetArgumentPtr(i, pRegisters), type.size);
offset += type.size; offset += type.size;
} }
m_pSavedCallArguments.push_back(std::move(pSavedCallArguments)); m_pSavedCallArguments.push_back(std::move(pSavedCallArguments));
@ -271,7 +271,7 @@ public:
size_t offset = 0; size_t offset = 0;
for (size_t i = 0; i < m_vecArgTypes.size(); i++) { for (size_t i = 0; i < m_vecArgTypes.size(); i++) {
DataTypeSized_t &type = m_vecArgTypes[i]; DataTypeSized_t &type = m_vecArgTypes[i];
memcpy(GetArgumentPtr(i, pRegisters), (void *)((unsigned long)pSavedCallArguments + offset), type.size); memcpy(GetArgumentPtr((unsigned int)i, pRegisters), (void *)((uintptr_t)pSavedCallArguments + offset), type.size);
offset += type.size; offset += type.size;
} }
m_pSavedCallArguments.pop_back(); m_pSavedCallArguments.pop_back();

View File

@ -116,7 +116,7 @@ CRegisters::CRegisters(std::vector<Register_t> registers)
// >> 64-bit General purpose registers // >> 64-bit General purpose registers
// ======================================================================== // ========================================================================
// 64-bit mode only // 64-bit mode only
/* #ifdef PLATFORM_X64
m_rax = CreateRegister(registers, RAX, 8); m_rax = CreateRegister(registers, RAX, 8);
m_rcx = CreateRegister(registers, RCX, 8); m_rcx = CreateRegister(registers, RCX, 8);
m_rdx = CreateRegister(registers, RDX, 8); m_rdx = CreateRegister(registers, RDX, 8);
@ -125,10 +125,7 @@ CRegisters::CRegisters(std::vector<Register_t> registers)
m_rbp = CreateRegister(registers, RBP, 8); m_rbp = CreateRegister(registers, RBP, 8);
m_rsi = CreateRegister(registers, RSI, 8); m_rsi = CreateRegister(registers, RSI, 8);
m_rdi = CreateRegister(registers, RDI, 8); m_rdi = CreateRegister(registers, RDI, 8);
*/
// 64-bit mode only
/*
m_r8 = CreateRegister(registers, R8, 8); m_r8 = CreateRegister(registers, R8, 8);
m_r9 = CreateRegister(registers, R9, 8); m_r9 = CreateRegister(registers, R9, 8);
m_r10 = CreateRegister(registers, R10, 8); m_r10 = CreateRegister(registers, R10, 8);
@ -137,7 +134,7 @@ CRegisters::CRegisters(std::vector<Register_t> registers)
m_r13 = CreateRegister(registers, R13, 8); m_r13 = CreateRegister(registers, R13, 8);
m_r14 = CreateRegister(registers, R14, 8); m_r14 = CreateRegister(registers, R14, 8);
m_r15 = CreateRegister(registers, R15, 8); m_r15 = CreateRegister(registers, R15, 8);
*/ #endif
// ======================================================================== // ========================================================================
// >> 64-bit MM (MMX) registers // >> 64-bit MM (MMX) registers
@ -165,7 +162,7 @@ CRegisters::CRegisters(std::vector<Register_t> registers)
m_xmm7 = CreateRegister(registers, XMM7, 16, 16); m_xmm7 = CreateRegister(registers, XMM7, 16, 16);
// 64-bit mode only // 64-bit mode only
/* #ifdef PLATFORM_X64
m_xmm8 = CreateRegister(registers, XMM8, 16); m_xmm8 = CreateRegister(registers, XMM8, 16);
m_xmm9 = CreateRegister(registers, XMM9, 16); m_xmm9 = CreateRegister(registers, XMM9, 16);
m_xmm10 = CreateRegister(registers, XMM10, 16); m_xmm10 = CreateRegister(registers, XMM10, 16);
@ -174,7 +171,7 @@ CRegisters::CRegisters(std::vector<Register_t> registers)
m_xmm13 = CreateRegister(registers, XMM13, 16); m_xmm13 = CreateRegister(registers, XMM13, 16);
m_xmm14 = CreateRegister(registers, XMM14, 16); m_xmm14 = CreateRegister(registers, XMM14, 16);
m_xmm15 = CreateRegister(registers, XMM15, 16); m_xmm15 = CreateRegister(registers, XMM15, 16);
*/ #endif
// ======================================================================== // ========================================================================
// >> 16-bit Segment registers // >> 16-bit Segment registers
@ -282,7 +279,7 @@ CRegisters::~CRegisters()
// >> 64-bit General purpose registers // >> 64-bit General purpose registers
// ======================================================================== // ========================================================================
// 64-bit mode only // 64-bit mode only
/* #ifdef PLATFORM_X64
DeleteRegister(m_rax); DeleteRegister(m_rax);
DeleteRegister(m_rcx); DeleteRegister(m_rcx);
DeleteRegister(m_rdx); DeleteRegister(m_rdx);
@ -291,10 +288,8 @@ CRegisters::~CRegisters()
DeleteRegister(m_rbp); DeleteRegister(m_rbp);
DeleteRegister(m_rsi); DeleteRegister(m_rsi);
DeleteRegister(m_rdi); DeleteRegister(m_rdi);
*/
// 64-bit mode only // 64-bit mode only
/*
DeleteRegister(m_r8); DeleteRegister(m_r8);
DeleteRegister(m_r9); DeleteRegister(m_r9);
DeleteRegister(m_r10); DeleteRegister(m_r10);
@ -303,7 +298,7 @@ CRegisters::~CRegisters()
DeleteRegister(m_r13); DeleteRegister(m_r13);
DeleteRegister(m_r14); DeleteRegister(m_r14);
DeleteRegister(m_r15); DeleteRegister(m_r15);
*/ #endif
// ======================================================================== // ========================================================================
// >> 64-bit MM (MMX) registers // >> 64-bit MM (MMX) registers
@ -330,7 +325,7 @@ CRegisters::~CRegisters()
DeleteRegister(m_xmm7); DeleteRegister(m_xmm7);
// 64-bit mode only // 64-bit mode only
/* #ifdef PLATFORM_X64
DeleteRegister(m_xmm8); DeleteRegister(m_xmm8);
DeleteRegister(m_xmm9); DeleteRegister(m_xmm9);
DeleteRegister(m_xmm10); DeleteRegister(m_xmm10);
@ -339,7 +334,7 @@ CRegisters::~CRegisters()
DeleteRegister(m_xmm13); DeleteRegister(m_xmm13);
DeleteRegister(m_xmm14); DeleteRegister(m_xmm14);
DeleteRegister(m_xmm15); DeleteRegister(m_xmm15);
*/ #endif
// ======================================================================== // ========================================================================
// >> 2-bit Segment registers // >> 2-bit Segment registers

View File

@ -132,8 +132,7 @@ enum Register_t
// ======================================================================== // ========================================================================
// >> 64-bit General purpose registers // >> 64-bit General purpose registers
// ======================================================================== // ========================================================================
// 64-bit mode only #ifdef PLATFORM_X64
/*
RAX, RAX,
RCX, RCX,
RDX, RDX,
@ -142,10 +141,7 @@ enum Register_t
RBP, RBP,
RSI, RSI,
RDI, RDI,
*/
// 64-bit mode only
/*
R8, R8,
R9, R9,
R10, R10,
@ -154,7 +150,7 @@ enum Register_t
R13, R13,
R14, R14,
R15, R15,
*/ #endif
// ======================================================================== // ========================================================================
// >> 64-bit MM (MMX) registers // >> 64-bit MM (MMX) registers
@ -181,7 +177,7 @@ enum Register_t
XMM7, XMM7,
// 64-bit mode only // 64-bit mode only
/* #ifdef PLATFORM_X64
XMM8, XMM8,
XMM9, XMM9,
XMM10, XMM10,
@ -190,7 +186,7 @@ enum Register_t
XMM13, XMM13,
XMM14, XMM14,
XMM15, XMM15,
*/ #endif
// ======================================================================== // ========================================================================
// >> 16-bit Segment registers // >> 16-bit Segment registers
@ -377,7 +373,7 @@ public:
// >> 64-bit General purpose registers // >> 64-bit General purpose registers
// ======================================================================== // ========================================================================
// 64-bit mode only // 64-bit mode only
/* #ifdef PLATFORM_X64
CRegister* m_rax; CRegister* m_rax;
CRegister* m_rcx; CRegister* m_rcx;
CRegister* m_rdx; CRegister* m_rdx;
@ -386,10 +382,7 @@ public:
CRegister* m_rbp; CRegister* m_rbp;
CRegister* m_rsi; CRegister* m_rsi;
CRegister* m_rdi; CRegister* m_rdi;
*/
// 64-bit mode only
/*
CRegister* m_r8; CRegister* m_r8;
CRegister* m_r9; CRegister* m_r9;
CRegister* m_r10; CRegister* m_r10;
@ -398,7 +391,7 @@ public:
CRegister* m_r13; CRegister* m_r13;
CRegister* m_r14; CRegister* m_r14;
CRegister* m_r15; CRegister* m_r15;
*/ #endif
// ======================================================================== // ========================================================================
// >> 64-bit MM (MMX) registers // >> 64-bit MM (MMX) registers
@ -425,7 +418,7 @@ public:
CRegister* m_xmm7; CRegister* m_xmm7;
// 64-bit mode only // 64-bit mode only
/* #ifdef PLATFORM_X64
CRegister* m_xmm8; CRegister* m_xmm8;
CRegister* m_xmm9; CRegister* m_xmm9;
CRegister* m_xmm10; CRegister* m_xmm10;
@ -434,7 +427,7 @@ public:
CRegister* m_xmm13; CRegister* m_xmm13;
CRegister* m_xmm14; CRegister* m_xmm14;
CRegister* m_xmm15; CRegister* m_xmm15;
*/ #endif
// ======================================================================== // ========================================================================
// >> 16-bit Segment registers // >> 16-bit Segment registers

View File

@ -63,15 +63,18 @@ DetourMap g_pPostDetours;
void UnhookFunction(HookType_t hookType, CHook *pDetour) void UnhookFunction(HookType_t hookType, CHook *pDetour)
{ {
#if defined( DHOOKS_DYNAMIC_DETOUR )
CHookManager *pDetourManager = GetHookManager(); CHookManager *pDetourManager = GetHookManager();
pDetour->RemoveCallback(hookType, (HookHandlerFn *)(void *)&HandleDetour); pDetour->RemoveCallback(hookType, (HookHandlerFn *)(void *)&HandleDetour);
// Only disable the detour if there are no more listeners. // Only disable the detour if there are no more listeners.
if (!pDetour->AreCallbacksRegistered()) if (!pDetour->AreCallbacksRegistered())
pDetourManager->UnhookFunction(pDetour->m_pFunc); pDetourManager->UnhookFunction(pDetour->m_pFunc);
#endif
} }
bool AddDetourPluginHook(HookType_t hookType, CHook *pDetour, HookSetup *setup, IPluginFunction *pCallback) bool AddDetourPluginHook(HookType_t hookType, CHook *pDetour, HookSetup *setup, IPluginFunction *pCallback)
{ {
#if defined( DHOOKS_DYNAMIC_DETOUR )
DetourMap *map; DetourMap *map;
if (hookType == HOOKTYPE_PRE) if (hookType == HOOKTYPE_PRE)
map = &g_pPreDetours; map = &g_pPreDetours;
@ -102,10 +105,14 @@ bool AddDetourPluginHook(HookType_t hookType, CHook *pDetour, HookSetup *setup,
wrappers->push_back(pWrapper); wrappers->push_back(pWrapper);
return true; return true;
#else
return false;
#endif
} }
bool RemoveDetourPluginHook(HookType_t hookType, CHook *pDetour, IPluginFunction *pCallback) bool RemoveDetourPluginHook(HookType_t hookType, CHook *pDetour, IPluginFunction *pCallback)
{ {
#if defined( DHOOKS_DYNAMIC_DETOUR )
DetourMap *map; DetourMap *map;
if (hookType == HOOKTYPE_PRE) if (hookType == HOOKTYPE_PRE)
map = &g_pPreDetours; map = &g_pPreDetours;
@ -139,10 +146,14 @@ bool RemoveDetourPluginHook(HookType_t hookType, CHook *pDetour, IPluginFunction
} }
return bRemoved; return bRemoved;
#else
return false;
#endif
} }
void RemoveAllCallbacksForContext(HookType_t hookType, DetourMap *map, IPluginContext *pContext) void RemoveAllCallbacksForContext(HookType_t hookType, DetourMap *map, IPluginContext *pContext)
{ {
#if defined( DHOOKS_DYNAMIC_DETOUR )
PluginCallbackList *wrappers; PluginCallbackList *wrappers;
CDynamicHooksSourcePawn *pWrapper; CDynamicHooksSourcePawn *pWrapper;
DetourMap::iterator it = map->iter(); DetourMap::iterator it = map->iter();
@ -170,16 +181,20 @@ void RemoveAllCallbacksForContext(HookType_t hookType, DetourMap *map, IPluginCo
it.erase(); it.erase();
} }
} }
#endif
} }
void RemoveAllCallbacksForContext(IPluginContext *pContext) void RemoveAllCallbacksForContext(IPluginContext *pContext)
{ {
#if defined( DHOOKS_DYNAMIC_DETOUR )
RemoveAllCallbacksForContext(HOOKTYPE_PRE, &g_pPreDetours, pContext); RemoveAllCallbacksForContext(HOOKTYPE_PRE, &g_pPreDetours, pContext);
RemoveAllCallbacksForContext(HOOKTYPE_POST, &g_pPostDetours, pContext); RemoveAllCallbacksForContext(HOOKTYPE_POST, &g_pPostDetours, pContext);
#endif
} }
void CleanupDetours(HookType_t hookType, DetourMap *map) void CleanupDetours(HookType_t hookType, DetourMap *map)
{ {
#if defined( DHOOKS_DYNAMIC_DETOUR )
PluginCallbackList *wrappers; PluginCallbackList *wrappers;
CDynamicHooksSourcePawn *pWrapper; CDynamicHooksSourcePawn *pWrapper;
DetourMap::iterator it = map->iter(); DetourMap::iterator it = map->iter();
@ -199,14 +214,18 @@ void CleanupDetours(HookType_t hookType, DetourMap *map)
UnhookFunction(hookType, it->key); UnhookFunction(hookType, it->key);
} }
map->clear(); map->clear();
#endif
} }
void CleanupDetours() void CleanupDetours()
{ {
#if defined( DHOOKS_DYNAMIC_DETOUR )
CleanupDetours(HOOKTYPE_PRE, &g_pPreDetours); CleanupDetours(HOOKTYPE_PRE, &g_pPreDetours);
CleanupDetours(HOOKTYPE_POST, &g_pPostDetours); CleanupDetours(HOOKTYPE_POST, &g_pPostDetours);
#endif
} }
#if defined( DHOOKS_DYNAMIC_DETOUR )
ICallingConvention *ConstructCallingConvention(HookSetup *setup) ICallingConvention *ConstructCallingConvention(HookSetup *setup)
{ {
// Convert function parameter types into DynamicHooks structures. // Convert function parameter types into DynamicHooks structures.
@ -249,6 +268,7 @@ ICallingConvention *ConstructCallingConvention(HookSetup *setup)
return pCallConv; return pCallConv;
} }
#endif
// Some arguments might be optimized to be passed in registers instead of the stack. // Some arguments might be optimized to be passed in registers instead of the stack.
bool UpdateRegisterArgumentSizes(CHook* pDetour, HookSetup *setup) bool UpdateRegisterArgumentSizes(CHook* pDetour, HookSetup *setup)

View File

@ -62,7 +62,9 @@ public:
CallingConvention callConv; CallingConvention callConv;
}; };
#if defined( DHOOKS_DYNAMIC_DETOUR )
ICallingConvention *ConstructCallingConvention(HookSetup *setup); ICallingConvention *ConstructCallingConvention(HookSetup *setup);
#endif
bool UpdateRegisterArgumentSizes(CHook* pDetour, HookSetup *setup); bool UpdateRegisterArgumentSizes(CHook* pDetour, HookSetup *setup);
ReturnAction_t HandleDetour(HookType_t hookType, CHook* pDetour); ReturnAction_t HandleDetour(HookType_t hookType, CHook* pDetour);
bool AddDetourPluginHook(HookType_t hookType, CHook *pDetour, HookSetup *setup, IPluginFunction *pCallback); bool AddDetourPluginHook(HookType_t hookType, CHook *pDetour, HookSetup *setup, IPluginFunction *pCallback);

View File

@ -338,6 +338,7 @@ cell_t Native_AddParam(IPluginContext *pContext, const cell_t *params)
// native bool:DHookEnableDetour(Handle:setup, bool:post, DHookCallback:callback); // native bool:DHookEnableDetour(Handle:setup, bool:post, DHookCallback:callback);
cell_t Native_EnableDetour(IPluginContext *pContext, const cell_t *params) cell_t Native_EnableDetour(IPluginContext *pContext, const cell_t *params)
{ {
#if defined( DHOOKS_DYNAMIC_DETOUR )
HookSetup *setup; HookSetup *setup;
if (!GetHandleIfValidOrError(g_HookSetupHandle, (void **)&setup, pContext, params[1])) if (!GetHandleIfValidOrError(g_HookSetupHandle, (void **)&setup, pContext, params[1]))
@ -377,11 +378,15 @@ cell_t Native_EnableDetour(IPluginContext *pContext, const cell_t *params)
// Add the plugin callback to the map. // Add the plugin callback to the map.
return AddDetourPluginHook(hookType, pDetour, setup, callback); return AddDetourPluginHook(hookType, pDetour, setup, callback);
#else
return pContext->ThrowNativeError("Dynamic detours are not enabled for this mod!");
#endif
} }
// native bool:DHookDisableDetour(Handle:setup, bool:post, DHookCallback:callback); // native bool:DHookDisableDetour(Handle:setup, bool:post, DHookCallback:callback);
cell_t Native_DisableDetour(IPluginContext *pContext, const cell_t *params) cell_t Native_DisableDetour(IPluginContext *pContext, const cell_t *params)
{ {
#if defined( DHOOKS_DYNAMIC_DETOUR )
HookSetup *setup; HookSetup *setup;
if (!GetHandleIfValidOrError(g_HookSetupHandle, (void **)&setup, pContext, params[1])) if (!GetHandleIfValidOrError(g_HookSetupHandle, (void **)&setup, pContext, params[1]))
@ -414,6 +419,9 @@ cell_t Native_DisableDetour(IPluginContext *pContext, const cell_t *params)
// Remove the callback from the hook. // Remove the callback from the hook.
return RemoveDetourPluginHook(hookType, pDetour, callback); return RemoveDetourPluginHook(hookType, pDetour, callback);
#else
return pContext->ThrowNativeError("Dynamic detours are not enabled for this mod!");
#endif
} }
cell_t HookEntityImpl(IPluginContext *pContext, const cell_t *params, uint32_t callbackIndex, uint32_t removalcbIndex) cell_t HookEntityImpl(IPluginContext *pContext, const cell_t *params, uint32_t callbackIndex, uint32_t removalcbIndex)

View File

@ -62,7 +62,11 @@ size_t GetStackParamOffset(HookParamsStruct *paramStruct, unsigned int index)
continue; continue;
} }
#endif #endif
#ifdef PLATFORM_X64
offset += 8;
#else
offset += paramStruct->dg->params[i].size; offset += paramStruct->dg->params[i].size;
#endif
} }
return offset; return offset;
} }
@ -77,8 +81,10 @@ size_t GetRegisterParamOffset(HookParamsStruct *paramStruct, unsigned int index)
for (int i = paramStruct->dg->params.size() - 1; i >= 0; i--) for (int i = paramStruct->dg->params.size() - 1; i >= 0; i--)
{ {
if (paramStruct->dg->params[i].custom_register == None) if (paramStruct->dg->params[i].custom_register == None)
{
stackSize += paramStruct->dg->params[i].size; stackSize += paramStruct->dg->params[i].size;
} }
}
size_t offset = stackSize; size_t offset = stackSize;
for (unsigned int i = 0; i < index; i++) for (unsigned int i = 0; i < index; i++)

View File

@ -200,8 +200,8 @@ SDKVector CallVFunction<SDKVector>(DHooksCallback *dg, HookParamsStruct *paramSt
{ {
size_t offset = GetParamOffset(paramStruct, i); size_t offset = GetParamOffset(paramStruct, i);
void *orgAddr = *(void **)((intptr_t)paramStruct->orgParams + offset); void *orgAddr = (void **)((intptr_t)paramStruct->orgParams + offset);
void *newAddr = *(void **)((intptr_t)paramStruct->newParams + offset); void *newAddr = (void **)((intptr_t)paramStruct->newParams + offset);
switch (dg->params.at(i).type) switch (dg->params.at(i).type)
{ {
@ -291,8 +291,8 @@ string_t CallVFunction<string_t>(DHooksCallback *dg, HookParamsStruct *paramStru
{ {
size_t offset = GetParamOffset(paramStruct, i); size_t offset = GetParamOffset(paramStruct, i);
void *orgAddr = *(void **)((intptr_t)paramStruct->orgParams + offset); void *orgAddr = (void **)((intptr_t)paramStruct->orgParams + offset);
void *newAddr = *(void **)((intptr_t)paramStruct->newParams + offset); void *newAddr = (void **)((intptr_t)paramStruct->newParams + offset);
switch (dg->params.at(i).type) switch (dg->params.at(i).type)
{ {

View File

@ -32,7 +32,11 @@
#include "vhook.h" #include "vhook.h"
#include "vfunc_call.h" #include "vfunc_call.h"
#include "util.h" #include "util.h"
#ifdef PLATFORM_X64
#include "sh_asm_x86_64.h"
#else
#include <macro-assembler-x86.h> #include <macro-assembler-x86.h>
#endif
SourceHook::IHookManagerAutoGen *g_pHookManager = NULL; SourceHook::IHookManagerAutoGen *g_pHookManager = NULL;
@ -47,9 +51,111 @@ using namespace sp;
#define OBJECT_OFFSET (sizeof(void *)*2) #define OBJECT_OFFSET (sizeof(void *)*2)
#endif #endif
#ifndef WIN32 #ifdef PLATFORM_X64
void *GenerateThunk(ReturnType type) using namespace SourceHook::Asm;
SourceHook::CPageAlloc GenBuffer::ms_Allocator(16);
void test_func(void* rcx, void* rdx, SDKVector* r8, bool r9)
{ {
//g_pSM->LogMessage(myself, "rcx(%p) - rdx(%p) - r8(%p) - r9(%p)", rcx, rdx, r8, r9);
}
SourceHook::Asm::x64JitWriter* GenerateThunk(HookSetup* hook)
{
auto masm = new x64JitWriter();
auto type = hook->returnType;
/*if (type == ReturnType_Vector)
{
masm->push(rcx);
masm->push(rdx);
masm->push(r8);
masm->push(r9);
masm->sub(rsp, 40);
masm->mov(rax, (uintptr_t)test_func);
masm->call(rax);
masm->add(rsp, 40);
masm->pop(r9);
masm->pop(r8);
masm->pop(rdx);
masm->pop(rcx);
}*/
// We're going to transform rbp into our stack
masm->push(rbp);
// Copy all the arguments into the stack
// 8 bytes per parameter + 8 bytes for potential return value
int32_t fakeStackSize = ke::Align((int32_t)hook->params.size() * 8 + 8, 16) + 8; // Add another +8 bytes to realign on 16 bytes, due to 'push rbp' earlier
int32_t parameterOffset = fakeStackSize + 8 /* push rbp */ + 8 /* return address */ + 32 /* shadow space */;
masm->sub(rsp, fakeStackSize);
masm->mov(rbp, rsp);
static x86_64_Reg arg_reg[] = { rcx, rdx, r8, r9 };
static x86_64_FloatReg arg_reg_float[] = { xmm0, xmm1, xmm2, xmm3 };
int stack_index = 0;
int fake_stack_index = 0;
int reg_index = 1; // Account |this| right away
if (type == ReturnType_Vector) { // Special return types occupy another register
masm->mov(rbp(8 * fake_stack_index), rdx); // Store return ptr at the bottom of the stack
reg_index++;
fake_stack_index++;
}
for (int i = 0; i < hook->params.size(); i++, fake_stack_index++) {
if (reg_index < 4) {
if (hook->params[i].type == HookParamType_Float && hook->params[i].flags == PASSFLAG_BYVAL) {
masm->movsd(rbp(8 * fake_stack_index), arg_reg_float[reg_index]);
} else {
masm->mov(rax, arg_reg[reg_index]);
masm->mov(rbp(8 * fake_stack_index), rax);
}
reg_index++;
} else {
masm->mov(rax, rbp(parameterOffset + 8 * stack_index));
masm->mov(rbp(8 * fake_stack_index), rax);
stack_index++;
}
}
//masm->mov(rbp(8 * 2), 0x7777777777777777);
//masm->mov(rbp(8 * 1), 0xDEADBEEFDEADBEEF);
// Setup 2nd parameter (our fake stack)
masm->mov(rdx, rbp);
if (type == ReturnType_Float)
{
masm->mov(rax, (uintptr_t)Callback_float);
}
else if (type == ReturnType_Vector)
{
masm->mov(rax, (uintptr_t)Callback_vector);
}
/*else if (type == ReturnType_String)
{
masm->mov(rax, (uintptr_t)Callback_stringt);
}*/
else
{
masm->mov(rax, (uintptr_t)Callback);
}
masm->sub(rsp, 40);
masm->call(rax);
masm->add(rsp, 40);
masm->add(rsp, fakeStackSize);
masm->pop(rbp);
masm->retn();
masm->SetRE();
return masm;
}
#elif !defined( WIN32 )
void *GenerateThunk(HookSetup* hook)
{
auto type = hook->returnType;
sp::MacroAssembler masm; sp::MacroAssembler masm;
static const size_t kStackNeeded = (2) * 4; // 2 args max static const size_t kStackNeeded = (2) * 4; // 2 args max
static const size_t kReserve = ke::Align(kStackNeeded + 8, 16) - 8; static const size_t kReserve = ke::Align(kStackNeeded + 8, 16) - 8;
@ -97,8 +203,9 @@ void *GenerateThunk(ReturnType type)
} }
#else #else
// HUGE THANKS TO BAILOPAN (dvander)! // HUGE THANKS TO BAILOPAN (dvander)!
void *GenerateThunk(ReturnType type) void *GenerateThunk(HookSetup* hook)
{ {
auto type = hook->returnType;
sp::MacroAssembler masm; sp::MacroAssembler masm;
static const size_t kStackNeeded = (3 + 1) * 4; // 3 args max, 1 locals max static const size_t kStackNeeded = (3 + 1) * 4; // 3 args max, 1 locals max
static const size_t kReserve = ke::Align(kStackNeeded + 8, 16) - 8; static const size_t kReserve = ke::Align(kStackNeeded + 8, 16) - 8;
@ -138,7 +245,7 @@ void *GenerateThunk(ReturnType type)
DHooksManager::DHooksManager(HookSetup *setup, void *iface, IPluginFunction *remove_callback, IPluginFunction *plugincb, bool post) DHooksManager::DHooksManager(HookSetup *setup, void *iface, IPluginFunction *remove_callback, IPluginFunction *plugincb, bool post)
{ {
this->callback = MakeHandler(setup->returnType); this->callback = MakeHandler(setup);
this->hookid = 0; this->hookid = 0;
this->remove_callback = remove_callback; this->remove_callback = remove_callback;
this->callback->offset = setup->offset; this->callback->offset = setup->offset;
@ -284,7 +391,7 @@ HookParamsStruct *GetParamStruct(DHooksCallback *dg, void **argStack, size_t arg
else //Offset result ptr else //Offset result ptr
{ {
params->orgParams = (void **)malloc(argStackSize-OBJECT_OFFSET); params->orgParams = (void **)malloc(argStackSize-OBJECT_OFFSET);
memcpy(params->orgParams, argStack+OBJECT_OFFSET, argStackSize-OBJECT_OFFSET); memcpy(params->orgParams, (void*)((uintptr_t)argStack + OBJECT_OFFSET), argStackSize - OBJECT_OFFSET);
} }
size_t paramsSize = GetParamsSize(dg); size_t paramsSize = GetParamsSize(dg);
@ -388,11 +495,14 @@ cell_t GetThisPtr(void *iface, ThisPointerType type)
return -1; return -1;
return gamehelpers->EntityToBCompatRef((CBaseEntity *)iface); return gamehelpers->EntityToBCompatRef((CBaseEntity *)iface);
} }
#ifdef PLATFORM_X64
return g_pSM->ToPseudoAddress(iface);
#else
return (cell_t)iface; return (cell_t)iface;
#endif
} }
#ifdef WIN32 #if defined( WIN32 ) && !defined( PLATFORM_X64 )
void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep) void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep)
#else #else
void *Callback(DHooksCallback *dg, void **argStack) void *Callback(DHooksCallback *dg, void **argStack)
@ -403,11 +513,12 @@ void *Callback(DHooksCallback *dg, void **argStack)
Handle_t rHndl; Handle_t rHndl;
Handle_t pHndl; Handle_t pHndl;
#ifdef WIN32 #if defined( WIN32 ) && !defined( PLATFORM_X64 )
*argsizep = GetStackArgsSize(dg); *argsizep = GetStackArgsSize(dg);
#else #else
size_t argsize = GetStackArgsSize(dg); size_t argsize = GetStackArgsSize(dg);
#endif #endif
//g_pSM->LogMessage(myself, "[DEFAULT]DHooksCallback(%p) argStack(%p) - argsize(%d)", dg, argStack, argsize);
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address) if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
{ {
@ -430,7 +541,7 @@ void *Callback(DHooksCallback *dg, void **argStack)
dg->plugin_callback->PushCell(rHndl); dg->plugin_callback->PushCell(rHndl);
} }
#ifdef WIN32 #if defined( WIN32 ) && !defined( PLATFORM_X64 )
if(*argsizep > 0) if(*argsizep > 0)
{ {
paramStruct = GetParamStruct(dg, argStack, *argsizep); paramStruct = GetParamStruct(dg, argStack, *argsizep);
@ -575,7 +686,7 @@ void *Callback(DHooksCallback *dg, void **argStack)
} }
return ret; return ret;
} }
#ifdef WIN32 #if defined( WIN32 ) && !defined( PLATFORM_X64 )
float Callback_float(DHooksCallback *dg, void **argStack, size_t *argsizep) float Callback_float(DHooksCallback *dg, void **argStack, size_t *argsizep)
#else #else
float Callback_float(DHooksCallback *dg, void **argStack) float Callback_float(DHooksCallback *dg, void **argStack)
@ -586,11 +697,12 @@ float Callback_float(DHooksCallback *dg, void **argStack)
Handle_t rHndl; Handle_t rHndl;
Handle_t pHndl; Handle_t pHndl;
#ifdef WIN32 #if defined( WIN32 ) && !defined( PLATFORM_X64 )
*argsizep = GetStackArgsSize(dg); *argsizep = GetStackArgsSize(dg);
#else #else
size_t argsize = GetStackArgsSize(dg); size_t argsize = GetStackArgsSize(dg);
#endif #endif
//g_pSM->LogMessage(myself, "[FLOAT]DHooksCallback(%p) argStack(%p) - argsize(%d)", dg, argStack, argsize);
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address) if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
{ {
@ -612,7 +724,7 @@ float Callback_float(DHooksCallback *dg, void **argStack)
} }
dg->plugin_callback->PushCell(rHndl); dg->plugin_callback->PushCell(rHndl);
#ifdef WIN32 #if defined( WIN32 ) && !defined( PLATFORM_X64 )
if(*argsizep > 0) if(*argsizep > 0)
{ {
paramStruct = GetParamStruct(dg, argStack, *argsizep); paramStruct = GetParamStruct(dg, argStack, *argsizep);
@ -729,24 +841,25 @@ float Callback_float(DHooksCallback *dg, void **argStack)
} }
return *(float *)ret; return *(float *)ret;
} }
#ifdef WIN32 #if defined( WIN32 ) && !defined( PLATFORM_X64 )
SDKVector *Callback_vector(DHooksCallback *dg, void **argStack, size_t *argsizep) SDKVector *Callback_vector(DHooksCallback *dg, void **argStack, size_t *argsizep)
#else #else
SDKVector *Callback_vector(DHooksCallback *dg, void **argStack) SDKVector *Callback_vector(DHooksCallback *dg, void **argStack)
#endif #endif
{ {
SDKVector *vec_result = (SDKVector *)argStack[0]; // Save the result SDKVector *vec_result = (SDKVector *)argStack[0];
HookReturnStruct *returnStruct = NULL; HookReturnStruct *returnStruct = NULL;
HookParamsStruct *paramStruct = NULL; HookParamsStruct *paramStruct = NULL;
Handle_t rHndl; Handle_t rHndl;
Handle_t pHndl; Handle_t pHndl;
#ifdef WIN32 #if defined( WIN32 ) && !defined( PLATFORM_X64 )
*argsizep = GetStackArgsSize(dg); *argsizep = GetStackArgsSize(dg);
#else #else
size_t argsize = GetStackArgsSize(dg); size_t argsize = GetStackArgsSize(dg);
#endif #endif
//g_pSM->LogMessage(myself, "[VECTOR]DHooksCallback(%p) argStack(%p) - argsize(%d) - params count %d", dg, argStack, argsize, dg->params.size());
if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address) if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address)
{ {
@ -768,7 +881,7 @@ SDKVector *Callback_vector(DHooksCallback *dg, void **argStack)
} }
dg->plugin_callback->PushCell(rHndl); dg->plugin_callback->PushCell(rHndl);
#ifdef WIN32 #if defined( WIN32 ) && !defined( PLATFORM_X64 )
if(*argsizep > 0) if(*argsizep > 0)
{ {
paramStruct = GetParamStruct(dg, argStack, *argsizep); paramStruct = GetParamStruct(dg, argStack, *argsizep);

View File

@ -39,6 +39,10 @@
#include <registers.h> #include <registers.h>
#include <vector> #include <vector>
#ifdef PLATFORM_X64
#include "sh_asm_x86_64.h"
#endif
enum CallingConvention enum CallingConvention
{ {
CallConv_CDECL, CallConv_CDECL,
@ -163,11 +167,20 @@ public:
class DHooksCallback : public SourceHook::ISHDelegate, public DHooksInfo class DHooksCallback : public SourceHook::ISHDelegate, public DHooksInfo
{ {
public: public:
DHooksCallback()
{
//g_pSM->LogMessage(myself, "DHooksCallback(%p)", this);
}
virtual bool IsEqual(ISHDelegate *pOtherDeleg){return false;}; virtual bool IsEqual(ISHDelegate *pOtherDeleg){return false;};
virtual void DeleteThis() virtual void DeleteThis()
{ {
*(void ***)this = this->oldvtable; *(void ***)this = this->oldvtable;
#ifdef PLATFORM_X64
delete callThunk;
#else
g_pSM->GetScriptingEngine()->FreePageMemory(this->newvtable[2]); g_pSM->GetScriptingEngine()->FreePageMemory(this->newvtable[2]);
#endif
delete this->newvtable; delete this->newvtable;
delete this; delete this;
}; };
@ -175,9 +188,12 @@ public:
public: public:
void **newvtable; void **newvtable;
void **oldvtable; void **oldvtable;
#ifdef PLATFORM_X64
SourceHook::Asm::x64JitWriter* callThunk;
#endif
}; };
#ifdef WIN32 #if defined( WIN32 ) && !defined( PLATFORM_X64 )
void *Callback(DHooksCallback *dg, void **stack, size_t *argsizep); void *Callback(DHooksCallback *dg, void **stack, size_t *argsizep);
float Callback_float(DHooksCallback *dg, void **stack, size_t *argsizep); float Callback_float(DHooksCallback *dg, void **stack, size_t *argsizep);
SDKVector *Callback_vector(DHooksCallback *dg, void **stack, size_t *argsizep); SDKVector *Callback_vector(DHooksCallback *dg, void **stack, size_t *argsizep);
@ -192,20 +208,6 @@ bool SetupHookManager(ISmmAPI *ismm);
void CleanupHooks(IPluginContext *pContext = NULL); void CleanupHooks(IPluginContext *pContext = NULL);
size_t GetParamTypeSize(HookParamType type); size_t GetParamTypeSize(HookParamType type);
SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type); SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type);
void *GenerateThunk(ReturnType type);
static DHooksCallback *MakeHandler(ReturnType type)
{
DHooksCallback *dg = new DHooksCallback();
dg->returnType = type;
dg->oldvtable = *(void ***)dg;
dg->newvtable = new void *[3];
dg->newvtable[0] = dg->oldvtable[0];
dg->newvtable[1] = dg->oldvtable[1];
dg->newvtable[2] = GenerateThunk(type);
*(void ***)dg = dg->newvtable;
return dg;
}
class HookParamsStruct class HookParamsStruct
{ {
@ -276,6 +278,37 @@ public:
HookMethod hookMethod; HookMethod hookMethod;
}; };
#ifdef PLATFORM_X64
SourceHook::Asm::x64JitWriter* GenerateThunk(HookSetup* type);
static DHooksCallback *MakeHandler(HookSetup* hook)
{
DHooksCallback *dg = new DHooksCallback();
dg->returnType = hook->returnType;
dg->oldvtable = *(void ***)dg;
dg->newvtable = new void *[3];
dg->newvtable[0] = dg->oldvtable[0];
dg->newvtable[1] = dg->oldvtable[1];
dg->callThunk = GenerateThunk(hook);
dg->newvtable[2] = dg->callThunk->GetData();
*(void ***)dg = dg->newvtable;
return dg;
}
#else
void *GenerateThunk(HookSetup* type);
static DHooksCallback *MakeHandler(HookSetup* hook)
{
DHooksCallback *dg = new DHooksCallback();
dg->returnType = hook->returnType;
dg->oldvtable = *(void ***)dg;
dg->newvtable = new void *[3];
dg->newvtable[0] = dg->oldvtable[0];
dg->newvtable[1] = dg->oldvtable[1];
dg->newvtable[2] = GenerateThunk(hook);
*(void ***)dg = dg->newvtable;
return dg;
}
#endif
class DHooksManager class DHooksManager
{ {
public: public: