Greetings overflowers,
Almost completed my associates degree in cybersecurity. Trying to manually load imports from a dll that's in byte code. The virtual address and size of PIMAGE_DATA_DIRECTORY shows the correct values. After parsing PIMAGE_IMPORT_DESCRIPTOR, the values don't get parsed correctly.
PIMAGE_NT_HEADERS32 ntHeader = (PIMAGE_NT_HEADERS32)((DWORD)dllFile32 ((PIMAGE_DOS_HEADER)(DWORD)dllFile32)->e_lfanew);
PIMAGE_DATA_DIRECTORY importDir = &NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
if (importDir->VirtualAddress > 0 && importDir->Size > sizeof(IMAGE_IMPORT_DESCRIPTOR))
{
PIMAGE_IMPORT_DESCRIPTOR iid = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)dllFile32 importDir->VirtualAddress);
printf(" VirtualAddress: X\n", importDir->VirtualAddress);
printf(" Size: X\n", importDir->Size);
printf("OriginalFirstThunk: X\n", iid->OriginalFirstThunk);
printf(" TimeDateStamp: X\n", iid->TimeDateStamp);
printf(" ForwarderChain: X\n", iid->ForwarderChain);
}
VirtualAddress: 0000507C - CORRECT
Size: 0000003C - CORRECT
OriginalFirstThunk: 00000000 - INCORRECT
TimeDateStamp: 56413F2E - INCORRECT
ForwarderChain: 74737973 - INCORRECT
CodePudding user response:
In PE Format, the data of each section has two different address. The first is the File Offset
in the file. You can use this address to access the section data in the file when the file is not mapped that is, when PE is in disk. The second is the RVA
(Relative Virtual Address). This address should be used when the OS mapped the PE file into memory.
In your case, you just copy the Dll to a buffer in memory and don't map the section datas to the specified RVA
s. Therefore, you cannot work with RVA
s. Instead, you should use the file offsets.
An utility function to convert the RVA
s to File Offset
s can be written as the following.
UINT RvaToFileOffset(BYTE* baseAddress, UINT rva) {
PIMAGE_NT_HEADERS lpNtHeaders = ImageNtHeader(baseAddress);
PIMAGE_FILE_HEADER lpFileHeader = &lpNtHeaders->FileHeader;
BYTE* lpOptionalHeader = &lpNtHeaders->OptionalHeader;
PIMAGE_SECTION_HEADER lpSections = (PIMAGE_SECTION_HEADER)(lpOptionalHeader lpFileHeader->SizeOfOptionalHeader);
for (int i = 0; i < lpFileHeader->NumberOfSections; i)
{
IMAGE_SECTION_HEADER section = lpSections[i];
if (rva >= section.VirtualAddress && rva <= section.VirtualAddress section.Misc.VirtualSize)
return section.PointerToRawData rva - section.VirtualAddress;
}
return -1; // Invalid RVA
}
Here is a test program.
#include <stdio.h>
#include <windows.h>
#include <ImageHlp.h>
#pragma comment(lib,"imagehlp.lib")
// Helper function to be used for converting RVAs to File Offsets.
UINT RvaToFileOffset(BYTE * base, UINT rva);
int main(int argc, char* argv[]) {
PIMAGE_DOS_HEADER lpDosHeader;
PIMAGE_NT_HEADERS lpNtHeaders;
PIMAGE_OPTIONAL_HEADER lpOptionalHeader;
PIMAGE_IMPORT_DESCRIPTOR lpImportDescriptor;
if (argc != 2)
{
printf("You didn't specified a PE file.\n");
printf("Usage: ImportsParser.exe <Full path of PE File>\n");
return -1;
}
HANDLE hFile = CreateFileA(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return -1;
HANDLE hMemoryMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (!hMemoryMap)
return -2;
PBYTE baseAddress = (PBYTE)MapViewOfFile(hMemoryMap, FILE_MAP_READ, 0, 0, 0);
if (!baseAddress)
return -3;
lpDosHeader = (PIMAGE_DOS_HEADER)baseAddress;
lpNtHeaders = (PIMAGE_NT_HEADERS)(baseAddress lpDosHeader->e_lfanew);
lpOptionalHeader = (PIMAGE_OPTIONAL_HEADER)(&(lpNtHeaders->OptionalHeader));
PIMAGE_DATA_DIRECTORY lpImportDirectoryEntry = &lpOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
lpImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(baseAddress
RvaToFileOffset(baseAddress, lpImportDirectoryEntry->VirtualAddress));
printf(" VirtualAddress: X\n", lpImportDirectoryEntry->VirtualAddress);
printf(" Size: X\n", lpImportDirectoryEntry->Size);
while (lpImportDescriptor->FirstThunk)
{
char* szDllName = baseAddress RvaToFileOffset(baseAddress, lpImportDescriptor->Name);
printf("DLL Name: %s\n", szDllName);
printf("OriginalFirstThunk: X\n", lpImportDescriptor->OriginalFirstThunk);
printf(" TimeDateStamp: X\n", lpImportDescriptor->TimeDateStamp);
printf(" ForwarderChain: X\n", lpImportDescriptor->ForwarderChain);
printf("\n");
lpImportDescriptor ;
}
getchar();
return 0;
}
UINT RvaToFileOffset(BYTE * baseAddress, UINT rva) {
PIMAGE_NT_HEADERS lpNtHeaders = ImageNtHeader(baseAddress);
PIMAGE_FILE_HEADER lpFileHeader = &lpNtHeaders->FileHeader;
BYTE* lpOptionalHeader = &lpNtHeaders->OptionalHeader;
PIMAGE_SECTION_HEADER lpSections = (PIMAGE_SECTION_HEADER)(lpOptionalHeader lpFileHeader->SizeOfOptionalHeader);
for (int i = 0; i < lpFileHeader->NumberOfSections; i)
{
IMAGE_SECTION_HEADER section = lpSections[i];
if (rva >= section.VirtualAddress && rva <= section.VirtualAddress section.Misc.VirtualSize)
return section.PointerToRawData rva - section.VirtualAddress;
}
return -1; // Invalid RVA
}