在PE文件中解析导入和导出表的RVA

jmg*_*unn 10 c c++ winapi

我目前正在编写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)));
Run Code Online (Sandbox Code Playgroud)

我是否必须使用内存映射IO来正确执行此操作?我在计算地址错了吗?有关PE RVA的信息似乎很少.提前致谢.

Ole*_*leg 13

我从时间打开一个我的老项目,因为我喜欢你检查进口和出口的目录结构(IMAGE_DIRECTORY_ENTRY_EXPORT,IMAGE_DIRECTORY_ENTRY_IMPORT,IMAGE_DIRECTORY_ENTRY_IATIMAGE_DIRECTORY_ENTRY_DELAY_IMPORT).我可以简单地解释你遇到问题的部分.我的意思是如何找到指针的部分,例如IMAGE_EXPORT_DIRECTORY在PE内部.

首先,可以使用读/写文件操作来分析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);
Run Code Online (Sandbox Code Playgroud)

在我们有指向pSrcFilePE文件的指针后,我们可以找到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);
Run Code Online (Sandbox Code Playgroud)

现在我们需要任何目录的虚拟地址.例如,

pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
Run Code Online (Sandbox Code Playgroud)

是导出目录的虚拟地址.之后将虚拟地址转换为内存指针,我们应该找到内部有这个虚拟地址的PE部分.要做到这一点,我们可以列举PE的部分,且找到一个i擦菜板或等于0和小于pNtHdr->FileHeader.NumberOfSectionS其中

pFirstSectionHeader[i].VirtualAddress <= 
pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
Run Code Online (Sandbox Code Playgroud)

同时

pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
< pFirstSectionHeader[i].VirtualAddress + pFirstSectionHeader[i].Misc.VirtualSize
Run Code Online (Sandbox Code Playgroud)

那么你应该在以下部分中搜索导出数据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);
Run Code Online (Sandbox Code Playgroud)

你应该重复找到相同的程序(IMAGE_IMPORT_DESCRIPTOR *)对应于IMAGE_DIRECTORY_ENTRY_IMPORT(IMAGE_BOUND_IMPORT_DESCRIPTOR *)相当于IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT转储导入信息包含绑定信息(如果存在的话).

要转发信息IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT(对应(ImgDelayDescr *)于delayimp.h中定义),您还应使用IMAGE_DIRECTORY_ENTRY_IAT(对应于(IMAGE_THUNK_DATA32 *))的信息.

有关PE的更多信息,我建议你http://msdn.microsoft.com/en-us/magazine/cc301808.aspx


Dan*_*ing 0

并非所有 PE 映像都会有导出目录表。您需要检查可选标头的 Windows 特定的“NumberOfRvaAndSizes”字段。如果它小于或等于IMAGE_DIRECTORY_ENTRY_EXPORT(0),则没有导出目录表(即 处没有任何有效的内容ioh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT])。

请参阅此问题的答案作为示例。