mirror of
https://github.com/alliedmodders/sourcemod.git
synced 2025-12-09 03:18:33 +00:00
Remove CDetour
This commit is contained in:
parent
1c5183dd18
commit
1339f38008
@ -1,147 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id: detourhelpers.h 248 2008-08-27 00:56:22Z pred $
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
||||
#define _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
||||
|
||||
#if defined PLATFORM_POSIX
|
||||
#include <sys/mman.h>
|
||||
#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC
|
||||
#endif
|
||||
|
||||
#include <amtl/am-bits.h>
|
||||
#include <jit/x86/x86_macros.h>
|
||||
#include <amtl/os/am-system-errors.h>
|
||||
#include <cstdio>
|
||||
|
||||
struct patch_t
|
||||
{
|
||||
patch_t()
|
||||
{
|
||||
patch[0] = 0;
|
||||
bytes = 0;
|
||||
}
|
||||
unsigned char patch[20];
|
||||
size_t bytes;
|
||||
};
|
||||
|
||||
inline void ProtectMemory(void *addr, int length, int prot)
|
||||
{
|
||||
char error[256];
|
||||
#if defined PLATFORM_POSIX
|
||||
long pageSize = sysconf(_SC_PAGESIZE);
|
||||
void *startPage = ke::AlignedBase(addr, pageSize);
|
||||
void *endPage = ke::AlignedBase((void *)((intptr_t)addr + length), pageSize);
|
||||
if (mprotect(startPage, ((intptr_t)endPage - (intptr_t)startPage) + pageSize, prot) == -1) {
|
||||
ke::FormatSystemError(error, sizeof(error));
|
||||
fprintf(stderr, "mprotect: %s\n", error);
|
||||
}
|
||||
#elif defined PLATFORM_WINDOWS
|
||||
DWORD old_prot;
|
||||
if (!VirtualProtect(addr, length, prot, &old_prot)) {
|
||||
ke::FormatSystemError(error, sizeof(error));
|
||||
fprintf(stderr, "VirtualProtect: %s\n", error);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void SetMemPatchable(void *address, size_t size)
|
||||
{
|
||||
ProtectMemory(address, (int)size, PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
|
||||
inline void PatchRelJump32(unsigned char *target, void *callback)
|
||||
{
|
||||
SetMemPatchable(target, 5);
|
||||
|
||||
// jmp <32-bit displacement>
|
||||
target[0] = IA32_JMP_IMM32;
|
||||
*(int32_t *)(&target[1]) = int32_t((unsigned char *)callback - (target + 5));
|
||||
}
|
||||
|
||||
inline void PatchAbsJump64(unsigned char *target, void *callback)
|
||||
{
|
||||
int i = 0;
|
||||
SetMemPatchable(target, 14);
|
||||
|
||||
// push <lower 32-bits> ; allocates 64-bit stack space on x64
|
||||
// mov [rsp+4], <upper 32-bits> ; unnecessary if upper bits are 0
|
||||
// ret ; jump to address on stack
|
||||
target[i++] = IA32_PUSH_IMM32;
|
||||
*(int32_t *)(&target[i]) = int32_t(int64_t(callback));
|
||||
i += 4;
|
||||
if ((int64_t(callback) >> 32) != 0)
|
||||
{
|
||||
target[i++] = IA32_MOV_RM_IMM32;
|
||||
target[i++] = ia32_modrm(MOD_DISP8, 0, kREG_SIB);
|
||||
target[i++] = ia32_sib(NOSCALE, kREG_NOIDX, kREG_ESP);
|
||||
target[i++] = 0x04;
|
||||
*(int32_t *)(&target[i]) = (int64_t(callback) >> 32);
|
||||
i += 4;
|
||||
}
|
||||
target[i] = IA32_RET;
|
||||
}
|
||||
|
||||
inline void DoGatePatch(unsigned char *target, void *callback)
|
||||
{
|
||||
#if defined(_WIN64) || defined(__x86_64__)
|
||||
int64_t diff = int64_t(callback) - (int64_t(target) + 5);
|
||||
int32_t upperBits = (diff >> 32);
|
||||
if (upperBits == 0 || upperBits == -1)
|
||||
PatchRelJump32(target, callback);
|
||||
else
|
||||
PatchAbsJump64(target, callback);
|
||||
#else
|
||||
PatchRelJump32(target, callback);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void ApplyPatch(void *address, int offset, const patch_t *patch, patch_t *restore)
|
||||
{
|
||||
unsigned char *addr = (unsigned char *)address + offset;
|
||||
SetMemPatchable(addr, patch->bytes);
|
||||
|
||||
if (restore)
|
||||
{
|
||||
for (size_t i=0; i<patch->bytes; i++)
|
||||
{
|
||||
restore->patch[i] = addr[i];
|
||||
}
|
||||
restore->bytes = patch->bytes;
|
||||
}
|
||||
|
||||
for (size_t i=0; i<patch->bytes; i++)
|
||||
{
|
||||
addr[i] = patch->patch[i];
|
||||
}
|
||||
}
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
||||
@ -1,112 +0,0 @@
|
||||
#include "detours.h"
|
||||
#include <cstdio>
|
||||
|
||||
ISourcePawnEngine *CDetourManager::spengine = NULL;
|
||||
IGameConfig *CDetourManager::gameconf = NULL;
|
||||
|
||||
void CDetourManager::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
|
||||
{
|
||||
CDetourManager::spengine = spengine;
|
||||
CDetourManager::gameconf = gameconf;
|
||||
}
|
||||
|
||||
CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, const char *signame)
|
||||
{
|
||||
void* pAddress;
|
||||
if (!gameconf->GetMemSig(signame, &pAddress))
|
||||
{
|
||||
g_pSM->LogError(myself, "Signature for %s not found in gamedata", signame);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!pAddress)
|
||||
{
|
||||
g_pSM->LogError(myself, "Sigscan for %s failed", signame);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return CreateDetour(callbackfunction, trampoline, pAddress);
|
||||
}
|
||||
|
||||
CDetour *CDetourManager::CreateDetour(void *callbackFunction, void **trampoline, void *pAddress)
|
||||
{
|
||||
CDetour* detour = new CDetour(callbackFunction, trampoline, pAddress);
|
||||
|
||||
auto result = safetyhook::InlineHook::create(pAddress, callbackFunction, safetyhook::InlineHook::Flags::StartDisabled);
|
||||
if(result)
|
||||
{
|
||||
detour->m_hook = std::move(result.value());
|
||||
*trampoline = detour->m_hook.original<void*>();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto err = result.error();
|
||||
switch(err.type)
|
||||
{
|
||||
case safetyhook::InlineHook::Error::BAD_ALLOCATION:
|
||||
if(err.allocator_error == safetyhook::Allocator::Error::BAD_VIRTUAL_ALLOC)
|
||||
{
|
||||
g_pSM->LogError(myself, "BAD_VIRTUAL_ALLOC hook %p", pAddress);
|
||||
}
|
||||
else if(err.allocator_error == safetyhook::Allocator::Error::NO_MEMORY_IN_RANGE)
|
||||
{
|
||||
g_pSM->LogError(myself, "NO_MEMORY_IN_RANGE hook %p", pAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pSM->LogError(myself, "BAD_ALLOCATION hook %p errnum %i", pAddress, err.allocator_error);
|
||||
}
|
||||
break;
|
||||
case safetyhook::InlineHook::Error::FAILED_TO_DECODE_INSTRUCTION:
|
||||
g_pSM->LogError(myself, "FAILED_TO_DECODE_INSTRUCTION hook %p ip %p", pAddress, err.ip);
|
||||
break;
|
||||
case safetyhook::InlineHook::Error::SHORT_JUMP_IN_TRAMPOLINE:
|
||||
g_pSM->LogError(myself, "SHORT_JUMP_IN_TRAMPOLINE hook %p ip %p", pAddress, err.ip);
|
||||
break;
|
||||
case safetyhook::InlineHook::Error::IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE:
|
||||
g_pSM->LogError(myself, "IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE hook %p ip %p", pAddress, err.ip);
|
||||
break;
|
||||
case safetyhook::InlineHook::Error::UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE:
|
||||
g_pSM->LogError(myself, "UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE hook %p ip %p", pAddress, err.ip);
|
||||
break;
|
||||
case safetyhook::InlineHook::Error::FAILED_TO_UNPROTECT:
|
||||
g_pSM->LogError(myself, "FAILED_TO_UNPROTECT hook %p ip %p", pAddress, err.ip);
|
||||
break;
|
||||
case safetyhook::InlineHook::Error::NOT_ENOUGH_SPACE:
|
||||
g_pSM->LogError(myself, "NOT_ENOUGH_SPACE hook %p ip %p", pAddress, err.ip);
|
||||
break;
|
||||
default:
|
||||
g_pSM->LogError(myself, "Unknown error %i hook %p ip %p", err.type, pAddress, err.ip);
|
||||
break;
|
||||
}
|
||||
|
||||
delete detour;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return detour;
|
||||
}
|
||||
|
||||
CDetour::CDetour(void* callbackFunction, void **trampoline, void *pAddress)
|
||||
{
|
||||
}
|
||||
|
||||
bool CDetour::IsEnabled()
|
||||
{
|
||||
return m_hook.enabled();
|
||||
}
|
||||
|
||||
void CDetour::EnableDetour()
|
||||
{
|
||||
m_hook.enable();
|
||||
}
|
||||
|
||||
void CDetour::DisableDetour()
|
||||
{
|
||||
m_hook.disable();
|
||||
}
|
||||
|
||||
void CDetour::Destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
@ -1,273 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id: detours.h 257 2008-09-23 03:12:13Z pred $
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_DETOURS_H_
|
||||
#define _INCLUDE_SOURCEMOD_DETOURS_H_
|
||||
|
||||
#include "safetyhook.hpp"
|
||||
#include <smsdk_ext.h>
|
||||
|
||||
#define DETOUR_MEMBER_CALL(name) (this->*name##_Actual)
|
||||
#define DETOUR_STATIC_CALL(name) (name##_Actual)
|
||||
|
||||
#define DETOUR_DECL_STATIC0(name, ret) \
|
||||
ret (*name##_Actual)(void) = NULL; \
|
||||
ret name(void)
|
||||
|
||||
#define DETOUR_DECL_STATIC1(name, ret, p1type, p1name) \
|
||||
ret (*name##_Actual)(p1type) = NULL; \
|
||||
ret name(p1type p1name)
|
||||
|
||||
#define DETOUR_DECL_STATIC2(name, ret, p1type, p1name, p2type, p2name) \
|
||||
ret (*name##_Actual)(p1type, p2type) = NULL; \
|
||||
ret name(p1type p1name, p2type p2name)
|
||||
|
||||
#define DETOUR_DECL_STATIC3(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \
|
||||
ret (*name##_Actual)(p1type, p2type, p3type) = NULL; \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name)
|
||||
|
||||
#define DETOUR_DECL_STATIC4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
|
||||
ret (*name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
|
||||
|
||||
#define DETOUR_DECL_STATIC5(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name) \
|
||||
ret (*name##_Actual)(p1type, p2type, p3type, p4type, p5type) = NULL; \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name)
|
||||
|
||||
#define DETOUR_DECL_STATIC6(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name) \
|
||||
ret (*name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type) = NULL; \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name)
|
||||
|
||||
#define DETOUR_DECL_STATIC7(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name) \
|
||||
ret (*name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type) = NULL; \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name)
|
||||
|
||||
#define DETOUR_DECL_STATIC8(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name) \
|
||||
ret (*name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type) = NULL; \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER0(name, ret) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(); \
|
||||
static ret (name##Class::* name##_Actual)(void); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(void) = NULL; \
|
||||
ret name##Class::name()
|
||||
|
||||
#define DETOUR_DECL_MEMBER1(name, ret, p1type, p1name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type) = NULL; \
|
||||
ret name##Class::name(p1type p1name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER2(name, ret, p1type, p1name, p2type, p2name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER3(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER5(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER6(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER7(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name)
|
||||
|
||||
#define DETOUR_DECL_MEMBER8(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name) \
|
||||
class name##Class \
|
||||
{ \
|
||||
public: \
|
||||
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name); \
|
||||
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type); \
|
||||
}; \
|
||||
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type) = NULL; \
|
||||
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name)
|
||||
|
||||
|
||||
#define GET_MEMBER_CALLBACK(name) (void *)GetCodeAddress(&name##Class::name)
|
||||
#define GET_MEMBER_TRAMPOLINE(name) (void **)(&name##Class::name##_Actual)
|
||||
|
||||
#define GET_STATIC_CALLBACK(name) (void *)&name
|
||||
#define GET_STATIC_TRAMPOLINE(name) (void **)&name##_Actual
|
||||
|
||||
#define DETOUR_CREATE_MEMBER(name, gamedata) CDetourManager::CreateDetour(GET_MEMBER_CALLBACK(name), GET_MEMBER_TRAMPOLINE(name), gamedata);
|
||||
#define DETOUR_CREATE_STATIC(name, gamedata) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), gamedata);
|
||||
|
||||
|
||||
class GenericClass {};
|
||||
typedef void (GenericClass::*VoidFunc)();
|
||||
|
||||
inline void *GetCodeAddr(VoidFunc mfp)
|
||||
{
|
||||
return *(void **)&mfp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a member function pointer to a void pointer.
|
||||
* This relies on the assumption that the code address lies at mfp+0
|
||||
* This is the case for both g++ and later MSVC versions on non virtual functions but may be different for other compilers
|
||||
* Based on research by Don Clugston : http://www.codeproject.com/cpp/FastDelegate.asp
|
||||
*/
|
||||
#define GetCodeAddress(mfp) GetCodeAddr(reinterpret_cast<VoidFunc>(mfp))
|
||||
|
||||
class CDetourManager;
|
||||
|
||||
class CDetour
|
||||
{
|
||||
public:
|
||||
|
||||
bool IsEnabled();
|
||||
|
||||
/**
|
||||
* These would be somewhat self-explanatory I hope
|
||||
*/
|
||||
void EnableDetour();
|
||||
void DisableDetour();
|
||||
|
||||
void Destroy();
|
||||
|
||||
friend class CDetourManager;
|
||||
|
||||
protected:
|
||||
CDetour(void*callbackfunction, void **trampoline, void *pAddress);
|
||||
private:
|
||||
SafetyHookInline m_hook{};
|
||||
};
|
||||
|
||||
class CDetourManager
|
||||
{
|
||||
public:
|
||||
|
||||
static void Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
|
||||
|
||||
/**
|
||||
* Creates a new detour
|
||||
*
|
||||
* @param callbackfunction Void pointer to your detour callback function.
|
||||
* @param trampoline Address of the trampoline pointer
|
||||
* @param signame Section name containing a signature to fetch from the gamedata file.
|
||||
* @return A new CDetour pointer to control your detour.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int)
|
||||
*
|
||||
* Define a new class with the required function and a member function pointer to the same type:
|
||||
*
|
||||
* class CBaseServerDetour
|
||||
* {
|
||||
* public:
|
||||
* bool ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
|
||||
* static bool (CBaseServerDetour::* ConnectClient_Actual)(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
|
||||
* }
|
||||
*
|
||||
* void *callbackfunc = GetCodeAddress(&CBaseServerDetour::ConnectClient);
|
||||
* void **trampoline = (void **)(&CBaseServerDetour::ConnectClient_Actual);
|
||||
*
|
||||
* Creation:
|
||||
* CDetourManager::CreateDetour(callbackfunc, trampoline, "ConnectClient");
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* CBaseServerDetour::ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int)
|
||||
* {
|
||||
* //pre hook code
|
||||
* bool result = (this->*ConnectClient_Actual)(netaddr_s, rest of params);
|
||||
* //post hook code
|
||||
* return result;
|
||||
* }
|
||||
*
|
||||
* Note we changed the netadr_s reference into a void* to avoid needing to define the type
|
||||
*/
|
||||
static CDetour *CreateDetour(void *callbackFunction, void **trampoline, const char *signame);
|
||||
static CDetour *CreateDetour(void *callbackFunction, void **trampoline, void *pAddress);
|
||||
|
||||
friend class CDetour;
|
||||
|
||||
private:
|
||||
static ISourcePawnEngine *spengine;
|
||||
static IGameConfig *gameconf;
|
||||
};
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_DETOURS_H_
|
||||
Loading…
Reference in New Issue
Block a user