Skip to content

Instantly share code, notes, and snippets.

@herrcore
Created May 24, 2023 22:35
Show Gist options
  • Save herrcore/d2de882d3ba84c1256f7adf0952b2ee1 to your computer and use it in GitHub Desktop.
Save herrcore/d2de882d3ba84c1256f7adf0952b2ee1 to your computer and use it in GitHub Desktop.
Example PEB walk and parsing NTDLL exports
# 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