Remove CDetour

This commit is contained in:
Kenzzer 2025-08-17 16:30:18 +00:00
parent 1c5183dd18
commit 1339f38008
No known key found for this signature in database
GPG Key ID: 64C3FD4332686DC1
3 changed files with 0 additions and 532 deletions

View File

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

View File

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

View File

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