#include <Windows.h>
#include <winternl.h>
#include <stdio.h>
#include <wchar.h>
PIMAGE_DOS_HEADER GetBaseAddress(const wchar_t *moduleName)
{
PLDR_DATA_TABLE_ENTRY orgPtr = nullptr;
PLDR_DATA_TABLE_ENTRY curPtr = nullptr;
wchar_t *foundDllName = nullptr;
__asm
{
mov eax, fs:[0x18] // TIB
mov eax, [eax + 0x30] // TIB->PEB
mov eax, [eax + 0x0C] // PEB->Ldr
lea ebx, [eax + 0x1C] // Ldr->InInitializationOrderLinks
mov orgPtr, ebx
loadOrderLoop :
mov edx, [ebx] // InInitializationOrderLinks->Flink
mov curPtr, edx
mov edx, [edx + 0x20] // LDR_DATA_TABLE_ENTRY.BaseDllName.Buffer
test edx, edx
je loadOrderFailed
mov foundDllName, edx
}
if(!_wcsicmp(foundDllName, moduleName))
return (PIMAGE_DOS_HEADER)curPtr->InMemoryOrderLinks.Flink; // -0x10, as used InInitializationOrderLinks
__asm{
loadOrderFailed :
mov ebx, curPtr
mov ebx, [ebx]
mov edx, orgPtr
cmp ebx, edx
jne loadOrderLoop
}
return nullptr;
}
int main()
{
// 1. Get Base Address of ntdll.dll
PIMAGE_DOS_HEADER ntdllBase = GetBaseAddress(L"ntdll.dll");
if (ntdllBase == nullptr) {
printf("[-] Failed to get ntdll.dll base address\n");
return -1;
}
printf("[+] ntdll.dll : 0x%08x\n", (DWORD)ntdllBase);
// 2. Parse Module - IMAGE_NT_HEADERS
PIMAGE_NT_HEADERS peSignature = (PIMAGE_NT_HEADERS)((PBYTE)ntdllBase + ntdllBase->e_lfanew);
if (peSignature->Signature != 'EP') {
printf("[-] Failed to find PE Signature\n");
return -1;
}
printf("[+] PE Signature : 0x%08x\n", (DWORD)peSignature);
// 3. Parse Module - Export Table
PIMAGE_EXPORT_DIRECTORY pIED = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)ntdllBase + peSignature->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
DWORD sizeofIED = peSignature->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
printf("[+] Export Table : 0x%08x, Size : 0x%08x\n", (DWORD)pIED, sizeofIED);
// 4. Find LdrGetProcedureAddress Function
PDWORD funcAddresses = (PDWORD)((PBYTE)ntdllBase + pIED->AddressOfFunctions);
PDWORD funcNames = (PDWORD)((PBYTE)ntdllBase + pIED->AddressOfNames);
PWORD funcOrdinals = (PWORD)((PBYTE)ntdllBase + pIED->AddressOfNameOrdinals);
void(__stdcall *pLdrGetProcedureAddress)(HMODULE, PANSI_STRING, DWORD, PVOID) = nullptr;
for (unsigned int i = 0; i < pIED->NumberOfFunctions; i++)
{
if (!strcmp("LdrGetProcedureAddress", (char *)((PBYTE)ntdllBase + funcNames[i])))
{
pLdrGetProcedureAddress = (void(__stdcall *)(HMODULE, PANSI_STRING, DWORD, PVOID))((PBYTE)ntdllBase + funcAddresses[funcOrdinals[i]]);
break;
}
}
if (pLdrGetProcedureAddress == nullptr)
{
printf("[-] Failed to find LdrGetProcedureAddress\n");
return -1;
}
printf("[+] LdrGetProcedureAddress : 0x%08x\n", (DWORD)pLdrGetProcedureAddress);
// 5. Find Functions With LdrGetProcedureAddress
HMODULE hKernel32 = (HMODULE)GetBaseAddress(L"kernel32.dll");
if (hKernel32 == nullptr)
{
printf("[-] Can't find kernel32.dll\n");
return -1;
}
printf("[+] kernel32.dll : 0x%08x\n", (DWORD)hKernel32);
ANSI_STRING targetFunction;
RtlInitAnsiString(&targetFunction, "CreateFileA");
HANDLE(__stdcall *pCreateFileA)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE) = nullptr;
pLdrGetProcedureAddress(hKernel32, &targetFunction, 0, &pCreateFileA);
printf("[+] CreateFileA : 0x%p\n", pCreateFileA);
RtlInitAnsiString(&targetFunction, "WriteFile");
BOOL(__stdcall *pWriteFile)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED) = nullptr;
pLdrGetProcedureAddress(hKernel32, &targetFunction, 0, &pWriteFile);
printf("[+] WriteFile : 0x%p\n", pWriteFile);
RtlInitAnsiString(&targetFunction, "CloseHandle");
BOOL(__stdcall *pCloseHandle)(HANDLE) = nullptr;
pLdrGetProcedureAddress(hKernel32, &targetFunction, 0, &pCloseHandle);
printf("[+] CloseHandle : 0x%p\n", pCloseHandle);
// 6. Use Functions
DWORD Length = 0;
HANDLE hFile = pCreateFileA("Test.txt", GENERIC_ALL, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
pWriteFile(hFile, "PEB Test String", 15, &Length, NULL);
pCloseHandle(hFile);
return 0;
}