【问题标题】:Printing out the names of implicitly linked dll's from .idata section in a portable executable从可移植可执行文件的 .idata 部分打印出隐式链接 dll 的名称
【发布时间】:2012-03-11 15:16:00
【问题描述】:

我正在尝试编写一个代码,该代码应该使用 exe 的 .idata 部分中的 IMAGE_IMPORT_DESCRIPTOR 结构的“名称”字段打印出 exe 中所有导入的 dll 的名称,但程序似乎陷入无限循环。谁能告诉我如何正确打印出名字...

    #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);

        }
    }

【问题讨论】:

    标签: windows executable exe portable-executable


    【解决方案1】:

    有几个问题。

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

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

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

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

    【讨论】:

    • msdn.microsoft.com/en-us/library/ms809762.aspx 本文说“.idata 部分(或导入表)以 IMAGE_IMPORT_DESCRIPTOR 数组开头。”,如果您向下滚动到“PE 文件导入”部分,第二段。
    • @user1232138:那篇文章还指出,Borland 链接器不使用标准的节名称。
    • 关于部分名称:它们甚至不必有名字!在开发我自己的 PE 分析工具 (PeStudio) 时,我遇到过一些 PE 二进制文件的部分名称确实以不可打印字符开头的情况,或者具有名为“.idata”的代码部分等......对于部分名称没有固定规则!唯一的规则是:为他们的名字保留的位置由 8 个字节组成。
    【解决方案2】:

    mox 的答案在所有方面都是正确的,但是我还想添加另一个解决方案 - 将文件加载为图像以读取数据。
    使用LoadLibraryEx 只需一行代码即可非常简单地实现这一点。

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

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

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

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

    释放可执行映像

    【讨论】:

    • 根据msdn.microsoft.com/en-us/library/windows/desktop/…: "...不要使用这个值;它只是为了向后兼容而提供的。如果您打算只访问 DLL 中的数据或资源,请使用 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 或 LOAD_LIBRARY_AS_IMAGE_RESOURCE或两者兼有。否则,使用 LoadLibrary 函数将库作为 DLL 或可执行模块加载。"
    • 这要简单得多,但它会将您限制为 32 位或 64 位 DLL(取决于您的进程的风格)。
    • @mox:是的,DONT_RESOLVE_DLL_REFERENCES 适用于所有系统,因为它向后兼容,但直到 Vista 才支持 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 和 LOAD_LIBRARY_AS_IMAGE_RESOURCE 标志。
    猜你喜欢
    • 1970-01-01
    • 2014-09-19
    • 1970-01-01
    • 2013-09-26
    • 2013-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多