diff options
Diffstat (limited to 'src/core/patcher.h')
-rw-r--r-- | src/core/patcher.h | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/core/patcher.h b/src/core/patcher.h new file mode 100644 index 00000000..87a6bea4 --- /dev/null +++ b/src/core/patcher.h @@ -0,0 +1,192 @@ +#pragma once + +#define WRAPPER __declspec(naked) +#define DEPRECATED __declspec(deprecated) +#define EAXJMP(a) { _asm mov eax, a _asm jmp eax } +#define VARJMP(a) { _asm jmp a } +#define WRAPARG(a) UNREFERENCED_PARAMETER(a) + +#define NOVMT __declspec(novtable) +#define SETVMT(a) *((DWORD_PTR*)this) = (DWORD_PTR)a + +#include <algorithm> +#include <vector> + +#include "common.h" + +enum +{ + PATCH_CALL, + PATCH_JUMP, + PATCH_NOTHING, +}; + +enum +{ + III_10 = 1, + III_11, + III_STEAM, + VC_10, + VC_11, + VC_STEAM +}; + +extern int gtaversion; + +class StaticPatcher +{ +private: + using Patcher = void(*)(); + + Patcher m_func; + StaticPatcher *m_next; + static StaticPatcher *ms_head; + + void Run() { m_func(); } +public: + StaticPatcher(Patcher func); + static void Apply(); +}; + +template<typename T> +inline T AddressByVersion(uint32_t addressIII10, uint32_t addressIII11, uint32_t addressIIISteam, uint32_t addressvc10, uint32_t addressvc11, uint32_t addressvcSteam) +{ + if(gtaversion == -1){ + if(*(uint32_t*)0x5C1E75 == 0xB85548EC) gtaversion = III_10; + else if(*(uint32_t*)0x5C2135 == 0xB85548EC) gtaversion = III_11; + else if(*(uint32_t*)0x5C6FD5 == 0xB85548EC) gtaversion = III_STEAM; + else if(*(uint32_t*)0x667BF5 == 0xB85548EC) gtaversion = VC_10; + else if(*(uint32_t*)0x667C45 == 0xB85548EC) gtaversion = VC_11; + else if(*(uint32_t*)0x666BA5 == 0xB85548EC) gtaversion = VC_STEAM; + else gtaversion = 0; + } + switch(gtaversion){ + case III_10: + return (T)addressIII10; + case III_11: + return (T)addressIII11; + case III_STEAM: + return (T)addressIIISteam; + case VC_10: + return (T)addressvc10; + case VC_11: + return (T)addressvc11; + case VC_STEAM: + return (T)addressvcSteam; + default: + return (T)0; + } +} + +inline bool +is10(void) +{ + return gtaversion == III_10 || gtaversion == VC_10; +} + +inline bool +isIII(void) +{ + return gtaversion >= III_10 && gtaversion <= III_STEAM; +} + +inline bool +isVC(void) +{ + return gtaversion >= VC_10 && gtaversion <= VC_STEAM; +} + +#define PTRFROMCALL(addr) (uint32_t)(*(uint32_t*)((uint32_t)addr+1) + (uint32_t)addr + 5) +#define INTERCEPT(saved, func, a) \ +{ \ + saved = PTRFROMCALL(a); \ + InjectHook(a, func); \ +} + +template<typename T, typename AT> inline void +Patch(AT address, T value) +{ + DWORD dwProtect[2]; + VirtualProtect((void*)address, sizeof(T), PAGE_EXECUTE_READWRITE, &dwProtect[0]); + *(T*)address = value; + VirtualProtect((void*)address, sizeof(T), dwProtect[0], &dwProtect[1]); +} + +template<typename AT> inline void +Nop(AT address, unsigned int nCount) +{ + DWORD dwProtect[2]; + VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + memset((void*)address, 0x90, nCount); + VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]); +} + +template<typename AT> inline void +ClearCC(AT address, unsigned int nCount) +{ + DWORD dwProtect[2]; + VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + memset((void*)address, 0xCC, nCount); + VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]); +} + +extern std::vector<int32> usedAddresses; + +template<typename AT, typename HT> inline void +InjectHook(AT address, HT hook, unsigned int nType=PATCH_NOTHING) +{ + if(std::any_of(usedAddresses.begin(), usedAddresses.end(), + [address](AT value) { return (int32)value == address; })) { + debug("Used address %#06x twice when injecting hook\n", address); + } + + usedAddresses.push_back((int32)address); + + DWORD dwProtect[2]; + switch ( nType ) + { + case PATCH_JUMP: + VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + *(BYTE*)address = 0xE9; + break; + case PATCH_CALL: + VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + *(BYTE*)address = 0xE8; + break; + default: + VirtualProtect((void*)((DWORD)address + 1), 4, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + break; + } + DWORD dwHook; + _asm + { + mov eax, hook + mov dwHook, eax + } + + *(ptrdiff_t*)((DWORD)address + 1) = (DWORD)dwHook - (DWORD)address - 5; + if ( nType == PATCH_NOTHING ) + VirtualProtect((void*)((DWORD)address + 1), 4, dwProtect[0], &dwProtect[1]); + else + VirtualProtect((void*)address, 5, dwProtect[0], &dwProtect[1]); +} + +inline void ExtractCall(void *dst, uint32_t a) +{ + *(uint32_t*)dst = (uint32_t)(*(uint32_t*)(a+1) + a + 5); +} +template<typename T> +inline void InterceptCall(void *dst, T func, uint32_t a) +{ + ExtractCall(dst, a); + InjectHook(a, func); +} +template<typename T> +inline void InterceptVmethod(void *dst, T func, uint32_t a) +{ + *(uint32_t*)dst = *(uint32_t*)a; + Patch(a, func); +} + +#define STARTPATCHES static StaticPatcher Patcher([](){ +#define ENDPATCHES }); |