mirror of
https://github.com/DxWnd/DxWnd.reloaded
synced 2024-12-30 09:25:35 +01:00
101 lines
3.4 KiB
C++
101 lines
3.4 KiB
C++
// hotpatch compiled system dlls come with Windows XP SP2 or later
|
|
|
|
// return:
|
|
// 0 = patch failed
|
|
// 1 = already patched
|
|
// addr = address of the original function
|
|
|
|
#define USEMINHOOK
|
|
|
|
#include <windows.h>
|
|
#include "dxwnd.h"
|
|
#include "dxwcore.hpp"
|
|
#ifdef USEMINHOOK
|
|
#include "MinHook.h"
|
|
#endif
|
|
|
|
void *HotPatch(void *apiproc, const char *apiname, void *hookproc)
|
|
{
|
|
#ifdef USEMINHOOK
|
|
void *pProc;
|
|
static BOOL DoOnce = TRUE;
|
|
|
|
if(DoOnce){
|
|
if (MH_Initialize() != MH_OK) {
|
|
OutTraceE("HotPatch: MH_Initialize FAILED\n");
|
|
// What to do here? No recovery action ...
|
|
return 0;
|
|
}
|
|
DoOnce = FALSE;
|
|
}
|
|
|
|
OutTraceH("HotPatch: api=%s addr=%x hook=%x\n", apiname, apiproc, hookproc);
|
|
|
|
if(!strcmp(apiname, "GetProcAddress")) return 0; // do not mess with this one!
|
|
|
|
if (MH_CreateHook(apiproc, hookproc, reinterpret_cast<void**>(&pProc)) != MH_OK){
|
|
OutTraceH("HotPatch: MH_CreateHook FAILED\n");
|
|
return 0;
|
|
}
|
|
|
|
if (MH_EnableHook(apiproc) != MH_OK){
|
|
OutTraceH("HotPatch: MH_EnableHook FAILED\n");
|
|
return 0;
|
|
}
|
|
|
|
OutTrace("HotPatch: api=%s addr=%x->%x hook=%x\n", apiname, apiproc, pProc, hookproc);
|
|
return pProc;
|
|
#else
|
|
DWORD dwPrevProtect;
|
|
BYTE* patch_address;
|
|
void *orig_address;
|
|
|
|
OutTraceH("HotPatch: api=%s addr=%x hook=%x\n", apiname, apiproc, hookproc);
|
|
|
|
if(!strcmp(apiname, "GetProcAddress")) return 0; // do not mess with this one!
|
|
|
|
patch_address = ((BYTE *)apiproc) - 5;
|
|
orig_address = (BYTE *)apiproc + 2;
|
|
|
|
// entry point could be at the top of a page? so VirtualProtect first to make sure patch_address is readable
|
|
//if(!VirtualProtect(patch_address, 7, PAGE_EXECUTE_READWRITE, &dwPrevProtect)){
|
|
if(!VirtualProtect(patch_address, 12, PAGE_EXECUTE_WRITECOPY, &dwPrevProtect)){
|
|
OutTraceH("HotPatch: access denied. err=%x\n", GetLastError());
|
|
return (void *)0; // access denied
|
|
}
|
|
|
|
// some calls (QueryPerformanceCounter) are sort of hot patched already....
|
|
if(!memcmp( "\x90\x90\x90\x90\x90\xEB\x05\x90\x90\x90\x90\x90", patch_address, 12)){
|
|
*patch_address = 0xE9; // jmp (4-byte relative)
|
|
*((DWORD *)(patch_address + 1)) = (DWORD)hookproc - (DWORD)patch_address - 5; // relative address
|
|
*((WORD *)apiproc) = 0xF9EB; // should be atomic write (jmp $-5)
|
|
|
|
VirtualProtect( patch_address, 12, dwPrevProtect, &dwPrevProtect ); // restore protection
|
|
OutTrace("HotPatch: api=%s addr=%x->%x hook=%x\n", apiname, apiproc, orig_address, hookproc);
|
|
return orig_address;
|
|
}
|
|
|
|
// make sure it is a hotpatchable image... check for 5 nops followed by mov edi,edi
|
|
if(memcmp( "\x90\x90\x90\x90\x90\x8B\xFF", patch_address, 7) && memcmp( "\x90\x90\x90\x90\x90\x89\xFF", patch_address, 7)){
|
|
VirtualProtect( patch_address, 12, dwPrevProtect, &dwPrevProtect ); // restore protection
|
|
// check it wasn't patched already
|
|
if((*patch_address==0xE9) && (*(WORD *)apiproc == 0xF9EB)){
|
|
// should never go through here ...
|
|
OutTraceH("HotPatch: patched already\n");
|
|
return (void *)1;
|
|
}
|
|
else{
|
|
OutTraceH("HotPatch: not patch aware.\n");
|
|
return (void *)0; // not hot patch "aware"
|
|
}
|
|
}
|
|
|
|
*patch_address = 0xE9; // jmp (4-byte relative)
|
|
*((DWORD *)(patch_address + 1)) = (DWORD)hookproc - (DWORD)patch_address - 5; // relative address
|
|
*((WORD *)apiproc) = 0xF9EB; // should be atomic write (jmp $-5)
|
|
|
|
VirtualProtect( patch_address, 12, dwPrevProtect, &dwPrevProtect ); // restore protection
|
|
OutTrace("HotPatch: api=%s addr=%x->%x hook=%x\n", apiname, apiproc, orig_address, hookproc);
|
|
return orig_address;
|
|
#endif
|
|
}
|