#include #include #include #include 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; }