Init iw4x base

This commit is contained in:
ineedbots
2021-06-28 12:13:34 -06:00
commit 0c2c478990
21 changed files with 1460 additions and 0 deletions

9
src/Game/MP.cpp Normal file
View File

@ -0,0 +1,9 @@
#include "STDInclude.hpp"
namespace MP
{
void PatchT4()
{
MessageBoxA(nullptr, "MP", "DEBUG", 0);
}
}

6
src/Game/MP.hpp Normal file
View File

@ -0,0 +1,6 @@
#pragma once
namespace MP
{
void PatchT4();
}

View File

0
src/Game/MP/Structs.hpp Normal file
View File

9
src/Game/SP.cpp Normal file
View File

@ -0,0 +1,9 @@
#include "STDInclude.hpp"
namespace SP
{
void PatchT4()
{
MessageBoxA(nullptr, "SP", "DEBUG", 0);
}
}

6
src/Game/SP.hpp Normal file
View File

@ -0,0 +1,6 @@
#pragma once
namespace SP
{
void PatchT4();
}

View File

0
src/Game/SP/Structs.hpp Normal file
View File

89
src/Main.cpp Normal file
View File

@ -0,0 +1,89 @@
#include "STDInclude.hpp"
namespace Main
{
static BYTE originalCode[5];
static PBYTE originalEP = 0;
void UnprotectModule(HMODULE hModule)
{
PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule;
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + header->e_lfanew);
// unprotect the entire PE image
SIZE_T size = ntHeader->OptionalHeader.SizeOfImage;
DWORD oldProtect;
VirtualProtect((LPVOID)hModule, size, PAGE_EXECUTE_READWRITE, &oldProtect);
}
void DoInit()
{
// return to the original EP
memcpy(originalEP, &originalCode, sizeof(originalCode));
// unprotect our entire PE image
HMODULE hModule;
if (SUCCEEDED(GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)DoInit, &hModule)))
{
UnprotectModule(hModule);
}
// detect which executable's patches to apply
DWORD dataStrData = Utils::Hook::Get<DWORD>(0x881CAC);
if (dataStrData == 0x62616E55)
MP::PatchT4();
else
SP::PatchT4();
hModule = GetModuleHandle(NULL);
PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule;
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + header->e_lfanew);
// back up original code
originalEP = (PBYTE)((DWORD)hModule + ntHeader->OptionalHeader.AddressOfEntryPoint);
__asm
{
jmp originalEP
}
}
void SetSafeInit()
{
// find the entry point for the executable process, set page access, and replace the EP
HMODULE hModule = GetModuleHandle(NULL); // passing NULL should be safe even with the loader lock being held (according to ReactOS ldr.c)
if (hModule)
{
PIMAGE_DOS_HEADER header = (PIMAGE_DOS_HEADER)hModule;
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)hModule + header->e_lfanew);
UnprotectModule(hModule);
// back up original code
PBYTE ep = (PBYTE)((DWORD)hModule + ntHeader->OptionalHeader.AddressOfEntryPoint);
memcpy(originalCode, ep, sizeof(originalCode));
// patch to call our EP
int newEP = (int)DoInit - ((int)ep + 5);
ep[0] = 0xE9; // for some reason this doesn't work properly when run under the debugger
memcpy(&ep[1], &newEP, 4);
originalEP = ep;
}
}
}
bool APIENTRY DllMain(HMODULE, DWORD dwReason, LPVOID)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
DWORD textSegData = Utils::Hook::Get<DWORD>(0x401000);
// detect for all executables to hook into
//if (textSegData == 0x9EF490B8 || textSegData == 0x83EC8B55)
Main::SetSafeInit();
}
return true;
}

97
src/Resource.rc Normal file
View File

@ -0,0 +1,97 @@
// Microsoft Visual C++ generated resource script.
//
#pragma code_page(65001)
#include "STDInclude.hpp"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "windows.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"#include ""windows.h""\r\n"
"\0"
END
2 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "CoD2m"
#ifdef _DEBUG
VALUE "FileDescription", "CoD2 client/server modification (DEBUG)"
#else
VALUE "FileDescription", "CoD2 client/server modification"
#endif
VALUE "FileVersion", SHORTVERSION
VALUE "InternalName", "cod2m"
VALUE "LegalCopyright", "All rights reserved."
VALUE "OriginalFilename", "d3d9.dll"
VALUE "ProductName", "CoD2m"
VALUE "ProductVersion", SHORTVERSION
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

90
src/SDLLP.cpp Normal file
View File

@ -0,0 +1,90 @@
// --------------------------------------+
// System Dynamic Link Library Proxy
// by momo5502
// --------------------------------------+
#include "STDInclude.hpp"
// Macro to declare an export
// --------------------------------------+
#define EXPORT(_export) extern "C" __declspec(naked) __declspec(dllexport) void _export() { static FARPROC function = 0; if(!function) function = SDLLP::GetExport(__FUNCTION__, LIBRARY); __asm { jmp function } }
// Static class
// --------------------------------------+
class SDLLP
{
private:
static std::map<std::string, HINSTANCE> mLibraries;
static void Log(const char* message, ...);
static void LoadLibrary(const char* library);
static bool IsLibraryLoaded(const char* library);
public:
static FARPROC GetExport(const char* function, const char* library);
};
// Class variable declarations
// --------------------------------------+
std::map<std::string, HINSTANCE> SDLLP::mLibraries;
// Load necessary library
// --------------------------------------+
void SDLLP::LoadLibrary(const char* library)
{
Log("[SDLLP] Loading library '%s'.", library);
CHAR mPath[MAX_PATH];
GetSystemDirectoryA(mPath, MAX_PATH);
strcat_s(mPath, "\\");
strcat_s(mPath, library);
mLibraries[library] = ::LoadLibraryA(mPath);
if (!IsLibraryLoaded(library)) Log("[SDLLP] Unable to load library '%s'.", library);
}
// Check if export already loaded
// --------------------------------------+
bool SDLLP::IsLibraryLoaded(const char* library)
{
return (mLibraries.find(library) != mLibraries.end() && mLibraries[library]);
}
// Get export address
// --------------------------------------+
FARPROC SDLLP::GetExport(const char* function, const char* library)
{
Log("[SDLLP] Export '%s' requested from %s.", function, library);
if (!IsLibraryLoaded(library)) LoadLibrary(library);
FARPROC address = GetProcAddress(mLibraries[library], function);
if (!address) Log("[SDLLP] Unable to load export '%s' from library '%s'.", function, library);
return address;
}
// Write debug string
// --------------------------------------+
void SDLLP::Log(const char* message, ...)
{
CHAR buffer[1024];
va_list ap;
va_start(ap, message);
vsprintf(buffer, message, ap);
va_end(ap);
OutputDebugStringA(buffer);
}
// --------------------------------------+
// Adapt export functions and library
// --------------------------------------+
#define LIBRARY "d3d9.dll"
EXPORT(D3DPERF_BeginEvent)
EXPORT(D3DPERF_EndEvent)
EXPORT(Direct3DCreate9)

115
src/STDInclude.cpp Normal file
View File

@ -0,0 +1,115 @@
#include "STDInclude.hpp"
// Rename sections
#ifndef DEBUG
#pragma comment(linker, "/merge:.text=.UPX0")
#pragma comment(linker, "/merge:.data=.UPX1")
#pragma comment(linker, "/merge:.rdata=.UPX2")
#pragma comment(linker, "/merge:.tls=.UPX3")
#pragma comment(linker, "/merge:.gfids=.UPX4")
#endif
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
// Do necessary assertions here
// Some compilers treat them differently which causes a size mismatch
// WinAPI types
AssertSize(DWORD, 4);
AssertSize(WORD, 2);
AssertSize(BYTE, 1);
// 128 bit integers (only x64)
//AssertSize(__int128, 16);
//AssertSize(unsigned __int128, 16);
// 64 bit integers
AssertSize(__int64, 8);
AssertSize(unsigned __int64, 8);
AssertSize(long long, 8);
AssertSize(unsigned long long, 8);
AssertSize(int64_t, 8);
AssertSize(uint64_t, 8);
AssertSize(std::int64_t, 8);
AssertSize(std::uint64_t, 8);
// 64 bit double precision floating point numbers
AssertSize(double, 8);
// 32 bit integers
AssertSize(__int32, 4);
AssertSize(unsigned __int32, 4);
AssertSize(int, 4);
AssertSize(unsigned int, 4);
AssertSize(long, 4);
AssertSize(unsigned long, 4);
AssertSize(int32_t, 4);
AssertSize(uint32_t, 4);
AssertSize(std::int32_t, 4);
AssertSize(std::uint32_t, 4);
// 32 bit single precision floating point numbers
AssertSize(float, 4);
// 16 bit integers
AssertSize(__int16, 2);
AssertSize(unsigned __int16, 2);
AssertSize(short, 2);
AssertSize(unsigned short, 2);
AssertSize(int16_t, 2);
AssertSize(uint16_t, 2);
AssertSize(std::int16_t, 2);
AssertSize(std::uint16_t, 2);
// 8 bit integers
AssertSize(bool, 1);
AssertSize(__int8, 1);
AssertSize(unsigned __int8, 1);
AssertSize(char, 1);
AssertSize(unsigned char, 1);
AssertSize(int8_t, 1);
AssertSize(uint8_t, 1);
AssertSize(std::int8_t, 1);
AssertSize(std::uint8_t, 1);
// Ensure pointers are 4 bytes in size (32-bit)
// ReSharper disable CppRedundantBooleanExpressionArgument
static_assert(sizeof(intptr_t) == 4 && sizeof(void*) == 4 && sizeof(size_t) == 4, "This doesn't seem to be a 32-bit environment!");
// ReSharper restore CppRedundantBooleanExpressionArgument
#if !defined(_M_IX86)
#error "Invalid processor achritecture!"
#endif
extern "C"
{
// Disable telemetry data logging
void __cdecl __vcrt_initialize_telemetry_provider() {}
void __cdecl __telemetry_main_invoke_trigger() {}
void __cdecl __telemetry_main_return_trigger() {}
void __cdecl __vcrt_uninitialize_telemetry_provider() {}
// Enable 'High Performance Graphics'
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
// Tommath fixes
int s_read_arc4random(void*, size_t)
{
return -1;
}
int s_read_getrandom(void*, size_t)
{
return -1;
}
int s_read_urandom(void*, size_t)
{
return -1;
}
int s_read_ltm_rng(void*, size_t)
{
return -1;
}
};

120
src/STDInclude.hpp Normal file
View File

@ -0,0 +1,120 @@
#pragma once
// Version number
#include "version.h"
#ifndef RC_INVOKED
#define _HAS_CXX17 1
#define _HAS_CXX20 1
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#define _CRT_SECURE_NO_WARNINGS
// Requires Visual Leak Detector plugin: http://vld.codeplex.com/
#define VLD_FORCE_ENABLE
//#include <vld.h>
#pragma warning(disable: 4740)
#include <windows.h>
#include <timeapi.h>
#include <shellapi.h>
#include <Wininet.h>
#include <Aclapi.h>
#include <Psapi.h>
#include <tlhelp32.h>
#include <Shlwapi.h>
#pragma warning(push)
#pragma warning(disable: 4091)
#pragma warning(disable: 4244)
#include <dbghelp.h>
#include <sstream>
#include <fstream>
#include <cctype>
#include <regex>
#include <thread>
#include <future>
#include <map>
#include <queue>
// Experimental C++17 features
#include <filesystem>
#include <optional>
#pragma warning(pop)
// Usefull for debugging
template <size_t S> class Sizer { };
#define BindNum(x, y) Sizer<x> y;
#define Size_Of(x, y) BindNum(sizeof(x), y)
#define Offset_Of(x, y, z) BindNum(offsetof(x, y), z)
// Submodules
// Ignore the warnings, it's not our code!
#pragma warning(push)
#pragma warning(disable: 4005)
#pragma warning(disable: 4091)
#pragma warning(disable: 4100)
#pragma warning(disable: 4244)
#pragma warning(disable: 4389)
#pragma warning(disable: 4702)
#pragma warning(disable: 4800)
#pragma warning(disable: 4996) // _CRT_SECURE_NO_WARNINGS
#pragma warning(disable: 5054)
#pragma warning(disable: 6001)
#pragma warning(disable: 6011)
#pragma warning(disable: 6031)
#pragma warning(disable: 6255)
#pragma warning(disable: 6258)
#pragma warning(disable: 6386)
#pragma warning(disable: 6387)
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
#pragma warning(pop)
#include "Utils/Hooking.hpp"
#include "Game/MP.hpp"
#include "Game/SP.hpp"
// Libraries
#pragma comment(lib, "Winmm.lib")
#pragma comment(lib, "Crypt32.lib")
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Wininet.lib")
#pragma comment(lib, "shlwapi.lib")
#pragma comment(lib, "Urlmon.lib")
#pragma comment(lib, "Advapi32.lib")
#pragma comment(lib, "rpcrt4.lib")
#pragma comment(lib, "dbghelp.lib")
// Enable additional literals
using namespace std::literals;
#endif
#define STRINGIZE_(x) #x
#define STRINGIZE(x) STRINGIZE_(x)
#define AssertSize(x, size) static_assert(sizeof(x) == size, STRINGIZE(x) " structure has an invalid size.")
#define AssertOffset(x, y, offset) static_assert(offsetof(x, y) == offset, STRINGIZE(x) "::" STRINGIZE(y) " is not at the right offset.")
// Resource stuff
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
// Defines below make accessing the resources from the code easier.
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

256
src/Utils/Hooking.cpp Normal file
View File

@ -0,0 +1,256 @@
#include "STDInclude.hpp"
namespace Utils
{
std::map<void*, void*> Hook::Interceptor::IReturn;
std::map<void*, void(*)()> Hook::Interceptor::ICallbacks;
void Hook::Signature::process()
{
if (this->signatures.empty()) return;
char* _start = reinterpret_cast<char*>(this->start);
unsigned int sigCount = this->signatures.size();
Hook::Signature::Container* containers = this->signatures.data();
for (size_t i = 0; i < this->length; ++i)
{
char* address = _start + i;
for (unsigned int k = 0; k < sigCount; ++k)
{
Hook::Signature::Container* container = &containers[k];
unsigned int j;
for (j = 0; j < strlen(container->mask); ++j)
{
if (container->mask[j] != '?' &&container->signature[j] != address[j])
{
break;
}
}
if (j == strlen(container->mask))
{
container->callback(address);
}
}
}
}
void Hook::Signature::add(Hook::Signature::Container& container)
{
Hook::Signature::signatures.push_back(container);
}
void Hook::Interceptor::Install(void* place, void* stub)
{
return Hook::Interceptor::Install(place, static_cast<void(*)()>(stub));
}
void Hook::Interceptor::Install(void* place, void(*stub)())
{
return Hook::Interceptor::Install(reinterpret_cast<void**>(place), stub);
}
void Hook::Interceptor::Install(void** place, void(*stub)())
{
Hook::Interceptor::IReturn[place] = *place;
Hook::Interceptor::ICallbacks[place] = stub;
*place = Hook::Interceptor::InterceptionStub;
}
__declspec(naked) void Hook::Interceptor::InterceptionStub()
{
__asm
{
sub esp, 4h // Reserve space on the stack for the return address
pushad // Store registers
lea eax, [esp + 20h] // Load initial stack pointer
push eax // Push it onto the stack
call Hook::Interceptor::RunCallback // Run the callback based on the given stack pointer
call Hook::Interceptor::PopReturn // Get the initial return address according to the stack pointer
add esp, 4h // Clear the stack
mov [esp + 20h], eax // Store the return address at the reserved space
popad // Restore the registers
retn // Return (jump to our return address)
}
}
void Hook::Interceptor::RunCallback(void* place)
{
auto iCallback = Hook::Interceptor::ICallbacks.find(place);
if (iCallback != Hook::Interceptor::ICallbacks.end())
{
iCallback->second();
Hook::Interceptor::ICallbacks.erase(iCallback);
}
}
void* Hook::Interceptor::PopReturn(void* _place)
{
void* retVal = nullptr;
auto iReturn = Hook::Interceptor::IReturn.find(_place);
if (iReturn != Hook::Interceptor::IReturn.end())
{
retVal = iReturn->second;
Hook::Interceptor::IReturn.erase(iReturn);
}
return retVal;
}
Hook::~Hook()
{
if (this->initialized)
{
this->uninstall();
}
}
Hook* Hook::initialize(DWORD _place, void(*_stub)(), bool _useJump)
{
return this->initialize(_place, reinterpret_cast<void*>(_stub), _useJump);
}
Hook* Hook::initialize(DWORD _place, void* _stub, bool _useJump)
{
return this->initialize(reinterpret_cast<void*>(_place), _stub, _useJump);
}
Hook* Hook::initialize(void* _place, void* _stub, bool _useJump)
{
if (this->initialized) return this;
this->initialized = true;
this->useJump = _useJump;
this->place = _place;
this->stub = _stub;
this->original = static_cast<char*>(this->place) + 5 + *reinterpret_cast<DWORD*>((static_cast<char*>(this->place) + 1));
return this;
}
Hook* Hook::install(bool unprotect, bool keepUnprotected)
{
std::lock_guard<std::mutex> _(this->stateMutex);
if (!this->initialized || this->installed)
{
return this;
}
this->installed = true;
if (unprotect) VirtualProtect(this->place, sizeof(this->buffer), PAGE_EXECUTE_READWRITE, &this->protection);
std::memcpy(this->buffer, this->place, sizeof(this->buffer));
char* code = static_cast<char*>(this->place);
*code = static_cast<char>(this->useJump ? 0xE9 : 0xE8);
*reinterpret_cast<size_t*>(code + 1) = reinterpret_cast<size_t>(this->stub) - (reinterpret_cast<size_t>(this->place) + 5);
if (unprotect && !keepUnprotected) VirtualProtect(this->place, sizeof(this->buffer), this->protection, &this->protection);
FlushInstructionCache(GetCurrentProcess(), this->place, sizeof(this->buffer));
return this;
}
void Hook::quick()
{
if (Hook::installed)
{
Hook::installed = false;
}
}
Hook* Hook::uninstall(bool unprotect)
{
std::lock_guard<std::mutex> _(this->stateMutex);
if (!this->initialized || !this->installed)
{
return this;
}
this->installed = false;
if (unprotect) VirtualProtect(this->place, sizeof(this->buffer), PAGE_EXECUTE_READWRITE, &this->protection);
std::memcpy(this->place, this->buffer, sizeof(this->buffer));
if (unprotect) VirtualProtect(this->place, sizeof(this->buffer), this->protection, &this->protection);
FlushInstructionCache(GetCurrentProcess(), this->place, sizeof(this->buffer));
return this;
}
void* Hook::getAddress()
{
return this->place;
}
void Hook::Nop(void* place, size_t length)
{
DWORD oldProtect;
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &oldProtect);
memset(place, 0x90, length);
VirtualProtect(place, length, oldProtect, &oldProtect);
FlushInstructionCache(GetCurrentProcess(), place, length);
}
void Hook::Nop(DWORD place, size_t length)
{
Nop(reinterpret_cast<void*>(place), length);
}
void Hook::SetString(void* place, const char* string, size_t length)
{
DWORD oldProtect;
VirtualProtect(place, length + 1, PAGE_EXECUTE_READWRITE, &oldProtect);
strncpy_s(static_cast<char*>(place), length, string, length);
VirtualProtect(place, length + 1, oldProtect, &oldProtect);
}
void Hook::SetString(DWORD place, const char* string, size_t length)
{
Hook::SetString(reinterpret_cast<void*>(place), string, length);
}
void Hook::SetString(void* place, const char* string)
{
Hook::SetString(place, string, strlen(static_cast<char*>(place)));
}
void Hook::SetString(DWORD place, const char* string)
{
Hook::SetString(reinterpret_cast<void*>(place), string);
}
void Hook::RedirectJump(void* place, void* stub)
{
char* operandPtr = static_cast<char*>(place) + 2;
int newOperand = reinterpret_cast<int>(stub) - (reinterpret_cast<int>(place) + 6);
Utils::Hook::Set<int>(operandPtr, newOperand);
}
void Hook::RedirectJump(DWORD place, void* stub)
{
Hook::RedirectJump(reinterpret_cast<void*>(place), stub);
}
}

185
src/Utils/Hooking.hpp Normal file
View File

@ -0,0 +1,185 @@
#pragma once
#define HOOK_JUMP true
#define HOOK_CALL false
namespace Utils
{
class Hook
{
public:
class Signature
{
public:
struct Container
{
const char* signature;
const char* mask;
std::function<void(char*)> callback;
};
Signature(void* _start, size_t _length) : start(_start), length(_length) {}
Signature(DWORD _start, size_t _length) : Signature(reinterpret_cast<void*>(_start), _length) {}
Signature() : Signature(0x400000, 0x800000) {}
void process();
void add(Container& container);
private:
void* start;
size_t length;
std::vector<Container> signatures;
};
class Interceptor
{
public:
static void Install(void* place, void* stub);
static void Install(void* place, void(*stub)());
static void Install(void** place, void(*stub)());
private:
static std::map<void*, void*> IReturn;
static std::map<void*, void(*)()> ICallbacks;
static void InterceptionStub();
static void RunCallback(void* place);
static void* PopReturn(void* place);
};
Hook() : initialized(false), installed(false), place(nullptr), stub(nullptr), original(nullptr), useJump(false), protection(0) { ZeroMemory(this->buffer, sizeof(this->buffer)); }
Hook(void* place, void* stub, bool useJump = true) : Hook() { this->initialize(place, stub, useJump); }
Hook(void* place, void(*stub)(), bool useJump = true) : Hook(place, reinterpret_cast<void*>(stub), useJump) {}
Hook(DWORD place, void* stub, bool useJump = true) : Hook(reinterpret_cast<void*>(place), stub, useJump) {}
Hook(DWORD place, DWORD stub, bool useJump = true) : Hook(reinterpret_cast<void*>(place), reinterpret_cast<void*>(stub), useJump) {}
Hook(DWORD place, void(*stub)(), bool useJump = true) : Hook(reinterpret_cast<void*>(place), reinterpret_cast<void*>(stub), useJump) {}
~Hook();
Hook* initialize(void* place, void* stub, bool useJump = true);
Hook* initialize(DWORD place, void* stub, bool useJump = true);
Hook* initialize(DWORD place, void(*stub)(), bool useJump = true); // For lambdas
Hook* install(bool unprotect = true, bool keepUnprotected = false);
Hook* uninstall(bool unprotect = true);
void* getAddress();
void quick();
template <typename T> static std::function<T> Call(DWORD function)
{
return std::function<T>(reinterpret_cast<T*>(function));
}
template <typename T> static std::function<T> Call(FARPROC function)
{
return Call<T>(reinterpret_cast<DWORD>(function));
}
template <typename T> static std::function<T> Call(void* function)
{
return Call<T>(reinterpret_cast<DWORD>(function));
}
static void SetString(void* place, const char* string, size_t length);
static void SetString(DWORD place, const char* string, size_t length);
static void SetString(void* place, const char* string);
static void SetString(DWORD place, const char* string);
static void Nop(void* place, size_t length);
static void Nop(DWORD place, size_t length);
static void RedirectJump(void* place, void* stub);
static void RedirectJump(DWORD place, void* stub);
template <typename T> static void Set(void* place, T value)
{
DWORD oldProtect;
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
*static_cast<T*>(place) = value;
VirtualProtect(place, sizeof(T), oldProtect, &oldProtect);
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
}
template <typename T> static void Set(DWORD place, T value)
{
return Set<T>(reinterpret_cast<void*>(place), value);
}
template <typename T> static void Xor(void* place, T value)
{
DWORD oldProtect;
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
*static_cast<T*>(place) ^= value;
VirtualProtect(place, sizeof(T), oldProtect, &oldProtect);
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
}
template <typename T> static void Xor(DWORD place, T value)
{
return Xor<T>(reinterpret_cast<void*>(place), value);
}
template <typename T> static void Or(void* place, T value)
{
DWORD oldProtect;
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
*static_cast<T*>(place) |= value;
VirtualProtect(place, sizeof(T), oldProtect, &oldProtect);
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
}
template <typename T> static void Or(DWORD place, T value)
{
return Or<T>(reinterpret_cast<void*>(place), value);
}
template <typename T> static void And(void* place, T value)
{
DWORD oldProtect;
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
*static_cast<T*>(place) &= value;
VirtualProtect(place, sizeof(T), oldProtect, &oldProtect);
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
}
template <typename T> static void And(DWORD place, T value)
{
return And<T>(reinterpret_cast<void*>(place), value);
}
template <typename T> static T Get(void* place)
{
return *static_cast<T*>(place);
}
template <typename T> static T Get(DWORD place)
{
return Get<T>(reinterpret_cast<void*>(place));
}
private:
bool initialized;
bool installed;
void* place;
void* stub;
void* original;
char buffer[5];
bool useJump;
DWORD protection;
std::mutex stateMutex;
};
}