-
-
Save zid/823b86b6f914858ec7a8ec151f403715 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
#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