From 5b7c9c5845dc959f86e64996f511fe0dccd14ac6 Mon Sep 17 00:00:00 2001 From: Asher Baker Date: Sat, 17 Jul 2021 20:53:25 +0100 Subject: [PATCH] Handle detour patches across page boundaries (#1535) On Linux if a detour crossed a page boundary we would only change the memory protection of the first page (as we were aligning the address as required, but not taking into account the length). I don't have an easy way to test this but it looks correct. `addr + len` doesn't appear to need to be aligned though, so another option could be to use `(addr - startPage) + length` as len. Also fixed a non-zero offset being passed into CDetour's ApplyPatch function - this is never done internally anywhere, but it doesn't hurt to fix it. Fixes #984 --- public/CDetour/detourhelpers.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/public/CDetour/detourhelpers.h b/public/CDetour/detourhelpers.h index 3231ed0b..271e7042 100644 --- a/public/CDetour/detourhelpers.h +++ b/public/CDetour/detourhelpers.h @@ -34,13 +34,10 @@ #if defined PLATFORM_POSIX #include -#ifndef PAGE_SIZE -#define PAGE_SIZE 4096 -#endif -#define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1)) #define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC #endif +#include #include struct patch_t @@ -57,8 +54,10 @@ struct patch_t inline void ProtectMemory(void *addr, int length, int prot) { #if defined PLATFORM_POSIX - void *addr2 = (void *)ALIGN(addr); - mprotect(addr2, sysconf(_SC_PAGESIZE), prot); + long pageSize = sysconf(_SC_PAGESIZE); + void *startPage = ke::AlignedBase(addr, pageSize); + void *endPage = ke::AlignedBase((void *)((intptr_t)addr + length), pageSize); + mprotect(startPage, ((intptr_t)endPage - (intptr_t)startPage) + pageSize, prot); #elif defined PLATFORM_WINDOWS DWORD old_prot; VirtualProtect(addr, length, prot, &old_prot); @@ -118,9 +117,9 @@ inline void DoGatePatch(unsigned char *target, void *callback) inline void ApplyPatch(void *address, int offset, const patch_t *patch, patch_t *restore) { - ProtectMemory(address, 20, PAGE_EXECUTE_READWRITE); - unsigned char *addr = (unsigned char *)address + offset; + SetMemPatchable(addr, patch->bytes); + if (restore) { for (size_t i=0; ibytes; i++)