PE结构详解(64位和32位的差别)(4)

2019-02-14 22:52

导入查找表是由长度为32位(PE32)或64位(PE32+)的数字组成的数组。其中的每一个元素都是位域,其格式如下表所示。在这种格式中,位31(PE32)或位63(PE32+)是最高位。这些项描述了从给定的DLL导入的所有函数。最后一个项被设置为0(NULL),用来指明表的结尾。

大偏移 小 Ordinal/Name 如果这个位为1,说明是通过序数导入的。否则是通过名称导入的。测试这个位的掩码为Flag Ordinal Number Hint/Name Table RVA 0x80000000(PE32)或)0x8000000000000000(PE32+)。 序数值(16位长)。只有当Ordinal/Name Flag域为1(即通过序数导入)时才使用这个域。位30-15(PE32)或62-15(PE32+)必须为0。 提示/名称表项的RVA(31位长)。只有当Ordinal/Name Flag域为0(即通过名称导入)时才使用这个域。对于PE32+来说,位62-31必须为0。 位域 描述 31/63 1 15-0 16 30-0 31 5.2.3 提示/名称表 提示/名称表中的每一个元素结构如下: 偏移 大小 域 描述 指出名称指针表的索引。当搜索匹配字符串时首选使用这个值。如果匹配失败,再在DLL的导出名称指针表0 2 Hint 中进行2进制搜索。 包含导入函数名称的ASCII码字符串。这个字符串必须与DLL导出的函数名称匹配。同时这个字符串区分大2 可变 Name 0或1 小写并且以NULL结尾。 * Pad 为了让提示/名称表的下一个元素出现在偶数地址,这里可能需要填充0个或1个NULL字节。 5.2.4 导入地址表 导入地址表的结构和内容与导入查找表完全一样,直到文件被绑定。在绑定过程中,用导入函数的32位(PE32)或64位(PE32+)地址覆盖导入地址表中的相应项。这些地址是导入函数的实际内存地址,尽管技术上仍把它们称为“虚拟地址”。加载器通常会处理绑定。 5.3 .pdata节(可有可无,谁也不希望自己的函数出问题的吧!) .pdata节是由用于异常处理的函数表项组成的数组。NT头中的Exception Table(异常表)域指向它。在将它们放进最终的镜像文件之前,这些项必须按函数地址(下列每个结构的第一个域)排序。下面描述了函数表项的3种格式,使用哪一种取决于目标平台。 对于32位的MIPS镜像来说,其函数表项格式如下: 偏移 大小 域 描述 0 4 8 12 16 4 4 4 4 4 Begin Address End Address Exception Handler Handler Data Prolog End Address 相应函数的VA 函数结尾的VA 指向要执行的异常处理程序的指针 指向要传递给异常处理程序的附加数据的指针 函数prolog代码结尾的VA 对于ARM、PowerPC、SH3和SH4 Windows CE平台来说,其函数表项格式如下:

偏移 大小 0 4 4 4 4 4 域 Begin Address 相应函数的VA 函数prolog代码包含的指令数 函数代码包含的指令数 描述 8位 Prolog Length 22位 Function Length 1位 32-bit Flag 1位 Exception Flag 如果此位为1,表明函数由32位指令组成。否则,函数由16位指令组成。 如果此位为1,表明存在用于此函数的异常处理程序;否则,不存在异常处理程序。 对于x64和Itanium平台来说,其函数表项格式如下:

偏移 大小 0 4 8 4 4 4 域 Begin Address End Address 相应函数的RVA 函数结尾的RVA 描述 Unwind Information 用于异常处理的展开(Unwind)信息的RVA 5.4 .reloc节 基址重定位表包含了镜像中所有需要重定位的内容。NT头中的数据目录中的Base Relocation Table(基址重定位表)域给出了基址重定位表所占的字节数。基址重定位表被划分成许多块,每一块表示一个4K页面范围内的基址重定位信息,它必须从32位边界开始。 5.4.1 基址重定位块 每个基址重定位块的开头都是如下结构: 偏移 大域 小 Page RVA Block Size 将镜像基址与这个域(页面RVA)的和加到每个偏移地址处最终形成一个VA,这个VA就是要进行基址重定位的地方。 描述 0 4 4 4 基址重定位块所占的总字节数,其中包括Page RVA域和Block Size域以及跟在它们后面的Type/Offset域。 Block Size域后面跟着数目不定的Type/Offset位域。它们中的每一个都是一个WORD(2字节),其结构如下:

偏移 0 0 大小 域 描述 4位 Type 它占这个WORD的最高4位,这个值指出需要应用的基址重定位类型。参考5.4.2节“基址重定位类型”。 它占这个WORD的其余12位,这个值是从基址重定位块的Page RVA域指定的地址处开始的偏移。这个12位 Offset 偏移指出需要进行基址重定位的位置。 为了进行基址重定位,需要计算镜像的首选基地址与实际被加载到的基地址之差。如果镜像本身就被加载到了其首选基地址,那么这个差为零,因此也就不需要进行基址重定位了。 5.4.2 基址重定位类型 值 0 基址重定位被忽略。这种类型可以用来对其它块进行填充。 1 基址重定位时将差值的高16位加到指定偏移处的一个16位域上。这个16位域是一个32位字的高半部分。 2 基址重定位时将差值的低16位加到指定偏移处的一个16位域上。这个16位域是一个32位字的低半部分。 3 基址重定位时将所有的32位差值加到指定偏移处的一个32位域上。 4 描述 进行基址重定位时将差值的高16位加到指定偏移处的一个16位域上。这个16位域是一个32位字的高半部分,而这个32位字的低半部分被存储在紧跟位域后面的一个16位字中。也就是说,这一个基址重定位项占了两个Type/Offset位域的位置。 5 对MIPS平台的跳转指令进行基址重定位。 6 保留,必须为0 7 保留,必须为0 9 对MIPS16平台的跳转指令进行基址重定位。 10 进行基址重定位时将差值加到指定偏移处的一。 5.5 加载配置结构(不清楚,大概又是多余的吧) 加载配置结构最初用于Windows NT操作系统自身几种非常有限的场合——在镜像文件头或NT头中描述各种特性太困难或这些信息尺寸太大。当前版本的Microsoft链接器和Windows XP以及后续版本的Windows使用的是这个结构的新版本,将之用于包含保留的SEH技术的基于x86的32位系统上。它提供了一个安全的结构化异常处理程序列表,操作系统在进行异常派送时要用到这些异常处理程序。如果异常处理程序的地址在镜像的VA范围之内,并且镜像被标记为支持保留的SEH,那么这个异常处理程序必须在镜像的已知安全异常处理程序列表中,否则操作系统将终止这个应用程序。这是为了防止利用“x86异常处理程序劫持”来控制操作系统,它在以前已经被利用过。 Microsoft的链接器自动提供一个默认的加载配置结构来包含保留的SEH数据。如果用户的代码已经提供了一个加载配置结构,那么它必须包含新添加的保留的SEH域。否则,链接器将不能包含保留的SEH数据,这样镜像文件就不能被标记为包含保留的SEH。 5.5.1 加载配置目录 对应于预保留的SEH加载配置结构的数据目录项必须为加载配置结构指定一个特别的大小,因为操作系统加载器总是希望它为这样一个特定值。事实上,这个大小只是用于检查这个结构的版本。为了与Windows XP以及以前版本的Windows兼容,x86镜像文件中这个结构的大小必须为64。

5.5.2 加载配置结构布局

用于32位和64位PE文件的加载配置结构布局如下:

偏移 0 4 8 10 12 16 20 24 32 40 48 56 64 大小 域 4 4 2 2 4 4 4 8 8 8 8 8 8 Characteristics TimeDateStamp MajorVersion MinorVersion GlobalFlagsClear GlobalFlagsSet 描述 指示文件属性的标志,当前未用。 日期/时间戳。这个值表示从UTC时间1970年1月1日午夜(00:00:00)以来经过的总秒数,它是根据系统时钟算出的。可以用C运行时函数time来获取这个时间戳。 主版本号 次版本号 当加载器启动进程时,需要被清除的全局加载器标志。 当加载器启动进程时,需要被设置的全局加载器标志。 CriticalSectionDefaultTimeout 用于这个进程处于无约束状态的临界区的默认超时值。 DeCommitFreeBlockThreshold 返回到系统之前必须释放的内存数量(以字节计)。 DeCommitTotalFreeThreshold 空闲内存总量(以字节计)。 [仅适用于x86平台]这是一个地址列表的VA。这个地址列表中保存的是使用LOCKLockPrefixTable MaximumAllocationSize VirtualMemoryThreshold ProcessAffinityMask 前缀的指令的地址,这样便于在单处理器机器上将这些LOCK前缀替换为NOP指令。 最大的分配粒度(以字节计)。 最大的虚拟内存大小(以字节计)。 将这个域设置为非零值等效于在进程启动时将这个设定的值作为参数去调用SetProcessAffinityMask函数(仅适用于.exe文件)。 进程堆的标志,相当于函数的第一个参数。这些标志用于在进程启动过程中创建的72 76 78 80 4 2 2 8 ProcessHeapFlags CSDVersion Reserved EditList SecurityCookie SEHandlerTable SEHandlerCount 堆。 Service Pack版本标识。 必须为0 保留,供系统使用。 指向cookie的指针。cookie由Visual C++编译器的GS实现所使用。 [仅适用于x86平台]这是一个地址列表的VA。这个地址列表中保存的是镜像中每60/88 4/8 64/96 4/8 68/104 4/8 个合法的、独一无二的SE处理程序的RVA,并且它们已经按RVA排序。 [仅适用于x86平台]表中独一无二的SE处理程序的数目。 5.6 .rsrc节 资源节可以看成是一个磁盘的分区,盘符是资源目录表,下面有3层目录(资源目录项),最后是文件(资源数据)。 ①资源目录表是一个16字节组成的结构。其第一个字节又称为“根节点”。其前的12字节虽然有定义,但加载器并不理会,所以任何值都可以。

②第1层目录(资源目录项)是资源类型,微软已经定义了21种。其结构是一个16字节的数组。资源目录项分为名称项和ID项,这取决于资源目录表。资源目录表指出跟着它的名称项和ID项各有多少个(表中所有的名称项在所有的ID项前面)。表中的所有项按升序排列:名称项是按不区分大小写的字符串,而ID项则是按数值。第0-3字节表示资源类型的名称字符串的地址或是32位整数,第4-7字节表示第二层目录(资源目录项)相对于根节点的偏移。

一系列资源目录表按如下方式与各层相联系:每个目录表后面跟着一系列目录项,它们给出那个层(类型、名称或语言)的名称或标识(ID)及其数据描述或另一个目录表的地址。如果这个地址指向一个数据描述,那么那个数据就是这棵树的叶子。如果这个地址指向另一个目录表,那么那个目录表列出了下一层的目录项。

一个叶子的类型、名称和语言ID由从目录表到这个叶子的路径决定。第1个表决定类型ID,第2个表(由第一个表中的目录项指向)决定名称ID,第3个表决定语言ID。 .rsrc节的一般结构如下:

数描述 据 资源所有的顶层(类型)结点都被列于第1个表中。这个表中的项指向第2层表。每个第2层树的类型ID相同但是名称ID不同。目第3层树的类型ID和名称ID都相同但语言ID不同。每个单个的表后面紧跟着目录项,每一项都有一个名称或数字标识和录一个指向数据描述或下一层表的指针。 表 资源目 录项 资源目录按2字节边界对齐的Unicode字符串,它是作为由资源目录项指向的字符串数据来使用的。 字符串 资源数一个由记录组成的数组,由表指向它,描述了资源数据的实际大小和位置。这些记录是资源描述树中的叶子。 据描述


PE结构详解(64位和32位的差别)(4).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:中级基础知识真题集

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: