从可移植可执行文件中的.idata节打印隐式链接的dll的名称

我试图写一个代码,应该打印出所有导入的DLL在exe文件的名称,通过使用exe文件的.idata节中的IMAGE_IMPORT_DESCRIPTOR结构的“名称”字段,但程序似乎越来越陷入无限循环。 有人可以告诉我如何正确打印名称…

#include<iostream> #include<Windows.h> #include<stdio.h> #include<WinNT.h> int main() { FILE *fp; int i; if((fp = fopen("c:\\Linked List.exe","rb"))==NULL) std::cout<<"unable to open"; IMAGE_DOS_HEADER imdh; fread(&imdh,sizeof(imdh),1,fp); fseek(fp,imdh.e_lfanew,0); IMAGE_NT_HEADERS imnth; fread(&imnth,sizeof(imnth),1,fp); IMAGE_SECTION_HEADER *pimsh; pimsh = (IMAGE_SECTION_HEADER *)malloc(sizeof(IMAGE_SECTION_HEADER) * imnth.FileHeader.NumberOfSections); long t; fread(pimsh,sizeof(IMAGE_SECTION_HEADER),imnth.FileHeader.NumberOfSections,fp); for(i=0;i<imnth.FileHeader.NumberOfSections;i++) { if(!strcmp((char *)pimsh->Name,".idata")) t = pimsh->PointerToRawData; pimsh++; } fseek(fp,t,0); IMAGE_IMPORT_DESCRIPTOR iid; char c; while(1) { fread(&iid,sizeof(iid),1,fp); if(iid.Characteristics == NULL) break; t = ftell(fp); fseek(fp,(long)iid.Name,0); while(c=fgetc(fp)) printf("%c",c); printf("\n"); fseek(fp,t,0); } } 

有几个问题。

  • 您不能假定导入部分被称为“.idata”。 您应该使用IMAGE_OPTIONAL_HEADER.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]找到导入。

  • PE文件中的大部分偏移量都是相对虚拟地址(RVA),而不是文件偏移量。 要将RVA转换为偏移量,需要确定虚拟地址所在的部分,然后根据该部分在文件中的位置计算偏移量。 具体而言, IMAGE_IMPORT_DESCRIPTOR.Name字段包含RVA,而不是文件偏移量。

  • 如果使用内存映射文件而不是文件I / O,则代码会更简单(更快)。

这个MSDN文章解释RVAs,数据目录等。它还包括pedump ,一个具有完整源代码转储PE文件的应用程序,这是一个有用的参考。

mox的答案是正确的,但是我也想添加另一个解决方案 – 将文件加载为图像来读取数据。
使用LoadLibraryEx只需一行代码即可实现。

 Base = LoadLibraryEx("c:\Linked List.exe", 0, DONT_RESOLVE_DLL_REFERENCES); 

这个负载并将您的可执行文件映射为图像,因此不需要打开/读取/映射或将rva转换为原始偏移量。

使用DONT_RESOLVE_DLL_REFERENCES标志图像是未初始化的,所以所有的导入数据都是不变的,并且不会执行入口点代码。 可执行文件只是映射到内存中。

您可以简单地使用Base + Rva来查找导入的dll名称或任何其他类型的PE信息。
使用FreeLibrary(Base)后释放可执行映像