Skip to content

Instantly share code, notes, and snippets.

@leegao
Created October 22, 2012 22:10
Show Gist options
  • Save leegao/3934918 to your computer and use it in GitHub Desktop.
Save leegao/3934918 to your computer and use it in GitHub Desktop.
Context-aware Hot Patching
#include <windows.h>
#include <stdio.h>
//68 BE BA FE CA
const unsigned char OP_PUSH = 0x68;
const unsigned char OP_JMP = 0xE9;
static DWORD rets[10000];
static PDWORD r = NULL;
struct patchwork{
PBYTE dst;
PBYTE src;
DWORD offset;
BYTE A;
DWORD B;
BYTE C;
DWORD D;
};
__declspec( naked ) void get_eip() {
__asm{
mov eax, [esp];
ret
}
}
void* patcher()
{
struct patchwork* patch;
PBYTE d; DWORD d2, r_eax;
__asm{mov patch, ecx};
d = patch->dst;
if(!VirtualProtect(d, 10, PAGE_EXECUTE_READWRITE, &d2)) return NULL;
//patch->A = *d;
//patch->B = *((PDWORD)(d+1));
//patch->C = *(d+5);
//patch->D = *((PDWORD)(d+6));
*d = patch->A;
*((PDWORD)(d + 1)) = patch->B;
*(d+5) = patch->C;
*((PDWORD)(d + 6)) = patch->D;
VirtualProtect(d, 10, d2, &d2);
d2 = (DWORD)patch->src;
// use two more items in stack
__asm{
mov ecx, dword ptr[ebp]
mov d, ecx ; *r = return addr
};
*r++ = (DWORD)d;
__asm{
mov ecx, dword ptr[ebp+4]
mov d, ecx ; *r = return addr
};
*r++ = (DWORD)d;
__asm{
mov ecx, patch
mov d, ecx ; *r+4 = patch
}
*r++ = (DWORD)d;
__asm{
call get_eip;
add eax, 12;
add esp, 20h;
mov dword ptr[ebp+4], eax;
jmp d2
label_done:
}
// reset stack, we're no longer guaranteed that our locals are preserved
// let's just start over, since RTC keeps on complaining about stack corruption
__asm{
sub esp, 24h;
}
__asm{
mov eax,0CCCCCCCCh
mov dword ptr [ebp-18h],eax
mov dword ptr [ebp-14h],eax
mov dword ptr [ebp-10h],eax
mov dword ptr [ebp-0Ch],eax
mov dword ptr [ebp-8],eax
mov dword ptr [ebp-4],eax
}
d = (PBYTE)*--r;
__asm{
mov ecx, d;
mov patch, ecx
}
d = (PBYTE)*--r;
__asm{
mov ecx, d;
mov dword ptr[ebp+4], ecx
}
d = (PBYTE)*--r;
__asm{
mov ecx, d;
mov dword ptr[ebp], ecx
}
d = patch->dst;
if(!VirtualProtect(d, 10, PAGE_EXECUTE_READWRITE, &d2)) return NULL;
patch->A = *d;
patch->B = *((PDWORD)(d+1));
patch->C = *(d+5);
patch->D = *((PDWORD)(d+6));
*d = OP_PUSH;
*((PDWORD)(d + 1)) = (DWORD)patch;
*(d+5) = OP_JMP;
*((PDWORD)(d + 6)) = (PBYTE)(patcher)-d-11;
VirtualProtect(d, 10, d2, &d2);
return;
}
struct patchwork* patch(void* dst, void* src){
DWORD old_protection, dummy;
PBYTE d = (PBYTE)(dst), s = (PBYTE)src, p = (PBYTE)(patcher)-1;
BOOL res;
DWORD offset = p - d - 10;
struct patchwork* patch;
if (!r){
// POP to eax first
res = VirtualProtect(p, 1, PAGE_EXECUTE_READWRITE, &old_protection);
if (!res){
return NULL;
}
*p = 0x59;
VirtualProtect(p, 1, old_protection, &dummy);
r = (PDWORD)&rets;
}
// initialize
patch = (struct patchwork*)malloc(sizeof(struct patchwork));
patch->dst = d;
patch->src = s;
patch->offset = offset;
// start patching, we'll use a poor man's jump table
res = VirtualProtect(d, 10, PAGE_EXECUTE_READWRITE, &old_protection);
if (!res){
free(patch);
return NULL;
}
patch->A = *d;
patch->B = *((PDWORD)(d+1));
patch->C = *(d+5);
patch->D = *((PDWORD)(d+6));
*d = OP_PUSH;
*((PDWORD)(d + 1)) = (DWORD)patch;
*(d+5) = OP_JMP;
*((PDWORD)(d + 6)) = offset;
VirtualProtect(d, 10, old_protection, &dummy);
return patch;
}
void f(){
printf("Hello World from f\n");
}
void* g(char* fmt, ...){
printf("Hello World from g\n");
f();
printf(fmt);
}
int main()
{
struct patchwork* p;
p = patch(printf, g);
f();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment