-
-
Save zid/8607b9503270be086c74340d5fa6e2b3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
list of patches like: | |
{CALL, &opt_hold, 1, 0x004101F8, hold_wrapper, 4}, | |
#include <windows.h> | |
#include <stdint.h> | |
#include "patch.h" | |
#include "stdio.h" | |
enum err { | |
ERR_UNHANDLED = -1, | |
ERR_OK = 0, | |
ERR_PERM, | |
ERR_WRITE, | |
ERR_MISMATCH | |
}; | |
/* Do it! */ | |
static enum err write_offset(uintptr_t in, void *out, size_t len) | |
{ | |
DWORD old; | |
if(!VirtualProtect((void *)in, len, PAGE_READWRITE, &old)) | |
return ERR_PERM; | |
if(!WriteProcessMemory(GetCurrentProcess(), (void *)in, &out, len, NULL)) | |
return ERR_WRITE; | |
VirtualProtect((void *)in, len, old, &old); | |
return ERR_OK; | |
} | |
static enum err write_array(uintptr_t in, void *out, size_t len) | |
{ | |
DWORD old; | |
if(!VirtualProtect((void *)in, len, PAGE_READWRITE, &old)) | |
return ERR_PERM; | |
if(!WriteProcessMemory(GetCurrentProcess(), (void *)in, out, len, NULL)) | |
return ERR_WRITE; | |
VirtualProtect((void *)in, len, old, &old); | |
return ERR_OK; | |
} | |
static enum err write_call(uintptr_t in, void *out, size_t len) | |
{ | |
unsigned char c; | |
/* Check we're actually patching a call */ | |
c = *((unsigned char *)in); | |
if(c != 0xE8) | |
return ERR_MISMATCH; | |
return write_offset(in+1, out-in-5, len); | |
} | |
static enum err write_jump(uintptr_t in, void *out, size_t len) | |
{ | |
unsigned char c; | |
size_t i; | |
/* Check we're actually patching some kind of jump */ | |
c = *((unsigned char *)in); | |
if(c < 0x70 || c > 0x7B && (c != 0xE3 && c != 0xEB && c != 0xEB && c != 0xE9)) | |
return ERR_MISMATCH; | |
return write_offset(in+1, out-in-5, len); | |
} | |
static enum err patch(struct patch p) | |
{ | |
enum err r = ERR_UNHANDLED; | |
if(p.t == OFFS) | |
r = write_offset(p.in, p.out, p.len); | |
else if(p.t == CALL) | |
r = write_call(p.in, p.out, p.len); | |
else if(p.t == JUMP) | |
r = write_jump(p.in, p.out, p.len); | |
else if(p.t = ARRY) | |
r = write_array(p.in, p.out, p.len); | |
return r; | |
} | |
void do_patches(struct patch *p) | |
{ | |
size_t i; | |
enum err r = ERR_OK; | |
char buf[128]; | |
/* Apply all the patches in the list */ | |
for(i = 0; p[i].t; i++) | |
{ | |
/* Patch is not enabled by config */ | |
if(p[i].p && *(p[i].p) < p[i].v) | |
continue; | |
r = patch(p[i]); | |
if(r != ERR_OK) | |
break; | |
} | |
if(r == ERR_OK) | |
return; | |
/* Print nice error messages if a patch failed, then kill game.exe */ | |
switch(r) | |
{ | |
char *s; | |
case ERR_UNHANDLED: | |
sprintf(buf, "Error: Unknown patch type %d {%p, %p}", p[i].t, p[i].in, (uintptr_t)p[i].out); | |
break; | |
case ERR_PERM: | |
sprintf(buf, "Error: Could not unlock source address: %p", p[i].in); | |
break; | |
case ERR_WRITE: | |
sprintf(buf, "Error: Could not write to address: %p (%d)", p[i].in); | |
break; | |
case ERR_MISMATCH: | |
s = (p[i].t == CALL) ? "call" : "jump"; | |
sprintf(buf, "Error: %s patch for %p wasn't a %s instruction", s, p[i].in, s); | |
break; | |
} | |
MessageBox(NULL, buf, "Failed to apply patch", MB_OK | MB_ICONERROR); | |
TerminateProcess(GetCurrentProcess(), 1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment