Reputation: 11
I'm writing a minimal PE loader that parses the export table to locate functions by name, in my hypervisor. However, when I try to retrieve the RVA of a function, the value seems incorrect. Here's the relevant code:
Here is my code:
#include <utils/stdlib.h>
__attribute__((section(".vmm")))
BYTE_PTR GetAssetFromExportedTable(BYTE_PTR physicalBaseAddress, PCHAR assetName) {
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)(physicalBaseAddress);
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
logDebug("Could not find the %s address. Invalid DOS header magic!!!\n", assetName);
return 0;
}
PIMAGE_NT_HEADERS64 pNtHeader = (PIMAGE_NT_HEADERS64)((BYTE_PTR)(pDosHeader) + pDosHeader->e_lfanew);
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
logDebug("Could not find the %s address. Invalid NT header magic!!!\n", assetName);
return 0;
}
PIMAGE_OPTIONAL_HEADER64 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER64)&(pNtHeader->OptionalHeader);
if (pOptionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
logDebug("Could not find the %s address. Invalid OPTIONAL header magic!!!\n", assetName);
return 0;
}
// Retrieve Export Directory
PIMAGE_DATA_DIRECTORY pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
if (pDataDirectory->VirtualAddress == 0) {
return FALSE; // No export directory present
}
PIMAGE_EXPORT_DIRECTORY pExportedDirectory = (PIMAGE_EXPORT_DIRECTORY)((BYTE_PTR)physicalBaseAddress + pDataDirectory->VirtualAddress);
if (pExportedDirectory == 0 || pExportedDirectory->AddressOfNames == 0) {
logDebug("Could not find the %s address. No exported names found.\n", assetName);
return 0;
}
DWORD_PTR pNames = (DWORD_PTR)((BYTE_PTR)physicalBaseAddress + pExportedDirectory->AddressOfNames);
DWORD_PTR pFunctions = (DWORD_PTR)((BYTE_PTR)physicalBaseAddress + pExportedDirectory->AddressOfFunctions);
WORD_PTR pOrdinals = (WORD_PTR)((BYTE_PTR)physicalBaseAddress + pExportedDirectory->AddressOfNameOrdinals);
for (DWORD i = 0; i < pExportedDirectory->NumberOfNames; i++) {
PCHAR pFunctionName = (PCHAR)(physicalBaseAddress + pNames[i]);
logDebug("Name: %s, Ordinal: %x, function RVA: %x\n", pFunctionName, pOrdinals[i], pFunctions[pOrdinals[i]]);
if (strcmp(pFunctionName, assetName)) {
DWORD functionRVA = pFunctions[pOrdinals[i]];
BYTE_PTR functionAddress = (BYTE_PTR)(physicalBaseAddress + functionRVA);
logDebug("Found %s at address: %x\n", assetName, functionAddress);
return functionAddress;
}
}
logDebug("Could not find the %s address in the export table.\n", assetName);
return 0;
}
I compile and run this code on Linux (using QEMU for virtualization), and I notice that the logged function RVA values don't match the "real" RVAs I'm expecting.
Are there any other potential pitfalls in my export table parsing code that could lead to incorrect RVAs?
I compile and run this code on Linux (using QEMU for virtualization), and I notice that the logged function RVA values don't match the "real" RVAs I'm expecting.
Are there any other potential pitfalls in my export table parsing code that could lead to incorrect RVAs?
Upvotes: 1
Views: 13