128 lines
4.1 KiB
C
Executable File
128 lines
4.1 KiB
C
Executable File
#include <windows.h>
|
|
#include <winternl.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
|
|
typedef struct _S_LDR_DATA_TABLE_ENTRY {
|
|
LIST_ENTRY InMemoryOrderModuleList;
|
|
LIST_ENTRY InInitializationOrderModuleList;
|
|
LPVOID DllBase;
|
|
LPVOID EntryPoint;
|
|
ULONG SizeOfImage;
|
|
UNICODE_STRING FullDllName;
|
|
UNICODE_STRING BaseDllName;
|
|
} S_LDR_DATA_TABLE_ENTRY;
|
|
|
|
typedef struct _S_PEB_LDR_DATA {
|
|
DWORD Length;
|
|
DWORD Initialized;
|
|
LPVOID SsHandle;
|
|
LIST_ENTRY InLoadOrderModuleList;
|
|
LIST_ENTRY InMemoryOrderModuleList;
|
|
} S_PEB_LDR_DATA;
|
|
|
|
typedef struct _S_PEB {
|
|
BYTE Reserved1[2];
|
|
BYTE BeingDebugged;
|
|
BYTE Reserved2;
|
|
#ifdef _WIN64
|
|
BYTE Reserved3[4];
|
|
#endif
|
|
LPVOID Reserved4[1];
|
|
LPVOID ImageBaseAddress;
|
|
S_PEB_LDR_DATA *Ldr;
|
|
} S_PEB;
|
|
|
|
static inline S_PEB *GetPeb(void) {
|
|
#ifdef _WIN64
|
|
return (S_PEB *)__readgsqword(0x60);
|
|
#else
|
|
return (S_PEB *)__readfsdword(0x30);
|
|
#endif
|
|
}
|
|
|
|
static DWORD StubHash(const char *str) {
|
|
DWORD h = 0x4E67C6A7;
|
|
while (*str) {
|
|
h = ((h << 5) + h) ^ (unsigned char)*str++;
|
|
}
|
|
return h;
|
|
}
|
|
|
|
static DWORD StubHashW(const WCHAR *str, USHORT lenBytes) {
|
|
DWORD h = 0x4E67C6A7;
|
|
const char *raw = (const char *)str;
|
|
for (USHORT i = 0; i < lenBytes; i++) {
|
|
char c = raw[i];
|
|
if (c >= 'a' && c <= 'z') c -= 0x20;
|
|
h = ((h << 5) + h) ^ (unsigned char)c;
|
|
}
|
|
return h;
|
|
}
|
|
|
|
int main(void) {
|
|
printf("=== PEB Module Walk ===\n");
|
|
S_PEB_LDR_DATA *ldr = GetPeb()->Ldr;
|
|
S_LDR_DATA_TABLE_ENTRY *first = (S_LDR_DATA_TABLE_ENTRY *)ldr->InMemoryOrderModuleList.Flink;
|
|
S_LDR_DATA_TABLE_ENTRY *entry = first;
|
|
do {
|
|
if (entry->BaseDllName.Buffer) {
|
|
DWORD h = StubHashW(entry->BaseDllName.Buffer, entry->BaseDllName.Length);
|
|
printf(" Module: %.*S hash=0x%08X base=%p\n",
|
|
entry->BaseDllName.Length / 2, entry->BaseDllName.Buffer,
|
|
h, entry->DllBase);
|
|
}
|
|
entry = (S_LDR_DATA_TABLE_ENTRY *)entry->InMemoryOrderModuleList.Flink;
|
|
} while (entry != first);
|
|
|
|
printf("\n=== Expected Hashes ===\n");
|
|
printf(" FH_KERNEL32 = 0x52B1CB57\n");
|
|
printf(" FH_NTDLL = 0x1EBCC013\n");
|
|
|
|
/* Try to resolve a function */
|
|
LPVOID k32 = NULL;
|
|
LPVOID ntdll = NULL;
|
|
entry = first;
|
|
do {
|
|
if (entry->BaseDllName.Buffer) {
|
|
DWORD h = StubHashW(entry->BaseDllName.Buffer, entry->BaseDllName.Length);
|
|
if (h == 0x52B1CB57) k32 = entry->DllBase;
|
|
if (h == 0x1EBCC013) ntdll = entry->DllBase;
|
|
}
|
|
entry = (S_LDR_DATA_TABLE_ENTRY *)entry->InMemoryOrderModuleList.Flink;
|
|
} while (entry != first);
|
|
|
|
printf("\n=== Resolution ===\n");
|
|
printf(" kernel32 base: %p %s\n", k32, k32 ? "FOUND" : "NOT FOUND!");
|
|
printf(" ntdll base: %p %s\n", ntdll, ntdll ? "FOUND" : "NOT FOUND!");
|
|
|
|
if (k32) {
|
|
/* Try resolving LoadLibraryA by hash */
|
|
LPBYTE base = (LPBYTE)k32;
|
|
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)base;
|
|
PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(base + dos->e_lfanew);
|
|
PIMAGE_EXPORT_DIRECTORY exp = (PIMAGE_EXPORT_DIRECTORY)(
|
|
base + nt->OptionalHeader.DataDirectory[0].VirtualAddress);
|
|
LPDWORD names = (LPDWORD)(base + exp->AddressOfNames);
|
|
int found = 0;
|
|
for (DWORD i = 0; i < exp->NumberOfNames && i < 5; i++) {
|
|
const char *name = (const char *)(base + names[i]);
|
|
DWORD h = StubHash(name);
|
|
if (i < 3) printf(" Export[%d]: %-30s hash=0x%08X\n", i, name, h);
|
|
}
|
|
/* Find LoadLibraryA specifically */
|
|
for (DWORD i = 0; i < exp->NumberOfNames; i++) {
|
|
const char *name = (const char *)(base + names[i]);
|
|
DWORD h = StubHash(name);
|
|
if (h == 0x32B72ABF) {
|
|
printf(" LoadLibraryA: FOUND (hash 0x32B72ABF matched \"%s\")\n", name);
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) printf(" LoadLibraryA: NOT FOUND!\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|