获取PE文件的输入表信息

输入表是PE文件结构中不可或缺的部分,输入表也称之为"导入表"。

要想了解输入表,首先还得先从DLL文件入手。日常生活中我们会看见一些大型软件有很多的DLL格式的文件,这些文件中有很多的导入函数,这些函数不会直接被执行。当一个程序(EXE)运行时,导入函数是被程序调用执行的,其执行的代码是不在主程序(EXE)中的一小部分函数,其真正的代码却在DLL文件中。这时我们就会想,那么EXE主程序是如何找到这些需要导入的函数呢,这就要归结于“输入表”了,输入表就相当于EXE文件与DLL文件沟通的钥匙,所有的导入函数信息都会写入输入表中,在PE文件映射到内存后,windows将相应的DLL文件装入,EXE文件通过“输入表”找到相应的DLL中的导入函数,从而完成程序的正常运行,这一动态连接的过程都是由“输入表”参与的。

下面以32位PE文件为例,分析如何从PE文件中获取输入表信息。

先看一下PE文件结构,PE文件由DOS首部,PE文件头,块表,块和调试信息组成,有关PE文件的数据结构信息在winnt.h中定义。

输入表的位置和大小可以从PE文件的IMAGE_OPTIONAL_HEADER32结构的数据目录表中获取。数据目录表有16项组成,每一项都是一个IMAGE_DATA_DIRECTORY结构,

其中第二项存放输入表信息,即OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress就是输入表的相对虚拟地址(RVA)

如果在内存中查找输入表,那么将RVA值加上PE文件装入的基址就是实际的地址,如果在PE文件中查找输入表,那么需要将RVA转换成文件偏移。

DWORD ITLibrary::RVA2Offset(PCHAR pImageBase,DWORD dwRVA)
{
    DWORD dwOffset=0;
    int iSections=0;
    PIMAGE_SECTION_HEADER pSection=NULL;

    if(m_dwType==PE_X86)
    {
        iSections=m_pImage_nt_header32->FileHeader.NumberOfSections;
        pSection=(PIMAGE_SECTION_HEADER)((PCHAR)m_pImage_nt_header32 + sizeof(IMAGE_NT_HEADERS32));
    }
    else if(m_dwType==PE_X64)
    {
        iSections=m_pImage_nt_header64->FileHeader.NumberOfSections;
        pSection=(PIMAGE_SECTION_HEADER)((PCHAR)m_pImage_nt_header64 + sizeof(IMAGE_NT_HEADERS64));
    }
    if(m_pImage_section_header==NULL)
    {
        for(int i=0;i<iSections;i++)
        {
            if((pSection->VirtualAddress) && (dwRVA<=(pSection->VirtualAddress+pSection->SizeOfRawData)))
            {
                m_pImage_section_header=pSection;
                break;
            }
            pSection++;
        }
        if(m_pImage_section_header==NULL)
        {
            return 0;
        }
    }

    dwOffset=dwRVA+m_pImage_section_header->PointerToRawData-m_pImage_section_header->VirtualAddress;

    return dwOffset;

}

输入表的地址指向的是IMAGE_IMPORT_DESCRIPTOR结构,输入表由一系列的IMAGE_IMPORT_DESCRIPTOR结构组成,结构的数量取决于程序要使用的DLL文件的数量,每一个结构对应一个DLL文件,在所有这些结构的最后,由一个内容全为0的IMAGE_IMPORT_DESCRIPTOR结构作为结束。

OriginalFirstThunk

指向一个包含一系列IMAGE_THUNK_DATA32结构的数组,数组中的每个IMAGE_THUNK_DATA32结构定义了一个导入函数的信息,数组最后以一个内容为0的IMAGE_THUNK_DATA32结构作为结束。

当 IMAGE_THUNK_DATA32 值的最高位为1时,表示函数以序号方式输入,这时候低31位被看作一个函数序号,可以使用预定义IMAGE_SNAP_BY_ORDINAL32来判断函数是否以序号方式输入。

当 IMAGE_THUNK_DATA32 值的最高位为0时,表示函数以字符串类型的函数名方式输入,这时其值是一个RVA,指向一个IMAGE_IMPORT_BY_NAME 结构。

结构中的 Hint 字段也表示函数的序号,不过这个字段是可选的,有些编译器总是将它设置为 0,Name字段定义了导入函数的名称,这是一个以 0 为结尾的字符串。

Name

它表示DLL 名称的相对虚地址,指向的是该导入DLL文件的名称,如Kernel32.dll

FirstThunk

指向一个包含一系列IMAGE_THUNK_DATA32结构的数组,在PE文件未装入内存时,其指向的信息和OriginalFirstThunk字段指向的信息相同,当PE文件装入内存后,由FirstThunk字段指向的那个数组中的每个双字都被替换成了真正的函数入口地址,

之所以在PE文件中使用两份IMAGE_THUNK_DATA32数组的拷贝并修改其中的一份,是为了最后还可以留下一份拷贝用来反过来查询地址所对应的导入函数名。

在PE文件中,所有DLL对应的导入地址数组是被排列在一起的,全部这些数组的组合也被称为导入地址表(IAT,Import Address Table),输入表中第一个IMAGE_IMPORT_DESCRIPTOR结构的FirstThunk字段指向的就是IAT的起始地址。也可以通过数据目录表的第13项找到IAT数据块的位置和大小。

至此,32位PE文件的输入表分析完毕,对于64位PE文件,获取输入表信息的方法和32位PE文件类似,但64位PE文件和32位PE文件在具体的数据结构字段和类型上有所差别。

最后,奉献上一个完整的获取32PE文件输入表信息和64PE文件输入表信息的程序,运行界面如下:

时间: 2024-10-06 00:23:32

获取PE文件的输入表信息的相关文章

C++ 获取PE文件自校验值的代码

将写代码过程比较重要的一些代码收藏起来,下边资料是关于C++ 获取PE文件自校验值的代码. #include#include <imagehlp.h>#pragma comment(lib,"imagehlp") { char szFileName[] = "d:\newupdate.exe"; DWORD dwCheckSum1,dwCheckSum2; if (MapFileAndCheckSum(szFileName,&dwCheckSum

获取pe文件的文件类型

工程文件petype.cpp通过调用pefile类中的函数获取文件类型. 文件类型的判断通过5个监测点完成. 监测点1:dos头的e_magic 监测点2:nt头的Signature 监测点3:文件头的Characteristics 监测点4:可选头的Magic 监测点5:可选头的Subsystem 通过监测点1和2判断是否是pe文件: 通过监测点3判断文件是否是动态库文件 通过监测点4判断文件是pe32还是pe32+还是rom映像 通过监测点5判断文件是否是0环可执行文件[驱动文件],还是3环

从Windows系统服务获取活动用户的注册表信息(当前活动用户的sessionId. 当前活动用户的 hUserToken)

首先,对“活动用户”的定义是,当前拥有桌面的用户.对于Windows XP及其以后的系统,即使是可以多个用户同时登录了,拥有桌面的也仅仅只有一个. 如果系统级服务调用Windows API来获取注册表键值的时候,直接以HKEY_CURRENT_USER为参数,则取到的并不是活动用户的注册表信息,而是系统用户的注册表信息,即,位于HKEY_LOCAL_MACHINE之下的.那么如何以系统服务的身份获取活动用户(真正的HKEY_CURRENT_USER)之下的注册表信息呢?主要有以下这么几步: 系统

[android] 如何获取media文件的meta data信息

在app开发过程中,经常需要显示media文件的meta data信息,我们如何获取这些信息呢? MediaStore 首先想到的就是MediaStore类了,它为我们提供的丰富的属性,我们只要通过sqlite操作,就能获取这些属性提供的值啦. public static final String[] ItemImageProjection = new String[] { MediaStore.Images.ImageColumns.DISPLAY_NAME, MediaStore.Image

获取pe文件调试符号文件pdb路径

一般如果编译器设置了调试符号文件,则编译后的PE文件中调试字段会包含该路径,在一般的溯源分析中我们可能会注意到: 使用工具:pestudio 如下图,将文件加载进工具后,查看debug字段,可以发现pdb路径.注意:该路径不一定存在... 原文地址:http://blog.51cto.com/antivirusjo/2105150

Sqlserver获取所有数据库名,表信息,字段信息,主键信息,以及表结构等。[转]

--获取所有数据库名: SELECT name FROM master..sysdatabases WHERE name NOT IN ( 'master', 'model', 'msdb', 'tempdb', 'northwind','pubs' ) --获取某数据库的所有表: SELECT name FROM YiDianTongV2..sysobjects Where xtype='U' ORDER BY name --获取所有表名 --XType='U':表示所有用户表; --XTyp

取PE文件的引入表和导出表

直接上代码(这里列出C++和Delphi的代码),Delphi代码中包含导入及导出文件和函数列表,PE结构可参阅资料,很多很详细,需要注意的是,本例中是映射到内存,不是通过PE装载器装入的,所以对于节的RVA地址需要转换成为文件偏移地址. Delphi代码 [delphi] view plaincopy unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Fo

获取Host文件权限 注册表导入

Windows Registry Editor Version 5.00 ;取得文件修改权限 [HKEY_CLASSES_ROOT\*\shell\runas] @="管理员权限" "Icon"="C:\\Windows\\System32\\imageres.dll,102" "NoWorkingDirectory"="" [HKEY_CLASSES_ROOT\*\shell\runas\command]

深入剖析PE文件

不赖猴的笔记,转载请注明出处. 深入剖析PE文件 PE文件是Win32的原生文件格式.每一个Win32可执行文件都遵循PE文件格式.对PE文件格式的了解可以加深你对Win32系统的深入理解. 一.        基本结构. 上图便是PE文件的基本结构.(注意:DOS MZ Header和部分PE header的大小是不变的:DOS stub部分的大小是可变的.) 一个PE文件至少需要两个Section,一个是存放代码,一个存放数据.NT上的PE文件基本上有9个预定义的Section.分别是:.t