導出表是數據目錄中的第一張表,要注意 VirtualAddress 是內存偏移。導出表中的三張表地址也是內存偏移。
代碼
// 打印導出表
VOID PrintExportTable(LPVOID pFileBuffer)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pFileBuffer + 4);
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));
PIMAGE_SECTION_HEADER pSectionHeader = \
(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
PIMAGE_EXPORT_DIRECTORY pExportDirectory = \
(PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer + RvaToFoa(pFileBuffer, pOptionHeader->DataDirectory[0].VirtualAddress));
printf("Base = %x\n", pExportDirectory->Base);
printf("NumberOfFunctions = %x\n", pExportDirectory->NumberOfFunctions);
printf("NumberOfNames = %x\n", pExportDirectory->NumberOfNames);
printf("----AddressOfFunctions----\n");
PDWORD AddressOfFunctions = (PDWORD)((DWORD)pFileBuffer + RvaToFoa(pFileBuffer, pExportDirectory->AddressOfFunctions));
for (int i = 0; i < pExportDirectory->NumberOfFunctions; i++)
{
printf("AddressOfFunctions[%d] = %x\n", i, AddressOfFunctions[i]);
}
printf("----AddressOfNames & AddressOfNameOridinals----\n");
PDWORD AddressOfNames = (PDWORD)((DWORD)pFileBuffer + RvaToFoa(pFileBuffer, pExportDirectory->AddressOfNames));
PWORD AddressOfNameOridinals = (PWORD)((DWORD)pFileBuffer + RvaToFoa(pFileBuffer, pExportDirectory->AddressOfNameOrdinals));
for (i = 0; i < pExportDirectory->NumberOfNames; i++)
{
printf("AddressOfNames[%d] = %s, AddressOfOrdinals[%d] = %d\n",
i, (char*)((DWORD)pFileBuffer + RvaToFoa(pFileBuffer, AddressOfNames[i])), i, AddressOfNameOridinals[i]);
}
}
VOID TestPrintExportTable(LPSTR lpszFile)
{
LPVOID pFileBuffer = NULL;
if (!ReadPEFile(lpszFile, &pFileBuffer))
{
printf("讀取文件失敗");
return;
}
PrintExportTable(pFileBuffer);
free(pFileBuffer);
}
// 內存偏移RVA轉成文件偏移FOA
// 返回轉換後FOA的值,找不到則返回0
DWORD RvaToFoa(IN LPVOID pFileBuffer,IN DWORD dwRva)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pFileBuffer + 4);
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));
PIMAGE_SECTION_HEADER pSectionHeader = \
(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
// RVA在文件頭中或者文件對齊==內存對齊時,RVA==FOA
if (dwRva < pOptionHeader->SizeOfHeaders || \
pOptionHeader->SectionAlignment == pOptionHeader->FileAlignment)
{
return dwRva;
}
// 遍歷節表,確定偏移屬於哪一個節
for (int i = 0; i < pPEHeader->NumberOfSections; i++)
{
if (dwRva >= pSectionHeader[i].VirtualAddress && \
dwRva < pSectionHeader[i].VirtualAddress + pSectionHeader[i].Misc.VirtualSize)
{
int offset = dwRva - pSectionHeader[i].VirtualAddress;
return pSectionHeader[i].PointerToRawData + offset;
}
}
printf("找不到RVA %x 對應的 FOA,轉換失敗\n", dwRva);
return 0;
}
運行結果
用 DEPENDENCY WALKER 驗證,解析正確。
附DLL的def導出文件