c++ - 解析 PE 文件中导入和导出表的 RVA

标签 c++ c winapi

我目前正在编写 PE 解析器/加载器。 我已经使用标准 c 文件 io 成功地将 PE 文件加载到内存中,检索到有效的 DOS 和 PE header (可选 header )以及获得对 PE 部分的访问权限。 我的下一个目标是访问导出表以检索导出的符号。 为此,我使用了存储在索引 0 处的可选 header 数据字典数组中的 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_EXPORTIMAGE_DIRECTORY_ENTRY_IMPORTIMAGE_DIRECTORY_ENTRY_IATIMAGE_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 的部分并找到大于或等于 0 且小于 pNtHdr->FileHeader.NumberOfSectioni,其中

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_DIRECTORY_ENTRY_IMPORT(IMAGE_IMPORT_DESCRIPTOR *) 和对应于 (IMAGE_BOUND_IMPORT_DESCRIPTOR *) >IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 转储包含绑定(bind)信息(如果存在)的导入信息。

要从 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT(对应于 delayimp.h 中定义的 (ImgDelayDescr *))转储信息,您还应该使用来自 IMAGE_DIRECTORY_ENTRY_IAT 的信息(对应于 (IMAGE_THUNK_DATA32 *))。

更多PE推荐给你http://msdn.microsoft.com/en-us/magazine/cc301808.aspx

关于c++ - 解析 PE 文件中导入和导出表的 RVA,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2975639/

相关文章:

c - 当我使用 free() 时,C 中的程序随机崩溃

winapi - 在线程持续时间内更改光标

c++ - WTL 子窗口事件处理

c++ - fatal error LNK1169 : one or more multiply defined symbols found (C++)

c++ - 在 AIX 上使用 ofstream

c - 未设置环境变量,来自 Netbeans

c++ - 重新注册用户定义的窗口类 - C++

c++ - 如果互斥体和数据项在内存中靠近在一起,那么缺点在哪里?

c++ - 为什么会出现段错误(数组作为类的元素)?

c - C 标准库的更安全替代品