Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 解决RVA';用于在PE文件中导入和导出表的_C++_C_Winapi - Fatal编程技术网

C++ 解决RVA';用于在PE文件中导入和导出表的

C++ 解决RVA';用于在PE文件中导入和导出表的,c++,c,winapi,C++,C,Winapi,我目前正在编写一个PE解析器/加载程序。 我已经使用标准c文件io成功地将PE文件加载到内存中,检索到了有效的DOS和PE头(可选头),并获得了对PE部分的访问权。 我的下一个目标是访问导出表以检索导出的符号。 为此,我使用了存储在索引0处的可选标头数据字典数组中的RVA(我相信它指向导出表),并将该地址添加到加载到程序内存中的PE文件的地址中,然后将其转换为有效的导出表标头。当我这样做时,我会显示空地址和数据。下面是一个小代码片段 // RVA from optional headers da

我目前正在编写一个PE解析器/加载程序。 我已经使用标准c文件io成功地将PE文件加载到内存中,检索到了有效的DOS和PE头(可选头),并获得了对PE部分的访问权。 我的下一个目标是访问导出表以检索导出的符号。 为此,我使用了存储在索引0处的可选标头数据字典数组中的RVA(我相信它指向导出表),并将该地址添加到加载到程序内存中的PE文件的地址中,然后将其转换为有效的导出表标头。当我这样做时,我会显示空地址和数据。下面是一个小代码片段

// 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的信息似乎很少。
提前感谢。

并非所有PE映像都有导出目录表。您需要检查可选标题的Windows特定“NumberOfRVandSizes”字段。如果小于或等于
IMAGE\u DIRECTORY\u ENTRY\u EXPORT
(0),则没有导出目录表(即
ioh->DataDirectory[IMAGE\u DIRECTORY\u ENTRY\u EXPORT]


例如,请参阅的答案。

我打开了一个我以前的项目,当时我像你一样检查了导入和导出目录的结构(
IMAGE\u DIRECTORY\u ENTRY\u export
IMAGE\u DIRECTORY\u ENTRY\u import
IMAGE\u DIRECTORY\u ENTRY\u IAT
IMAGE\u DIRECTORY\u ENTRY\u DELAY\u import
)。我可以简单地解释一下你有问题的部分。我指的是如何找到PE内部的指针,例如
IMAGE\u EXPORT\u目录

首先,可以使用读/写文件操作来分析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.NumberOfSection
s的
i
,其中

pFirstSectionHeader[i].VirtualAddress <= 
pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
您应该重复相同的过程来查找对应于
图像目录条目导入的
(图像导入描述符*)
,以及对应于
图像目录条目导入的
(图像绑定导入描述符*)
,以转储包含绑定信息的导入信息(如果存在)

要从delayimp.h中定义的
(对应于
(imgdelaydscr*)
)中转储信息,您还应使用
图像目录项IAT中的信息(对应于
(图像数据32*)


有关PE的更多信息,我建议您

有一个宏定义用于获取第一节


PIMAGE\u SECTION\u HEADER firstsection=IMAGE\u FIRST\u SECTION(n头)

本SO答案中所指的一组文章可能会有所帮助:为了澄清一下,你能说一下
pbyFile
来自哪里吗?@DebugErr:它与以前使用的
pSrcFile
相同。不需要在内存中读取整个EXE/DLL文件。你可以使用内存映射方法来访问它。我知道了,我是用C#写的,所以我现在有点懒,只需要文件中的地址(pSrcFile在计算时应该是0)。我实现了您的函数,但除了TimeDateStamp字段外,我的其他所有ExportDataDirectory字段看起来都大错特错:(@DebugErr:对不起,我无法调试您的代码。我只能猜测您可能会遇到64位/32位的问题。请参阅我的。我不希望您:)如果找到解决方案,我将再次阅读MSDN文章,我会公布我做错了什么。
pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
< pFirstSectionHeader[i].VirtualAddress + pFirstSectionHeader[i].Misc.VirtualSize
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);