Skip to content

Instantly share code, notes, and snippets.

@zid

zid/patch.c Secret

Created June 16, 2022 04:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zid/8607b9503270be086c74340d5fa6e2b3 to your computer and use it in GitHub Desktop.
Save zid/8607b9503270be086c74340d5fa6e2b3 to your computer and use it in GitHub Desktop.
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