我正在编写一个PE解析器/加载程序.
我已经使用标准的c文件io,检索到的有效的DOS和PE头(可选标题)成功地将PE文件加载到内存中,并获得了PE的部分的访问.
我的下一个目标是访问导出表以检索导出的符号.
为了做到这一点,我已经使用存储在可选头数据字典数组中的RVA(索引0)(我相信指向导出表),并将该地址添加到加载到程序存储器中的PE文件的地址,然后将其转换为一个有效的导出表头.当我这样做时,我正在打开NULL地址和数据.这里是一个小代码段;
我已经使用标准的c文件io,检索到的有效的DOS和PE头(可选标题)成功地将PE文件加载到内存中,并获得了PE的部分的访问.
我的下一个目标是访问导出表以检索导出的符号.
为了做到这一点,我已经使用存储在可选头数据字典数组中的RVA(索引0)(我相信指向导出表),并将该地址添加到加载到程序存储器中的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,NULL); hMapSrcFile = CreateFileMapping (hSrcFile,PAGE_READONLY,NULL); pSrcFile = (PBYTE) MapViewOfFile (hMapSrcFile,FILE_MAP_READ,0);
在指向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和等于0而不是pNtHdr-> FileHeader.NumberOfSections
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_IRPORT_DESCRIPTOR *)对应于IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT的(IMAGE_IMPORT_DESCRIPTOR *),您应该重复找到与IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT相对应的过程,以转储包含绑定信息(如果存在)的导入信息.
要从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