在PE文件中解析导入和导出表的RVA
我目前正在编写PE解析器/加载器。 我已经使用标准c文件io成功地将PE文件加载到内存中,检索有效的DOS和PE标头(可选标头)以及访问PE的部分。 我的下一个目标是获取对Export表的访问权以检索导出的符号。 为此,我使用存储在索引0的可选头数据字典数组中的RVA(我相信指向导出表)并将此地址添加到加载到程序存储器中的PE文件的地址,然后将其转换为有效的导出表头。 当我这样做时,我正在调出NULL地址和数据。 这是一个小代码片段;
// RVA from optional headers data dictionaries array cast to Export directory type IMAGE_EXPORT_DIRECTORY* ied( (IMAGE_EXPORT_DIRECTORY*)((void*) ((unsigned char*)buffer + ioh->DataDirectory[0].VirtualAddress)));
我是否必须使用内存映射IO来正确执行此操作? 我在计算地址错了吗? 有关PE RVA的信息似乎很少。 提前致谢。
我打开了一个旧的项目,因为我喜欢你检查导入和导出目录的结构( IMAGE_DIRECTORY_ENTRY_EXPORT
, IMAGE_DIRECTORY_ENTRY_IMPORT
, IMAGE_DIRECTORY_ENTRY_IAT
和IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
)。 我可以简单地解释你遇到问题的部分。 我的意思是如何在PE内找到指向例如IMAGE_EXPORT_DIRECTORY
的指针。
首先,可以使用读/写文件操作来分析PE文件,但使用文件映射要容易得多,如下所示:
hSrcFile = CreateFile (pszSrcFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); hMapSrcFile = CreateFileMapping (hSrcFile, NULL, PAGE_READONLY, 0, 0, NULL); pSrcFile = (PBYTE) MapViewOfFile (hMapSrcFile, FILE_MAP_READ, 0, 0, 0);
在我们有指向PE文件的指针pSrcFile
之后我们可以找到PE内部的另一个重要位置:
pDosHeader = (IMAGE_DOS_HEADER *)pSrcFile; IMAGE_NT_HEADERS32 *pNtHdr = (IMAGE_NT_HEADERS32 *) ((PBYTE)pDosHeader + pDosHeader->e_lfanew); IMAGE_SECTION_HEADER *pFirstSectionHeader = (IMAGE_SECTION_HEADER *) ((PBYTE)&pNtHdr->OptionalHeader + pNtHdr->FileHeader.SizeOfOptionalHeader);
现在我们需要任何目录的虚拟地址。 例如,
pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
是导出目录的虚拟地址。 之后将虚拟地址转换为内存指针, 我们应该找到内部有这个虚拟地址的PE部分 。 要做到这一点,我们可以枚举PE的各个部分并找到一个i
grater或等于0
且小于pNtHdr->FileHeader.NumberOfSection
s其中
pFirstSectionHeader[i].VirtualAddress <= pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
同时
pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress < pFirstSectionHeader[i].VirtualAddress + pFirstSectionHeader[i].Misc.VirtualSize
那么你应该在pFirstSectionHeader[i]
部分搜索导出数据:
IMAGE_SECTION_HEADER *pSectionHeader = &pFirstSectionHeader[i]; IMAGE_EXPORT_DIRECTORY *pExportDirectory = (IMAGE_EXPORT_DIRECTORY *)((PBYTE)pbyFile + pSectionHeader->PointerToRawData + pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress - pSectionHeader->VirtualAddress);
您应该重复查找的相同程序(IMAGE_IMPORT_DESCRIPTOR *)
对应于IMAGE_DIRECTORY_ENTRY_IMPORT
和(IMAGE_BOUND_IMPORT_DESCRIPTOR *)
,对应于IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
以转储包含绑定信息(如果存在)的导入信息。
要从IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
转储信息(对应于(ImgDelayDescr *)
定义的(ImgDelayDescr *)
),您还应使用IMAGE_DIRECTORY_ENTRY_IAT
信息(对应于(IMAGE_THUNK_DATA32 *)
)。
有关PE的更多信息,我建议你http://msdn.microsoft.com/en-us/magazine/cc301808.aspx
并非所有PE映像都具有导出目录表。 您需要检查可选标头的Windows特定“NumberOfRvaAndSizes”字段。 如果它小于或等于IMAGE_DIRECTORY_ENTRY_EXPORT
(0),则没有导出目录表(即,在ioh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
没有任何有效的位置)。
有关示例,请参阅此问题的答案。
有宏定义获得第一部分
PIMAGE_SECTION_HEADER FisrtSection = IMAGE_FIRST_SECTION(NtHeaders)