输入表
计算机术语
输入表是PE(Portable Executable File Format)文件结构中不可或缺的部分,输入表也被称之为“导入表”。可执行文件使用来自于其他 Dll 的代码或数据时,称为输入。输入表就相当于 EXE文件与 DLL文件沟通的钥匙,形象的可以比喻成两个城市之间交流的高速公路,所有的导入函数信息都会写入输入表中,在 PE 文件映射到内存后,Windows 将相应的 DLL文件装入,EXE 文件通过“输入表”找到相应的 DLL 中的导入函数,从而完成程序的正常运行,这一动态连接的过程都是由“输入表”参与的。
简介
要想了解输入表,首先还得先从DLL文件入手。日常生活中我们会看见一些大型软件有很多的DLL格式的文件,它们是“动态链接库文件”,这些文件中有很多的导入函数,这些函数不会直接被执行,当一个程序(EXE)运行时,导入函数是被程序调用执行的,其执行的代码是不在主程序(EXE)中的一小部分函数,其真正的代码却在DLL文件中。这时我们就会想,那么EXE主程序是如何找到这些需要导入的函数呢,这就要归结于“输入表”了,输入表就相当于EXE文件与DLL文件沟通的钥匙,形象的可以比喻成两个城市之间交流的高速公路,所有的导入函数信息都会写入输入表中,在PE文件映射到内存后,windows将相应的DLL文件装入,EXE文件通过“输入表”找到相应的DLL中的导入函数,从而完成程序的正常运行,这一动态连接的过程都是由“输入表”参与的。
PE文件
PE(Portable Executable)文件格式是微软制定的一种文件标准, 它是从普遍运用于 UNIX 操作系统的 COFF(Common ObjectFile Format)发展而来, 在 Windows 操作系统中扮演着非常重要的角色, 其格式中的数据结构通常定义在 WINNT.H 中。 本文试图对 PE 的格式及其最新扩展进行分析 , 以便能较好地去理解Windows 操作系统以及目前微软的最新的开发平台.Net。
PE 文件格式是一种文件组织的方式,里面除了程序运行的代码和数据外,还有一些文件相关的重要信息,如文件由磁盘装载到内存中的起始地址、程序执行的入口地址、调用 DLL 动态链接库函数地址等。PE 文件主要由 DOS M Z H eader(DOS头)、DOS Stub (DOS 块)、PE H eader (PE 头)、SectionTable(节表)、Sections(各个节)五部分组成。DOS M Z header 和 DOS stub 称为 DOS 部分。紧随 DOS stub 的是 PE 头,其中包含 PE 装载器用到的许多重要数据。PE 头后面是节表,包含了指向各个节的数据信息。各个节存放了 PE 文件的代码、数据和资源等内容。
结构
输入函数
输入函数,表示被程序调用但是它的代码不在程序代码中的,而在dll中的函数。对于这些函数,磁盘上的可执行文件只是保留相关的函数信息,如函数名,dll文件名等。在程序运行前,程序是没有保存这些函数在内存中的地址。当程序运行起来时,windows加载器会把相关的dll装入内存,并且将输入函数的指令与函数真在内存中正的地址联系起来。输入表(导入表)就是用来保存这些函数的信息的。
Data Directory
在IMAGE_OPTIONAL_HEADER 中的 DataDirectory[16] 数组保存了 输入表的RVA跟大小。通过RVA可以在OD中加载程序通过 ImageBase+RVA 找到 输入表,或者通过RVA计算出文件偏移地址,查看磁盘中的可执行文件,通过文件偏移地址找到输入表。
输入表是以一个IMAGE_IMPORT_DESCRIPTOR(IID)数组 开始的,每一个被PE文件隐式的链接进来的dll都有一个IID,IID数组的最后一个单元用NULL表示。
IMAGE_IMPORT_DESCRIPTOR 结构:
其中Name是dll名字的指针。OriginalFirstThunk指向一个IMAGE_THUNK_DATA数组叫做输入名称表Import Name Table(INT),用来保存函数,FirstThunk也指向IMAGE_THUNK_DATA数组叫做输入地址表Import Address Table(IAT)。
IMAGE_THUNK_DATA 结构:
当IMAGE_THUNK_DATA 的值最高位为1时,表示函数是以序号方式输入,这时低31为被当作函数序号。当最高位是0时,表示函数是以字符串类型的函数名方式输入的,这时,IMAGE_THUNK_DATA 的值为指向IMAGE_IMPORT_BY_NAME 的结构的RVA。
Hint 表示这个函数在其所驻留dll的输出表的序号,不是必须的。
Name 表示 函数名,是一个ASCII字符串以0结尾,大小不固定。
INT保存的是这个程序导入这个dll中函数信息,它是固定的不会被修改。但是IAT会在程序加载时被重写,当程序加载时,它会被PE加载器重写成 这些函数的在内存中的真正地址。即把它原来指向的IMAGE_IMPORT_BY_NAME 改成 函数真正的地址。
要两个 IMAGE_THUNK_DATA
数组的原因
当程序加载时,IAT 会被PE加载器重写,PE加载器先搜索INT,PE加载器迭代搜索INT数组中的每个指针,找出 INT所指向的IMAGE_IMPORT_BY_NAME结构中的函数在内存中的真正的地址,并把它替代原来IAT中的值。当完成后,INT就没有用了,程序只需要IAT就可以正常运行了。
看下面图,这个是可执行程序在磁盘中的时候:
这个是当程序被加载的是后:
实例分析
先找到输入表RVA,通过IMAGE_OPTIONAL_HEADER 中的最后一个项 IMAGE_DATA_DIRECTORY 可以知道 输入表相对与PE文件头的偏移量为80h可以找到输入表达RVA。
图片1
但这个是RVA不是文件偏移地址。通过转换可以知道,输入表的文件偏移地址为850h,
查看850h,即IID,可以看到这个程序有两个IID,即链接了 两个dll,看到一个IID,可以知道它的OriginalFirstThunk 是 2098h FirstThunk 为200Ch,它们转换后的文件偏移地址分别为898h 和 80Ch
图片2 IID数组
查看OriginalFirstThunk跟FirstThunk ,可以发现这里INT跟IAT的内容是一样的,先看看第一个函数的信息,因为第一位为1,所以这里00002122h 表示 IMAGE_IMPORT_BY_NAME 的RVA,转化为文件偏移值为922h
图片3 INT跟IAT
查看922h 可以看函数名。
图片4:
我们可以从上面看到程序在磁盘中时 INT 与IAT内容一样,都是指向 IMAGE_IMPORT_BY_NAME 。用OD加载程序,查看INT与IAT的内容
图片5 INT
图片6 IAT
可以发现INT没有发生变化,IAT变成了例如77D3C702h,IAT中的RVA被改成了函数的真正的地址。
查看77D3C702h,就可以看到这个函数
图片7
参考资料
PE文件格式剖析.中国知网.2004-03-28
PE 文件结构分析和构建.中国知网.2014-06-15
最新修订时间:2024-11-25 15:43
目录
概述
简介
参考资料