-
-
Save herrcore/d2de882d3ba84c1256f7adf0952b2ee1 to your computer and use it in GitHub Desktop.
Example PEB walk and parsing NTDLL exports
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# include <stdlib.h> | |
# include <stdio.h> | |
# include <string.h> | |
# include <windows.h> | |
#include <winnt.h> | |
#include <winternl.h> | |
typedef struct _CUSTOM_PEB_LDR_DATA | |
{ | |
ULONG Length; | |
UCHAR Initialized; | |
PVOID SsHandle; | |
LIST_ENTRY InLoadOrderModuleList; | |
LIST_ENTRY InMemoryOrderModuleList; | |
LIST_ENTRY InInitializationOrderModuleList; | |
PVOID EntryInProgress; | |
} CUSTOM_PEB_LDR_DATA, * PCUSTOM_PEB_LDR_DATA; | |
typedef struct _CUSTOM_LDR_DATA_TABLE_ENTRY | |
{ | |
LIST_ENTRY InLoadOrderLinks; | |
LIST_ENTRY InMemoryOrderModuleList; | |
LIST_ENTRY InInitializationOrderModuleList; | |
PVOID DllBase; | |
PVOID EntryPoint; | |
ULONG SizeOfImage; | |
UNICODE_STRING FullDllName; | |
UNICODE_STRING BaseDllName; | |
ULONG Flags; | |
USHORT LoadCount; | |
USHORT TlsIndex; | |
union | |
{ | |
LIST_ENTRY HashLinks; | |
struct | |
{ | |
PVOID SectionPointer; | |
ULONG CheckSum; | |
}; | |
}; | |
union | |
{ | |
ULONG TimeDateStamp; | |
PVOID LoadedImports; | |
}; | |
PVOID EntryPointActivationContext; | |
PVOID PatchInformation; | |
} CUSTOM_LDR_DATA_TABLE_ENTRY, * PCUSTOM_LDR_DATA_TABLE_ENTRY; | |
int main(void) | |
{ | |
#ifdef _WIN64 | |
PPEB pPeb = (PPEB)__readgsqword(0x60); | |
#else | |
PPEB pPeb = (PPEB)__readfsdword(0x30); | |
#endif | |
PCUSTOM_PEB_LDR_DATA pLdr = (PCUSTOM_PEB_LDR_DATA)pPeb->Ldr; | |
LIST_ENTRY* pStart = &pLdr->InLoadOrderModuleList; | |
LIST_ENTRY* pCur = pStart->Flink; | |
DWORD_PTR ntdllBase = 0; | |
while (pCur != pStart) | |
{ | |
PCUSTOM_LDR_DATA_TABLE_ENTRY pModEntry = (PCUSTOM_LDR_DATA_TABLE_ENTRY)pCur; | |
UNICODE_STRING dll = pModEntry->BaseDllName; | |
// Hack - we assume this will match ntdll before any mismatches | |
if(dll.Length == 18 && ((BYTE*)dll.Buffer)[0] == BYTE(0x6e) && ((BYTE*)dll.Buffer)[10] == BYTE(0x2e)) { | |
printf("Found ntdll at base: 0x%p\n", pModEntry->DllBase); | |
ntdllBase = (DWORD_PTR)pModEntry->DllBase; | |
break; | |
} | |
pCur = pCur->Flink; | |
} | |
if (ntdllBase == 0) { | |
return EXIT_FAILURE; | |
} | |
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)ntdllBase; | |
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(ntdllBase + pDosHeader->e_lfanew); | |
PIMAGE_OPTIONAL_HEADER pOptionalHeaders = (PIMAGE_OPTIONAL_HEADER)&pNtHeaders->OptionalHeader; | |
PIMAGE_DATA_DIRECTORY pExportDataDir = (PIMAGE_DATA_DIRECTORY)&pOptionalHeaders->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; | |
PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY)(pExportDataDir->VirtualAddress + ntdllBase); | |
DWORD* pExportNames = (DWORD*)(pExportDir->AddressOfNames + ntdllBase); | |
WORD* pExportOrds = (WORD*)(pExportDir->AddressOfNameOrdinals + ntdllBase); | |
DWORD* pExportFunctions = (DWORD*)(pExportDir->AddressOfFunctions + ntdllBase); | |
for (ULONG i = 0; i < pExportDir->NumberOfNames; i++) | |
{ | |
ULONG CurrentNameRva = pExportNames[i] ; | |
const char* CurrentName = (const char*)(ntdllBase + CurrentNameRva); | |
ULONG CurrentFunctionRva = pExportFunctions[pExportOrds[i]]; | |
if (CurrentFunctionRva >= pExportDataDir->VirtualAddress && CurrentFunctionRva < pExportDataDir->VirtualAddress + pExportDataDir->Size) | |
continue; //we ignore forwarded exports | |
// adjust the ordinal from the name ordinal using the export base | |
printf("%s (%d) -> %x\n", CurrentName, pExportOrds[i] + pExportDir->Base, CurrentFunctionRva); | |
} | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment