blob: 737b0e202f5510ac0e9994b85ff652a2daf4f1c3 [file] [log] [blame]
#include <stdint.h>
#include <string.h>
#include <windows.h>
#include <psapi.h>
#include "dbg.h"
#include "patch.h"
static CRITICAL_SECTION s_cs;
static IMAGE_IMPORT_DESCRIPTOR *imports(IMAGE_DOS_HEADER *dh) {
char *base = (char *)dh;
IMAGE_NT_HEADERS *nth = (IMAGE_NT_HEADERS *)(base + dh->e_lfanew);
IMAGE_DATA_DIRECTORY *impdd =
nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_IMPORT;
ASSERT(dh->e_lfanew);
ASSERT(nth);
ASSERT(impdd);
return impdd && impdd->VirtualAddress
? (IMAGE_IMPORT_DESCRIPTOR *)(base + impdd->VirtualAddress)
: 0;
}
static IMAGE_THUNK_DATA *lookup2(char *base,
IMAGE_THUNK_DATA *td,
IMAGE_THUNK_DATA *otd,
const char *nm) {
while (otd->u1.AddressOfData) {
IMAGE_IMPORT_BY_NAME *name =
(IMAGE_IMPORT_BY_NAME *)(otd->u1.AddressOfData + base);
if (otd->u1.Ordinal & IMAGE_ORDINAL_FLAG)
dbg(" ordinal1\n");
else {
dbg(" name: %s %p\n", name->Name, td->u1.Function);
if (0 == strcmp((char*)name->Name, nm))
return td;
}
otd++;
td++;
}
return 0;
}
static IMAGE_THUNK_DATA *lookup(IMAGE_DOS_HEADER *dh, const char *nm) {
char *base = (char *)dh;
IMAGE_IMPORT_DESCRIPTOR *id = imports(dh);
if (!id) return 0;
while (id->Name) {
if (id->FirstThunk && id->OriginalFirstThunk) {
IMAGE_THUNK_DATA *d =
lookup2(base,
(IMAGE_THUNK_DATA*)(id->FirstThunk + base),
(IMAGE_THUNK_DATA*)(id->OriginalFirstThunk + base),
nm);
dbg(" import %s\n", id->Name + base);
if (d)
return d;
}
id++;
}
return 0;
}
static void modpatch(IMAGE_DOS_HEADER *dh,
void *orig,
void *hook,
void **preal,
const char *nm) {
IMAGE_THUNK_DATA *td = lookup(dh, nm);
if (td && orig == (void *)td->u1.Function) {
DWORD o;
dbg(" patching %s %p %p -> %p\n", nm, td->u1.Function, orig, hook);
*preal = (void *)td->u1.Function;
CHK(VirtualProtect(td, sizeof(*td), PAGE_EXECUTE_READWRITE, &o));
td->u1.Function = (uintptr_t)hook;
CHK(VirtualProtect(td, sizeof(*td), o, &o));
}
}
void patchInstall(void *orig, void *hook, void **preal, const char *nm) {
HMODULE mod[4096];
DWORD n;
DWORD i;
extern IMAGE_DOS_HEADER __ImageBase;
CHK(EnumProcessModules(GetCurrentProcess(), mod, sizeof(mod), &n));
n /= sizeof(HMODULE);
dbg("orig %s %p\n", nm, orig);
for (i = 0; i < n; i++) {
HMODULE m = mod[i];
char mname[4096];
CHK(GetModuleFileNameA(m, mname, sizeof(mname)));
dbg("module %s\n", mname);
if (m != (HMODULE)&__ImageBase)
modpatch((IMAGE_DOS_HEADER *)m, orig, hook, preal, nm);
}
dbg("modules patched\n");
}
int patchInstalled(DWORD pid) {
static uint8_t pids[0x1000] = {0};
unsigned index = pid >> 2;
unsigned byte = (index >> 3) & 0xfff;
unsigned mask = 1 << (index & 7);
int ret;
EnterCriticalSection(&s_cs);
ret = pids[byte] & mask;
pids[byte] |= mask;
LeaveCriticalSection(&s_cs);
return ret;
}
void patchInit() {
InitializeCriticalSection(&s_cs);
}
void patchTerm() {
DeleteCriticalSection(&s_cs);
}