blob: dbadbaf6dc7b9ea044b8509789652175a38f0bf4 [file] [log] [blame]
#include <stdint.h>
#include <string.h>
#include <stdbool.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");
}
bool
patchInstalled(DWORD pid)
{
static uint8_t pids[0x1000] = { 0 };
unsigned index = pid >> 2;
unsigned byte = (index >> 3) & 0xfff;
unsigned mask = 1 << (index & 7);
bool ret;
EnterCriticalSection(&s_cs);
ret = (pids[byte] & mask) != 0;
pids[byte] |= mask;
LeaveCriticalSection(&s_cs);
return ret;
}
void
patchInit()
{
InitializeCriticalSection(&s_cs);
}
void
patchTerm()
{
DeleteCriticalSection(&s_cs);
}