深入剖析Win32可移植可执行文件格式(第二部分)



深入剖析 Win32 可移植可执行文件格式 第二部分
作者:Matt Pietrek
上个月在本文的第一部分中,我首先对可移植可执行文件进行了全面的介绍.我讲了 PE 文 件的历史和组成 PE 文件头的数据结构,还讲了节表.PE 文件头和节表告诉你在可执行文件中都 包含什么类型的代码和数据,以及在哪里能找到它们. 本月我要讲一下常见的节.最后讲一下我的最新的经过彻底改进的PEDUMP程序,它可以在 2002 年 2 月的专栏中下载.如果你不熟悉PE文件的基本概念,应该首先读一下本文的第一部分. 上个月我讲了节是怎样的一个逻辑上属于一起的代码或数据块. 例如可执行文件的所有导入 信息都在一个节中. 现在让我们来看一下在可执行文件和 OBJ 文件中经常遇到的一些节. 除非特 别说明,否则下表中的节名都来自 Microsoft 的工具。
名称 .text .data .rdata .idata 描述 默认的代码节. 默认的可读/可写数据节.全局变量通常在这个节中. 默认的只读数据节.字符串常量和 C++/COM 虚表就放在这个节中. 导入表.实际上,链接器经常把.idata 节合并到其它节中(或者是明确指定的,或者是通 过链接器的默认行为).默认情况下,链接器仅在创建发行版的程序时才把.idata 节合并 到其它节中. .edata 导出表. 当创建要导出函数或数据的可执行文件时, 链接器会创建一个.EXP 文件. 这个.EXP 文件包含一个.edata 节,这个节被添加到最后的可执行文件中.与.idata 节一样,.edata 节也经常被合并到.text 节或.rdata 节中. .rsrc .bss 资源节.这个节是只读的.它不应该被命名为其它名称,也不应该被合并到其它节中. 未初始化的数据节. 在最新的链接器创建的可执行文件中很少见到. 链接器扩展可执行文件 的.data 节的 VirtualSize 域以便容纳未初始化的数据. .crt 添加到可执行文件中的数据,用来支持C++运行时库(CRT).一个比较好的例子就是用于调 用静态C++对象的构造函数和析构函数的指针.要获取更详细的信息,可以参考2001 年 1 月 的Under The Hood专栏. .tls 这个节中的数据用来支持使用\\\\_\\\\_declspec(thread)语法创建的线程局部存储变量. 它包括数 据的初始值,以及运行时需要的附加变量. .reloc 可执行文件中的基址重定位节. 通常 DLL 需要基址重定位信息而 EXE 并不需要. 在创建发行 版的程序时,链接器并不为 EXE 文件生成基址重定位信息.可以使用/FIXED 链接器选项移 除基址重定位信息. .sdata 通过全局指针(Global Pointer)相对寻址的"短(Short)"可读/可写数据.用于 IA-64 和其它使用全局指针寄存器的平台上.IA-64 平台上正常大小的全局变量在这个节中. .srdata 通过全局指针相对寻址的"短(Short)"只读数据.用于 IA-64 和其它使用全局指针寄存 器的平台上. .pdata 异常表.它包含一个 IMAGE\\\\_RUNTIME\\\\_FUNCTION\\\\_ENTRY 结构数组,这个结构与平台体系结构 相关. 数据目录中索引为 IMAGE\\\\_DIRECTORY\\\\_ENTRY\\\\_EXCEPTION 的项指向它. 用于使用基于表 的异常处理的平台,例如 IA-
  64.惟一不使用基于表的异常处理的平台是 x86(它使用的是
名称
描述 基于堆栈的异常处理).
.debug$S
OBJ 文件中的 Codeview 格式的调试符号(Symbol)信息.这是一列可变长度的 CodeView 格 式的调试符号记录.
.debug$T
OBJ 文件中的 Codeview 格式的调试类型(Type)记录.这是一列可变长度的 CodeView 格式 的调试类型记录.
.debug$P .drectve
可以在使用预编译头(Precompiled Headers)生成的 OBJ 文件中找到这个节. 这个节包含链接器指令, 并且只存在于 OBJ 文件中. 这些指令是传递到链接器命令行的 ASCII 码字符串,例如:-defaultlib:LIBC.指令之间用空格分开.
.didat
延迟加载导入数据.可以在非发行版本的可执行文件中找到.在发行版本中,延迟加载数据 被合并到其它节中.
导出表
当一个 EXE 或 DLL 导出函数或变量时,其它 EXE 或 DLL 就可以使用这些导出的函数或变量. 为了简单起见,我把导出的函数和导出的变量统称为"符号".当导出一些符号时,最起码导出 符号的地址需要能够以一种已定义好的方式被获取.每个导出的符号都有一个与之关联的序数, 它可以用来查找这个符号. 同时, 几乎总有一个 ASCII 码格式的字符串名称与这个导出的符号关 联.一般来说,导出的符号名与源文件中的符号名是一样的,尽管它们可以被修改的不一样. 通常,当可执行文件导入符号时,它使用的是符号的名称而不是它的序号.但是当通过名 称导入时, 系统仅使用这个名称去查找所需符号对应的导出序数, 然后根据这个序数值去获取相 应的地址. 如果先使用的是序数值的话查找过程会快一点. 通过名称导出和导入只是为了让程序 员使用方便罢了. 在.DEF 文件中的 Exports 节中使用 ORDINAL 关键字可以告诉链接器创建一个导入库,这个 导入库强制函数只能通过序数导入而不能通过名称导入. 我首先介绍 IMAGE\\\\_EXPORT\\\\_DIRECTORY 结构,如下表所示:
大小 DWORD DWORD 域 Characteristics TimeDateStamp 描述 导出标志.当前未定义任何值. 导出数据的创建时间.这个域的定义与 IMAGE\\\\_NT\\\\_HEADERS.FileHeader.TimeDateStamp 相同 (从 GMT 时间 1970 年 1 月 1 日 00:00 以来的总秒数). WORD WORD DWORD MajorVersion MinorVersion Name 导出数据的主版本号.未用,设置为
  0. 导出数据的次版本号.未用,设置为
  0. 与导出符号相关的 DLL 的名称 ASCII 字符串的 RVA(例如 KERNEL
  32.DLL). DWORD Base 这个域包含了这个可执行文件的导出符号所使用的序数值的起始值. 通常情况下这个值为 1, 但并不总是这样. 当通过序数查找导出符号时, 将序数值减去这个域的值就得到了这个导出符号在导出地址表 (Export Address Table ,EAT)中的索引.
大小 DWORD
域 NumberOfFunctions
描述 EAT 中的元素数.注意 EAT 中的某些元素可能为 0,这表明没有 代码/数据使用那个序数值导出.
DWORD
NumberOfNames
导出名称表(Export Names Table,ENT)中的元素数.这个域的值总 是小于或等于 NumberOfFunctions 域的值.当某些符号仅使用序数导 出时,它就小于那个域的值.如果导出序数之间有间隔,它同样也小 于那个域的值.这个域的值也是导出序数表的大小(见下文).
DWORD
AddressOfFunctions
EAT 的 RVA.EAT 中的每个元素都是一个 RVA.其中每个非 0 的 RVA 都 对应一个导出符号.
DWORD
AddressOfNames
ENT 的 RVA.ENT 中的每个元素都是一个 ASCII 码字符串的 RVA.其中 的每个 ASCII 码字符串都对应一个由名称导出的符号.这些字符串是 按一定顺序排列的.这就使得加载器在查找导出符号时可以进行二进 制搜索.名称字符串的排序是按二进制(与 C++运行时库函数 strcmp 类似),而不是与位置相关的字母表顺序.
DWORD
AddressOfNameOrdinals
导出序号表的 RVA.这个表是一个 WORD 类型的数组.它将 ENT 中的索 引映射到导出地址表中相应的元素上.
导出目录(Export Directory)指向三个数组和一个 ASCII 码字符串表.其中只有导出地 址表是必需的,它是一个由指向导出函数的指针组成的数组.导出序数是这个数组的索引(见下 图).
让我们通过例子来看一下导出表的工作原理. 下图显示了 KERNEL
  32.DLL 导出表的部分内容: exports table: Name: TimeDateStamp: Version: Ordinal base: # of Names: KERNEL
  32.dll 3B7DDFD8 -> Fri Aug 17 23:24:08 2001
  0.00 00000001 000003A0 Characteristics: 00000000
# of functions: 000003A0
Entry Pt Ordn Name
00012ADA 000082C2
1 ActivateActCtx 2 AddAtomA
remainder of exports omitted 假设你调用 GetProcAddress 来获取 KERNEL32 中的 AddAtomA 这个 API 的地址.这时系统开 始查找 KERNEL32 的 IMAGE\\\\_EXPORT\\\\_DIRECTORY 结构. 它从那里获取了导出名称表的起始地址, 知 道了在这个数组中有 0x3A0 个元素,它通过二进制搜索来查找字符串"AddAtomA". 假设加载器发现 AddAtomA 是这个数组中的第二个元素.然后它从导出序数表(Export Ordinal Table)中读取相应的第二个值.这个值就是 AddAtomA 的导出序数.将这个导出序数作 为 EAT 的索引(加上 Base 域的值),它最终获取 AddAtomA 的相对虚拟地址(RVA)是 0x82C
  2. 将此值与 KERNEL32 的加载地址相加就得到了 AddAtomA 的实际地址.
导出转发
导出表一个特别聪明的地方是它能将一个导出函数转发(Forwarding)到其它 DLL.例如 在 Windows NT,Windows 2000 和 Windows XP 中,KERNEL32 中的 HeapAlloc 函数被转发到了 NTDLL 导出的 RtlAllocHeap 函数上.转发是在链接时通过.DEF 文件中的 EXPORTS 节中的一种特 殊语法形式来实现的.对于 HeapAlloc 这个例子,KERNEL32 的.DEF 文件一定包含下面的内容: EXPORTS HeapAlloc = NTDLL.RtlAllocHeap 怎样才能区别转发的函数与正常导出的函数呢?这需要一些技巧.通常 EAT 中包含的是导 出符号的 RVA. 但是如果这个 RVA 位于导出表中 (通过相应的 DataDirectory 中的 VirtualAddress 域和 Size 域进行判断),那么它就是转发的. 当转发一个符号时,它的 RVA 很明显不能是当前模块中的代码或数据的地址.实际上,它 的 RVA 指向一个由 DLL 和转发到的符号名称组成的字符串.在前面的例子中,这个字符串就是 NTDLL.RtlAllocHeap.
导入表
与导出函数或变量相反的就是导入它们.为了与前面保持一致,我仍然使用"符号"这个 术语来指代导入的函数和变量. 导入数据被保存在 IMAGE\\\\_IMPORT\\\\_DESCRIPTOR 结构中.对应着导入表的数据目录项就指向 由这个结构组成的数组.每个 IMAGE\\\\_IMPORT\\\\_DESCRIPTOR 结构都与一个导入的可执行文件对应. 这个数组的最后一个元素的所有域都被设置为
  0.下表是这个结构的内容:
大小 DWORD 域 OriginalFirstThunk 描述 这个域的命名太不恰当.它包含导入名称表的 RVA.导入名称表是一个 IMAGE\\\\_THUNK\\\\_DATA 结构数组.这个域被设置为 0 表示 IMAGE\\\\_IMPORT\\\\_DESCRIPTOR 结构数组的结尾.
大小 DWORD
域 TimeDateStamp
描述 如果可执行文件并未绑定导入的 DLL, 这个域的值为
  0. 当使用老的绑定 类型进行绑定(参考"绑定"一节)时,这个域包含日期/时间戳.当使 用新的绑定类型进行绑定时,这个域的值为-
  1.
DWORD
ForwarderChain
这是首个转发的函数的索引. 如果没有转发的函数, 这个域被设置为-
  1. 它仅用于老的绑定类型,因为那种绑定类型不能很有效地处理转发的函 数.
DWORD DWORD
Name FirstThunk
导入的 DLL 名称字符串(ASCII 码格式)的 RVA. 导入地址表的 RVA.IAT 是一个 IMAGE\\\\_THUNK\\\\_DATA 结构数组.
每个 IMAGE\\\\_IMPORT\\\\_DESCRIPTOR 结构指向两个数组,这两个数组实际上是一样的.它们有 好几种叫法, 但最常用的名称是导入地址表 (Import Address Table, IAT) 和导入名称表 (Import Name Talbe,INT).下图显示的是可执行文件从 USER
  32.DLL 中导入一些 API 时的情况.
这两个数组的元素均为 IMAGE\\\\_THUNK\\\\_DATA 类型的结构,这个结构是一个与指针大小相同的 共用体(或者称为联合).每个 IMAGE\\\\_THUNK\\\\_DATA 结构对应着从可执行文件中导入的一个函数. 这两个数组最后都以一个值为 0 的 IMAGE\\\\_THUNK\\\\_DATA 结构作为结尾.这个共用体(实际是一个 DWORD 值)可以有如下几种含义: DWORD ForwarderString;// 转发函数字符串的 RVA(见上文) DWORD Function; DWORD Ordinal; // 导入函数的内存地址 // 导入函数的序数
DWORD AddressOfData; // IMAGE\\\\_IMPORT\\\\_BY\\\\_NAME 和导入函数名称的 RVA(见下文) IAT中的IMAGE\\\\_THUNK\\\\_DATA结构的用途可以分为两种.在可执行文件中,它们或者是导入函 数的序数,或者是一个IMAGE\\\\_IMPORT\\\\_BY\\\\_NAME结构的RVA.IMAGE\\\\_IMPORT\\\\_BY\\\\_NAME结构只是一个 WORD类型的值,它后面跟着导入函数的名称字符串.这个WORD类型的值是一个"提示(hint)", 它提示加载器导入函数的序号可能是什么. 当加载器加载可执行文件时, 它用导入函数的实际地 址来覆盖IAT中的每个元素. 这一点是理解下文的关键. 我强烈建议你读一读本期杂志中Russell Osterlund的文章??揭开Windows加载器的神秘面纱,这篇文章详细讲述了Windows加载器的行 为. 在可执行文件被加载之前,是否存在一种方法能够区分 IMAGE\\\\_THUNK\\\\_DATA 结构中到底包含 的是导入函数的序数呢, 还是 IMAGE\\\\_IMPORT\\\\_BY\\\\_NAME 结构的 RVA 呢?答案在 IMAGE\\\\_THUNK\\\\_DATA
结构的最高位.如果它为 1,那么低 31 位(在 64 位可执行文件中是低 63 位)中是导入函数的 序数. 如果最高位为 0, 那么 IMAGE\\\\_THUNK\\\\_DATA 结构的值就是 IMAGE\\\\_IMPORT\\\\_BY\\\\_NAME 结构的 RVA. 另一个数组 INT,本质上与 IAT 是一样的.它也是一个 IMAGE\\\\_THUNK\\\\_DATA 结构数组.关键 的区别在于当加载器将可执行文件加载进内存时,它并不覆盖 INT.为什么对于从 DLL 中导入的 每组 API 都需要有两个并列的数组呢?答案在于一个称为绑定(binding)的概念.当在绑定过 程(后面我会讲到)中覆盖可执行文件的 IAT 时,需要以某种方式
  •  
 

相关内容

03 第二部分 投标函格式B版071106final

  招标书编号:DPLNG-PL-ITT-016第二部分:投标函格式 第 1 页 共 13 页第二部分 投标函格式广东大鹏液化天然气有限公司招标书编号:DPLNG-PL-ITT-016第二部分:投标函格式 第 2 页 共 13 页目录附件A 投标函(格式) 附件B 投标保函(格式) 附件C 授权书(格式) 附件D 联合协议(如有)广东大鹏液化天然气有限公司招标书编号:DPLNG-PL-ITT-016第二部分:投标函格式 第 3 页 共 13 页附件 A 投标函( 格式) 投标函 ( 格式 )广东大鹏 ...

转发文件格式

  关于转发文件的标题格式的规定在转发式公文标题的拟制中,时常遇到这样一种难以处 理的情况, 如<<xX 县政府关于转发 Xx 行署关于转发 XX 省政 府关于 XXX(事由)的通知的通知的通知>>。在这种标题中, 介词一“关于” ;动词一“转发” ;文种一“通知”反复在一 个标题内出现,令人不知所云。当遇到这种情况时,可采取 以下三种方法进行技术处理。 一是省略法。 一是省略法。当批转、转发、印发(颁发)原文标题中 已有“关于”一词时,新拟标题可省略介词“关于”和文种 “通 ...

通知文件格式样式

  粤府办〔2005〕92号 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 转发科技部关于国家高新技术产业 开发区技术创新纲要的通知各地级以上市人民政府,省政府各部门、各直属机构: 现将科技部制定的《国家高新技术产业开发区技术创新纲要》 (国科发火字〔2005〕16 号,以下简称《纲要》)转发给你们,经 省人民政府同意,提出如下意见,请一并认真贯彻执行。 一、进一步提高认识,高度重视高新区的技术创新工作。各地、 各有关部门要坚持科学发展观,认真把握《纲要》精神实质,切实 指导和协调高新区做 ...

投标文件部分格式

  广东省广播电视微波电路数字化改造工程天井山铁塔基础工程GPCGD093162GG037F第六章 投 标 文 件 部 分 格 式广东省政府采购中心6-1广东省广播电视微波电路数字化改造工程天井山铁塔基础工程GPCGD093162GG037F{招标工程项目名称} 工程施工招标 招标工程项目名称}投标文件项目编号: 项目编号: {项目编号} 项目编号}名称: 项目名称: 投标文件内容: 投标文件内容: 投标人: 投标人: 法 定 代 表 人 或其委托代理人: 或其委托代理人:{招标工程项目名称} 招标 ...

通知、通告类文件格式

  备 /TO : 忘录指示请 示报告MEMO字号:宋体五号(含下)由 /F RO M : 题 /S UB : 号 /N O : 报 /C /C : 送 /C /C : 签 发 / SI GN ER:通知工作联系加急酒店全体员工: 正文(字号:宋体小四号) #################################### ###################################### ###################################### #######. ...

招投标文件格式 范文

  招标文件项目标号: 项目标号: 项目标名: 项目标名:招 标 人: 监管服务: 监管服务: 日期-1-第一章 投标邀请书某公司就某项目在交易中心进行公开招标,特邀贵单位参加。有关事项如下: 一、招标内容: 项目标号: 项目标名: 项目内容: (1)一作业区施工安装内容 1)机务专业: 2)电气专业: (2)二作业区施工安装内容 二、招标文件发售 发售时间: 2010 年 9 月 19 日至 2010 年 9 月 27 日, 每天 8:30-11:30, 14:30-17:30 (公休日除外) , ...

第二章 投标文件格式

  XX 公司 XX 工程 承包招标文件招标编号: 招标编号第一卷 商务部分 第二章 投标文件格式招标人: 招标人:XX 公司 招标代理机构: 招标代理机构:XX 招标公司 年 月 日GXTC-XXXXXXXXX 公司 XX 工程承包招标文件目录第一部分 资质及技术部分 .................................................................................................................... ...

部分资质文件格式样本

  部分资质文件格式样本年云南省省级和昆明市级医疗机构医用耗 2007 年云南省省级和昆明市级医疗机构医用耗 材及检验试剂集中备案采购 材及检验试剂集中备案采购 (YNKMHCSJBACG-2007) YNKMHCSJBACG-2007) BACG 供应商资格证明文件封面(供应商主体册)文件编号:第册共册(加盖供应商公章)产品类别:产品数: 年 月 日1附表 2供应商基本情况供应商(盖章): 供应商序号: 供应商所在地: 供应商联系电话: 供应商传真: 供应商通信地址: 供应商邮政编码: 供应商网址 ...

关于统一文件格式的通知

  关于统一文件格式的通知各处室、各部门: 为使我校文书档案做到格式规范、文体规范、文字规范,从即日起学校出台 统一格式要求,具体如下: 1、统一纸张 一般情况下使用 A4 纸,如有特殊情况可使用 A3 纸。(学校可定制印有“学 校全称+文件”或“学校全称”红色文字加下划线的两种文本用纸, 用于管理类文书 档案首页的打印。) 2、统一格式 (1)文章标题:黑体,三号,下空一行接正文,正副标题均居中; (2)正文一级标题:黑体,小四,序号请使用例“一、二、三……”的格式; (3)正文二级标题,宋体,小 ...

XXX程序文件格式模版

  珠海市杰威汽车电机有限公司标题:1.目的 1.目的程序文件编 号: XXXXXX 版 本: XX 第 1 页 ,共4XXXXX 程序页规范公司对人力资源合理配置、招募、管理等相关管理过程,有效的做好选才、育才、用才、留才之人力 资源管理。确保人力资源满足质量管理体系的要求。2.适用范围 2.适用范围适用于公司所有员工。3.引用文件 3.引用文件GB/T 18305-2010 ISO/TS 16949:2009 6.2 文件控制4.术语和定义 4.术语和定义4.1 离职:包括公司辞退、公司开除、员 ...

热门内容

研究生就业程序及问答

  随着高校研究生的逐年扩招,研究生的就业形势越来越严峻。毕业研究生的 就业指导工作也面临着前所未有的挑战。 为了使研究生详细了解国家关于高校毕 业研究生就业的相关政策,具体的就业流程,从而科学理性地安排自已的就业之 路,研究生处特编写此就业指南。 第一部分 毕业生就业程序指南一、研究生处管理科就业工作安排及上报时间表 (一)每年 2 月,研究生就业工作正式开始。学院应该密切关注当年毕 业生思想、 心理动态和就业方向, 做好摸查和动员工作, 及时上报研究生管理科。 管理科以《就业简报》的形式公布全校 ...

五年级下册数学知识点总结

  北海小学五(04)、五(09)第十册数学复习提纲5/7/2011五年级下册知识点班级 姓名 学号一 图形的变换轴对称: 这样的图形叫做轴对称图 轴对称: 如果一个图形沿着一条直线对折后两部分完全重合, 形, 这条直线叫做对称轴。 旋转:在平面内,一个图形绕着一个顶点旋转一定的角度得到另一个图形的变化较做旋 旋转 转,定点 O 叫做旋转中心,旋转的角度叫做旋转角,原图形上的一点旋转后成为的另一 点成为对应点。 旋转的性质: 旋转的性质 图形的旋转是图形上的每一点在平面上绕某个固定点旋转固定角度的位 ...

高考零分作文的反思

  最美的青春 当喝着知名厂商毒奶粉长大, 当庆幸自己身体没有得结石, 我依然固执地认为这是意外, 用暗自侥幸写下:相信未来 !当上学花掉十几万血汗钱, 当一年奋斗买不到放马桶地! 我依然固执地认为这是暂时困难, 在蜗居的简棚里写下:相信未来!当我的女朋友成为别人 二奶, 当我发现新交女朋友是小三, 我依然固执地沉默这是巧合, 在凄凉的墙壁上写下:相信未来!当富二代 朋友开着宝马 车驶过, 当学好物理化不如有个好爸妈! 我的骚动心扉有些动摇, 忍着抱怨写下:相信未来!当天上人家大款们抱着美女作 乐, ...

Hcteay商业银行财务会计--第七章 外汇业务

  秋风清,秋月明,落叶聚还散,寒鸦栖复惊。第七章外汇业务外汇是以外国货币表示的可用于国际结算的支付手段,包括外国货币、外币 有价证券、外币支付凭证、特殊债权和其他外汇资金。商业银行办理的外汇业务 可以分为外汇买卖业务、外汇存贷款业务、国际支付结算业务和金融衍生品业务 四大类。 第一节 外汇买卖业务一、外汇买卖的记账方法 外汇业务的记账方法有“本币记账法”和“原币记账法”两种。 (一)本币记账法 本币记账法也称为外汇统账制,是以本币为记账单位,在业务发生时,对所 发生的外币都按照一定的汇率折算成本币 ...

现货黄金介绍资料

  黄金现货国际黄金现货又叫伦敦金, 国际黄金现货又叫伦敦金, 伦敦金不是一种黄金的名称, 伦敦金不是一种黄金的名称, 而是一种黄 金交易方式的名称。因最早起源于伦敦而得名。伦敦金以美元标价, 金交易方式的名称。因最早起源于伦敦而得名。伦敦金以美元标价, 以英制盎司为计量单位。 黄金报价以道琼斯国际报价为准, 主要根据 以英制盎司为计量单位。 黄金报价以道琼斯国际报价为准, 伦敦市场的现货黄金价格。 一盎司等于 31.106 克。 每日盘价为*** 伦敦市场的现货黄金价格。 每日盘价为 盎司黄金的价 ...