#pragma once #include #include #include #include namespace rem { void Patch(DWORD address, const void* data, UINT length); void PatchBytes(DWORD address, std::initializer_list bytes); void Nop(DWORD address, UINT length); void ReadWriteProtect(DWORD address, DWORD size); template inline void Patch(DWORD address, Type value) { Patch(address, &value, sizeof(Type)); } template inline Type& ValueAt(DWORD address) { ReadWriteProtect(address, sizeof(Type)); return *reinterpret_cast(address); } template inline Func FunctionAt(DWORD address) { return reinterpret_cast(address); } template Func SetRelPointer(DWORD location, Func hook) { DWORD& relative = ValueAt(location); DWORD original = location + relative + 4; DWORD hookAddress = *reinterpret_cast(&hook); relative = hookAddress - (location + 4); return FunctionAt(original); } template void Hook(DWORD address, Func hook, UINT instructionLength, bool jump = false) { assert(instructionLength >= 5); Patch(address, jump ? 0xE9 : 0xE8); SetRelPointer(address + 1, hook); if (instructionLength > 5) Nop(address + 5, instructionLength - 5); } template Func Trampoline(DWORD address, Func hook, UINT instructionLength) { BYTE* gateway = static_cast( VirtualAlloc(nullptr, instructionLength + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)); ReadWriteProtect(address, instructionLength); memcpy(gateway, reinterpret_cast(address), instructionLength); Hook(address, hook, instructionLength, true); Hook(reinterpret_cast(gateway + instructionLength), FunctionAt(address + instructionLength), 5, true); return FunctionAt(reinterpret_cast(gateway)); } template void CleanupTrampoline(Func trampoline) { VirtualFree(reinterpret_cast(*reinterpret_cast(&trampoline)), 0, MEM_RELEASE); } }