2022年PE文件详解 .pdf

上传人:C****o 文档编号:32489833 上传时间:2022-08-09 格式:PDF 页数:45 大小:400.13KB
返回 下载 相关 举报
2022年PE文件详解 .pdf_第1页
第1页 / 共45页
2022年PE文件详解 .pdf_第2页
第2页 / 共45页
点击查看更多>>
资源描述

《2022年PE文件详解 .pdf》由会员分享,可在线阅读,更多相关《2022年PE文件详解 .pdf(45页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、一、前言( Preface)- PE ( “ portable executable”,可移植的可执行文件)文件格式, 是微软 WindwosNT,Windows95和 Win32 子集中的可执行的二进制文件的格式;在 WindowsNT 中,驱动程序也是这种格式。它还能被应用于各种目标文件和库文件中。这种文件格式是由微软设计的,并于1993 年被 TIS(tool interface standard,工具接口标准)委员会(由Microsoft,Intel,Borland,Watcom,IBM,等等组成)所批准,它明显的基于COFF 文件格式的许多知识。COFF(“common object

2、 file fromat ”,通用目标文件格式)是应用于好几种 UNIX 系统和VMS 系统中的目标文件和可执行文件的格式。Win32 SDK 中包含一个名叫 的头文件,其中含有很多用于PE 格式的 #define 和typedef 定义。我将逐步地提到其中的很多结构成员名字和#define 定义。你也可能发现DLL 文件 “imagehelp.dll”很有用途, 它是 WindowNT 的一部分, 但其书面文件却很缺乏。它的一些功用在“DeveloperNetwork” (开发者网络)中有所描述。二、总览( General Layout )- 在一个 PE 文件的开始处,我们会看到一个MS-

3、DOS 可执行体(英语叫“stub ”,意为 “ 根,存根” ) ;它使任何PE文件都是一个有效的MS-DOS 可执行文件。在 DOS-根之后是一个32 位的签名以及魔数0 x00004550 (IMAGE_NT_SIGNATURE)(意为“ NT签名 ” , 也就是 PE签名;十六进制数45 和 50 分别代表 ASCII 码字母 E和 P-译者注)。之后是文件头(按COFF 格式) ,用来说明该二进制文件将运行在何种机器之上、分几个区段、链接的时间、是可执行文件还是DLL 、等等。(本文中可执行文件和DLL文件的区别在于: DLL文件不能被启动,但能被别的二进制文件使用,而一个二进制文件则

4、不能链接到另一个可执行文件。 )那些之后,是可选头(尽管它一直都存在,却仍被称作“ 可选 ” -因为 COFF 文件格式仅为库文件使用一个“ 可选头 ” ,却不为目标文件使用一个“ 可选头 ” ,这就是为什么它被称为“ 可选” 的原因)。它会告诉我们该二进制文件怎样被载入的更多信息:开始的地址呀、 保留的堆栈数呀、数据段的大小呀、等等。可选头的一个有趣的部分是尾部的“ 数据目录 ” 数组;这些目录包含许多指向各“ 节 ” 数据的指针 。 例 如 : 如 果 一 个 二 进 制 文 件 拥 有 一 个 输 出 目 录 , 那 么 你 就 会 在 数 组 成 员“ IMAGE_DIRECTORY_

5、ENTRY_EXPORT”(输出目录项) 中找到一个指向那个目录的指针,而该指针指向文件中的某节。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 45 页 - - - - - - - - - 跟在各种头后面我们就发现各个“ 节” 了,它们都由 “ 节头 ” 引导。本质上讲,各节中的内容才是你执行一个程序真正需要的东西,所有头和目录这些东西只是为了帮助你找到它们。每节都含有和对齐、包含什么样的数据(如“ 已初始化数据” 等等)、是否能共享等有关的一些标记,还有就是数据本身。

6、大多数(并非所有)节都含有一个或多个可通过可选头的“ 数据目录 ” 数组中的项来参见的目录,如输出函数目录和基址重定位目录等。无目录形式的内容有:例如 “ 可执行代码 ” 或“ 已初始化数据” 等。 +-+ | DOS-stub | -DOS- 头 +-+ | file-header | -文件头 +-+ | optional header | -可选头 |- - - - - - - - - -| | | | data directories | -数据目录 | | +-+ | | | section headers | -节头 | | +-+ | | | section 1 | -节 1 |

7、 | +-+ | | | section 2 | -节 2 | | +-+ | | | . | | | +-+ | | | section n | -节 n | | +-+ 三、 DOS-根和签名( DOS-stub and Signature)- 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 45 页 - - - - - - - - - DOS-根的概念很早从16 位 windows 的可执行文件(当时是“ NE”格式)时就广为人知了。根原来是用于OS/2系统的可执行

8、文件的,也用于自解压档案文件和其它的应用程序。对于 PE 文件来说, 它是一个总是由大约100 个字节所组成的和MS-DOS 2.0 兼容的可执行体,用来输出象 “this program needs windows NT ”之类的错误信息。你可以通过确认DOS-头部分是否为一个IMAGE_DOS_HEADER (DOS 头) 结构来认出 DOS-根, 它的前两个字节必须为连续的两个字母“MZ ”(有一个 #define IMAGE_DOS_SIGNATURE的定义是针对这个WORD 单元的)。你可以通过跟在后面的签名来将一个PE 二进制文件和其它含有根的二进制文件区分开来,跟在后面的签名可由

9、头成员e_lfanew( 它是从字节偏移地址60 处开始的, 有 32 字节长) 所设定的偏移地址找到。对于OS/2 系统和Windows 系统的二进制文件来说,签名是一个16位的 word 单元;对于PE 文件来说,它是一个按照8 位字节边界对齐的32 位的 longword单元, 并且 IMAGE_NT_SIGNATURE(NT 签名)的值已由#defined 定义为 0 x00004550(即字母 “PE/0/0”-译者) 。四、文件头( File Header)- 要到达 IMAGE_FILE_HEADER(文件头) 结构,请先确认 DOS-头“MZ ”(起始的2 个字节),然后找出D

10、OS-根的头部的成员“e_lfanew ”,并从文件开始处跳过那么多的字节。在核实你在那里找到的签名后,IMAGE_FILE_HEADER(文件头) 结构的文件头就紧跟其后开始了,下面我们将从头至尾的介绍其成员。1)第一个成员是“ Machine (机器) ” ,一个 16 位的值,用来指出该二进制文件预定运行于什么样的系统。已知的合法的值有: IMAGE_FILE_MACHINE_I386 (0 x14c) Intel 80386 处理器或更高 0 x014d Intel 80386 处理器或更高 0 x014e Intel 80386 处理器或更高 0 x0160 R3000 (MIPS

11、)处理器,大尾 IMAGE_FILE_MACHINE_R3000 (0 x162) R3000 (MIPS) 处理器,小尾名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 45 页 - - - - - - - - - IMAGE_FILE_MACHINE_R4000 (0 x166) R4000 (MIPS) 处理器,小尾 IMAGE_FILE_MACHINE_R10000 (0 x168) R10000 (MIPS) 处理器,小尾 IMAGE_FILE_MACHINE_A

12、LPHA (0 x184) DEC Alpha AXP 处理器 IMAGE_FILE_MACHINE_POWERPC (0 x1F0) IBM Power PC, 小尾2)然后是 “ NumberOfSections (节数) ” 成员, 16 位的值。它是紧跟在头后面的节的数目。我们以后将讨论节的问题。3)下一个成员是时间戳“ TimeDateStamp ”(32 位) ,用来给出文件建立的时间。即使它的 “ 官方” 版本号没有改变,你也可通过这个值来区分同一个文件的不同版本。(除了同一个文件的不同版本之间必须唯一,时间戳的格式没有明文规定,但似乎是按照UTC时间 “ 从 1970年 1 月

13、 1 日 00:00:00 算起的秒数值” -也就是大多数C 语言编译器给time_t 标志使用的格式。 )这个时间戳是用来绑定各个输入目录的,我们稍后再讨论它。警告:有一些链接器往往将时间戳设为荒唐的值,而不是如前所述的time_t 格式的链接时间。4-5)成员 “PointerToSymbolTable (符号表指针)” 和成员 “ NumberOfSymbols (符号数) ” (都是 32 位)都用于调试信息的。我不知道该怎样去解读它,并且我发现该指针的值总为0。6)成员 “ SizeOfOptionalHeader (可选头大小) ”(16 位)只是 “IMAGE_OPTIONAL_

14、HEADER(可选头) ” 项的大小,你能用它去验证PE 文件结构的正确性。7)成员 “ Characteristics (特性) ” 是一个 16 位的,由许多标志位形成的集合组成,但大多数标志位只对目标文件和库文件有效。具体如下:位 0 IMAGE_FILE_RELOCS_STRIPPED(重定位被剥离文件)表示如果文件中没有重定位信息,该位置1,这就表明各节的重定位信息都在它们各自的节中;可执行文件不使用该位,它们的重定位信息放在下面将要描述的“base relocation”(基址重定位)目录中。位 1 IMAGE_FILE_EXECUTABLE_IMAGE(可执行映象文件)表示如果文

15、件是一个可执行文件,也即不是目标文件或者库文件时,置1。如果链接器尝试创建一个可执行文件,却因为一些原因失败了,并保存映像以便下次例如增量链接时使用,此时此标志位也可能置1。位 2 IMAGE_FILE_LINE_NUMS_STRIPPED(行数被剥离文件)表示如果行数信息被剥除,此位置1;此位也不用于可执行文件。位 3 IMAGE_FILE_LOCAL_SYMS_STRIPPED(本地符号被剥离文件)表示如果文件中名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 45 页

16、 - - - - - - - - - 没有关于本地符号的信息时,此位置1(此位也不用于可执行文件)。位 4 IMAGE_FILE_AGGRESIVE_WS_TRIM(强行工作集修剪文件)表示如果操作系统被假定为: 通过将正在运行的进程(它所使用的内存数量)强行的页清除来修剪它的工作集时,此位置1。如果一进程是大部分时间处于等待,且一天中仅被唤醒一次的演示性的应用程序之类时,此位也应该被置1。位7 IMAGE_FILE_BYTES_REVERSED_LO( 低字节 变换 文件 )和位15IMAGE_FILE_BYTES_REVERSED_HI( 高字节变换文件)表示如果一文件的字节序不是机器所预

17、期的形式,因此它在读入前必须调换字节时,此位置1。这样做对可执行文件是不可靠的(操作系统期望可执行文件都已经被正确地按字节排整齐了)。位 8 IMAGE_FILE_32BIT_MACHINE(32 位机器文件)表示如果使用的机器被期望为32位的机器时,此位置1。现在的应用程序总将此位置1;NT5 系统可能工作不同。位 9 IMAGE_FILE_DEBUG_STRIPPED(调试信息被剥离文件) 表示如果文件中没有调试信息,此位置1。此位可执行文件不用。按照其它信息(6) (这里指的是参考书目中的第6种- 译者注),此位被称作 “ 恒定 ” ,并且当一个映象文件只有在被装入优先的装入地址才能运行

18、(亦即:此文件不可重定位)时,此位置1。位 10 IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP(移动介质文件从交换文件运行) 表示如果一个应用程序不可以从可移动的介质,如软盘或CD-ROM 上运行时, 此位置 1。在这种情况下,建议操作系统将文件复制到交换文件并从那里执行。位 11 IMAGE_FILE_NET_RUN_FROM_SWAP(网络文件从交换文件运行) 表示如果一个应用程序不可以从网络上运行时,此位置1。在这种情况下,建议操作系统将文件复制到交换文件并从那里执行。位 12 IMAGE_FILE_SYSTEM(系统文件 ) 表示如果文件是一个象驱动程序那样的系

19、统文件,此位置1。此位可执行文件不用;我所见过的所有NT 系统的驱动程序也不用。位 13 IMAGE_FILE_DLL(DLL 文件 ) 表示如果文件是一个DLL 文件时,此位置1。位 14 IMAGE_FILE_UP_SYSTEM_ONLY(仅但处理器系统的文件) 表示如果文件不设计运行在多处理器系统上(也就是说, 因为此文件严格地依赖单一处理器的一些方式工作,所以它会发生冲突)时,此位置1。五、相对虚拟地址(Relative Virtual Addresses )- PE格 式 大 量 地 使 用 所 谓 的RVA ( 相 对 虚 拟 地 址 )。 一 个RVA , 亦 即 一 个名师资料

20、总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 45 页 - - - - - - - - - “ Relative Virtual Addresses(相对虚拟地址)” ,是在你不知道基地址时,被用来描述一个内存地址的。它是需要加上基地址才能获得线性地址的数值。基地址就是PE 映象文件被装入内存的地址,并且可能会随着一次又一次的调用而变化。例如:假若一个可执行文件被装入的地址是0 x400000,并且从 RVA 0 x1560 处开始执行,那么有效的执行开始处将位于0 x4015

21、60 地址处。假若它被装入的地址为0 x100000,那么执行开始处就位于0 x101560 地址处。因为 PE-文件中的各部分 (各节) 不需要像已载入的映象文件那样对齐,事情变得复杂起来。例如,文件中的各节常按照512(十六进制的0 x200- 译者注)字节边界对齐,而已载入的映象文件则可能按照4096(十六进制的0 x1000- 译者注)字节边界对齐。参见下面的“ SectionAlignment (节对齐) ” 和 “FileAlignment (文件对齐)” 。因此,为了在PE 文件中找到一个特定RVA 地址的信息,你得按照文件已被载入时的那样来计算偏移量,但要按照文件的偏移量来跳过

22、。试举一例,假若你已知道执行开始处位于RVA 0 x1560 地址处,并且想从那里开始的代码处反汇编。 为了从文件中找到这个地址,你得先查明在RAM(内存) 中各节是按照4096 字节对齐的,并且“.code ”节是从RVA 0 x1000地址处开始,有16384 字节长;然后你才知道RVA 0 x1560 地址位于此节的偏移量0 x560 处。你还要查明在文件中那节是按512 字节边界对齐,且 “.code ”节在文件中从偏移量0 x800 处开始, 然后你就知道在文件中代码的执行开始处就在 0 x800+0 x560=0 xd60 字节处。然后你反汇编它并发现访问一个变量的线性地址位于0

23、x1051d0 处。二进制文件的线性地址在装入时将被重定位,并常被假定使用的是优先载入地址。因为你已查明优先载入地址为0 x100000,因此我们可开始处理RVA 0 x51d0 了。因数据节开始于RVA 0 x5000 处 ,且有 2048字节长,所以它处于数据节中。又因数据节在文件中开始于偏移量0 x4800 处,所以该变量就可以在文件中的0 x4800+0 x51d0-0 x5000=0 x49d0 处找到。六、可选头( Optional Header )- 紧跟在文件头后面的就是IMAGE_OPTIONAL_HEADER(尽管它名叫 “ 可选头 ” ,它却一直都在那里)。它包含有怎样去

24、准确处理PE 文件的信息。我们也将从头至尾的介绍其成员。1)第一个16 位的 word 单元叫 “ Magic (魔数) ” ,就我目前所观察过的PE 文件而言,它的值总是 0 x010b。2-3)下面 2 个字节是创建此文件的链接器的版本( ,MajorLinkerVersion? ,“ 链接器主版本号”和,MinorLinkerVersion? ,“ 链接器小版本号” ) 。这两个值又是不可靠的,并不能总是正确地名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 45 页

25、 - - - - - - - - - 反映链接器的版本号。 (有好几个链接器根本就不设置这个值。)况且,你可想象一下,你连使用的是 “ 什么 ” 链接器都不知道,知道它的版本号又有什么作用呢?4-6)下面3 个 longword (每个32 位)分别用来设定可执行代码的大小(“ SizeOfCode ”) 、已初始化数据的大小( “SizeOfInitializedData”,所谓的 “ 数据段 ” ) 、以及未初始化数据的大小(“SizeOfUninitializedData”,所谓的 “bss 段 ” ) 。这些值也是不可靠的(例如:数据段实际上可能会被编译器或者链接器分成好几段),并且你

26、可以通过查看可选头后面的各个“ 节” 来获得更准确的大小。7)下一个32 位值是 RVA。这个 RVA 是代码入口点的偏移量(,AddressOfEntryPoint? ,“ 入口点地址 ” ) 。执行将从这里开始,它可以是:例如DLL 文件的 LibMain() 的地址,或者一个程序的开始代码(这里相应的叫main())的地址,或者驱动程序的DriverEntry() 的地址。如果你敢于 “ 手工 ” 装载映象文件, 那么在你完成所有的修正和重定位后,你可以从这个地址开始执行你的进程。8-9)下两个32 位值分别是可执行代码的偏移值(,BaseOfCode?,“ 代码基址 ” )和已初始化数

27、据的偏移值(,BaseOfData?,“ 数据基址 ” ) ,两个都是RVA,并且两个对我们来说都没有多少意义,因为你可以通过查看可选头后面的各个“ 节” 来获得更可靠的信息。未初始化的数据没有偏移量,正因为它没有初始化,所以在映象文件中提供这些数据是没有用处的。10)下一项是个32 位值,提供整个二进制文件包括所有头的优先(线性)载入地址(,ImageBase?,“ 映象文件基址 ”)。这是一个文件已被链接器重定位后的地址(总是64 KB 的倍数) 。如果二进制文件事实上能被载入这个地址,那么加载器就不用再重定位文件了,也就节省了一些载入时间。优先载入地址在另一个映象文件已被先载入那个地址(

28、 “ 地址冲突 ” ,在当你载入好几个全部按照链接器的缺省值重定位的DLL 文件时经常发生) 时,或者该内存已被用于其它目的(堆栈、 malloc()、未初始化数据、或不管是什么)时,就不能用了。在这些情况下,映象文件必须被载人其它的地址,并且需要重定位(参见下面的“ 重定位目录 ” ) 。如果是一个DLL 文件,这么做还会产生其它问题,因为此时的“ 绑定输入 ” 已不再有效,所以使用DLL 的二进制文件必须被修正-参见下面的 “ 输入目录 ” 一节。11-12)下两个 32 位值分别是RAM 中的 “SectionAlignment”(当映象文件已被载入后,意为“ 节对齐 ” )和文件中的

29、“ FileAlignment”(文件对齐) ,它们都是PE 文件的各节的对齐值。这两个值通常都是32,或者是: FileAlignment为 512,SectionAlignment 为 4096。节会在以后讨论。13-14 ) 下2个16位word单元 都 是 预 期 的 操 作 系 统 版 本 信息(MajorOperatingSystemVersion,“操作系统主版本号” ) 和 (MinorOperatingSystemVersion , “ 操作系统小版本号” )它们都使用微软自己书面确定的名字。这个版本信息应该为操作系统的版本号(如NT 或 Win95 ) ,而不是子系统的版本

30、信息(如Win32) 。版本信息常常被不提供或者错误提供。很明显的,加载器并不使用它们。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 45 页 - - - - - - - - - 15-16)下 2 个 16 位 word 单元都是本二进制文件的版本信息(MajorImageVersion“映象文件主版本号 ” 和MinorImageVersion“映象文件小版本号”)。很多链接器不正确地设定这个信息,许多程序员也懒得提供这些,因此即便存在这样的信息,你最好也不要信赖它

31、。17-18)下 2 个 16 位 word 单元都是预期的子系统版本信息(MajorSubsystemVersion“子系统主版本号 ” 和MinorSubsystemVersion“子系统小版本号”)。此信息应该为Win32 或 POSIX 的版本信息,因为很明显的,16 位程序或 OS/2 程序都不是PE 格式的。子系统版本应该被正确的提供,因为它“ 会” 被检验和使用:如果一个应用程序是一个Win32-GUI 应用程序并运行于NT4 系统之上,而且子系统版本“ 不是”4.0的话,那么对话框就不会是以3D 形式显示,并且一些其它的特征也只会按“ 老式 ” 的方式工作,因为此应用程序预期是

32、在NT 3.51 系统上运行的,而NT 3.51 系统上只有程序管理器而没有浏览器、等等,于是NT 4.0 系统就尽可能地仿照那个系统的行为来运行程序。19)然后,我们便碰到32 位的 “ Win32VersionValue”(Win32 版本值)。我不清楚它有什么作用。在我所观察过的PE 文件中,它全部都为0。20)下一个是 32 位值,给出映象文件将要使用的内存数量,单位为字节 (,SizeOfImage?,“ 映象文件大小 ” ) 。如果是按照“SectionAlignment ”对齐的,它就是所有头和节的长度的总和。它提示加载器,为了载入映象文件需要多少页。21)下一个是32 位值,给

33、出所有头的总长度,包括数据目录和节头(,SizeOfHeaders?,“ 头的大小 ” ) 。同时,它也是从文件的开头到第一节的原始数据的偏移量。22)然后,我们发现一个32 位的校验和(“ CheckSum”) 。这个校验和,对于当前的NT 版本,只在映象文件是NT 驱动程序时才校验(如果校验和不正确,驱动就将装载失败)。对于其他的二进制文件形式,校验和不需提供并且可能为0。 计算校验和的算法是微软的私产,他们不会告诉你的。但是,Win32 SDK 的好几个工具都会计算和/或补正一个有效的校验和,而且 imagehelp.dll 中的 CheckSumMappedFile() 函数也会做同样

34、的工作。使用校验和的目的是为了防止载入无论如何都会冲突的、已损坏的二进制文件- 况且一个冲突的驱动程序会导致一个BSOD错误,因此最好根本就不载入这样的坏文件。23)然后,就到了一个16 位的 word 单元 “ Subsystem ”(子系统),用来说明映象文件应运行于什么样的NT 子系统之上: IMAGE_SUBSYSTEM_NATIVE (1) 二进制文件不需要子系统。用于驱动程序。 IMAGE_SUBSYSTEM_WINDOWS_GUI (2) 映象文件是一个Win32 二进制图象文件。 (它还是能用AllocConsole() 打开一个控制台界面,但在开始时却不能自动地打开。) IM

35、AGE_SUBSYSTEM_WINDOWS_CUI (3) 二进制文件是一个Win32 控制台界面二进制文件。 (它将在开始时按照缺省值打开一个控制台,或者继承其父程序的控制台。)名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 45 页 - - - - - - - - - IMAGE_SUBSYSTEM_OS2_CUI (5) 二进制文件是一个OS/2 控制台界面二进制文件。(OS/2 控制台界面二进制文件是OS/2 格式,因此此值在PE 文件中很少使用。 ) IMAGE

36、_SUBSYSTEM_POSIX_CUI (7) 二进制文件使用POSIX控制台子系统。Windows 95 的二进制文件总是使用Win32 子系统,因此它的二进制文件的合法值只有2 和3;我不知道windows 95 的“ 原” 二进制文件是否可能(会有其它值 -译者添加, 仅供参考)。24)下一个是16 位的值,指明,如果是DLL文件,何时调用DLL文件的入口点(,DllCharacteristics? , “DLL特性 ” ) 。此值似乎不用;很明显地,DLL 文件总是被通报所有的情况。如果位 0 被置 1,DLL 文件被通知进程附加(亦即DLL 载入)。如果位 1 被置 1,DLL 文

37、件被通知线程附加(亦即线程终止)。如果位 2 被置 1,DLL 文件被通知线程附加(亦即线程创建)。如果位 3 被置 1,DLL 文件被通知进程附加(亦即DLL 卸载)。25-28)下4 个 32 位值分别是:保留栈的大小(SizeOfStackReserve) 、初始时指定栈大小( SizeOfStackCommit )、 保 留 堆 的 大 小 ( SizeOfHeapReserve ) 和 指 定 堆 大 小(SizeOfHeapCommit ) 。“ 保留的 ” 数量是保留给特定目的的地址空间(不是真正的RAM ) ;在程序开始时,“ 指定的 ”数量是指在RAM 中实际分配的大小。如果

38、需要的话,“ 指定的 ” 值也是指定的堆或栈用来增加的数量。(有资料说,不管“SizeOfStackCommit”的值是多少,栈都是按页增加的。我没有验证过。)因此,举例来说,如一个程序的保留堆有1 MB ,指定堆为64 KB, 那么启动时堆的大小为64 KB, 并且保证可以扩大到1 MB 。堆将按64 KB 一块来增加。“ 堆” 在本文中是指主要(缺省)堆。如果它愿意的话,一个进程可创建很多堆。栈是指第一个线程的栈(启动main()的那个)。进程可以创建很多线程,每个线程都有自己的栈。DLL文件没有自己的堆或栈,所以它们的映象文件忽略这些值。我不知道驱动程序是否有它们自己的堆或栈,但我认为它

39、们没有。29)堆和栈的这些描述之后,我们就发现一个32 位的 “LoaderFlags (加载器标志)” ,我没有找到它的任何有用的描述。我只发现一篇时新的关于设置此标志位的短文,说设置此标志位会在映象文件载入后自动地调用一个断点或者调试器;可似乎不正确。30)接着我们会发现32 位的 “ NumberOfRvaAndSizes (Rva 数和大小) ” ,它是紧随其后的目录 的 有 效 项 的 数 目 。 我 已 发 现 此 值 不 可 靠 ; 你 也 许 希 望 用 常 量IMAGE_NUMBEROF_DIRECTORY_ENTRIES(映象文件目录项数目)来代替它,或者用它们中的较小者。

40、名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 45 页 - - - - - - - - - NumberOfRvaAndSizes之后是一个IMAGE_NUMBEROF_DIRECTORY_ENTRIES (16)(映象文件目录项数目)个IMAGE_DATA_DIRECTORY(映象文件数据目录)数组。这些目录中的每一个目录都描述了一个特定的、位于目录项后面的某一节中的信息的位置(32 位的RVA,叫 “ VirtualAddress (虚拟地址)” )和大小(也是32

41、 位,叫 “ Size (大小) ” ) 。例如,安全目录能在索引4 中给定的RVA 处发现并具有索引4 中给定的大小。稍后我将讨论我知道其结构的目录。已定义的目录及索引有: IMAGE_DIRECTORY_ENTRY_EXPORT (0) 输出符号目录;大多用于DLL 文件。后面介绍。 IMAGE_DIRECTORY_ENTRY_IMPORT (1) 输入符号目录;参见后面。 IMAGE_DIRECTORY_ENTRY_RESOURCE (2) 资源目录。后面介绍。 IMAGE_DIRECTORY_ENTRY_EXCEPTION (3) 异常目录 - 结构和用途不详。 IMAGE_DIREC

42、TORY_ENTRY_SECURITY (4) 安全目录 - 结构和用途不详。 IMAGE_DIRECTORY_ENTRY_BASERELOC (5) 基址重定位表 - 参见后面。 IMAGE_DIRECTORY_ENTRY_DEBUG (6) 调试目录 - 内容编译器相关。此外, 许多编译器将编译信息填入代码节,并不为此创建一个单独的节。 IMAGE_DIRECTORY_ENTRY_COPYRIGHT (7) 描述字符串 - 一些随意的版权信息之类。 IMAGE_DIRECTORY_ENTRY_GLOBALPTR (8) 机器值 (MIPS GP) - 结构和用途不详。 IMAGE_DIRE

43、CTORY_ENTRY_TLS (9) 线程级局部存储目录 - 结构不详; 包含声明为 “ _declspec(thread)”的变量 , 也就是每线程的全局变量。 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG (10) 载入配置目录 - 结构和用途不详。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 45 页 - - - - - - - - - IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (11) 绑定输入目录 - 参见

44、输入目录的描述。 IMAGE_DIRECTORY_ENTRY_IAT (12) 输入地址表 - 参见输入目录的描述。试举一例, 如果我们在索引7 中发现 2 个 longword : 0 x12000 和 33,并且载入地址为0 x10000,那么我们就知道版权信息数据位于地址0 x10000+0 x12000(在哪个节都有可能)处,并且版权信息有33 字节长。如果二进制文件中没有使用特殊类型的目录,Size(大小)和VirtualAddress (虚拟地址)的值就都为0。七、节目录( Section directories )- 节由两个主要部分组成:首先,是一个节描述(IMAGE_SECT

45、ION_HEADER意为 “ 节头 ” 类型的 ),然后是原始的节数据。因此, 我们会在数据目录后发现一“NumberOfSections”个节头组成的数组,它们按照各节的RVA 排序。节头包括:1)一个IMAGE_SIZEOF_SHORT_NAME (8)(意为 “ 短名的大小 ” )个字节的数组,形成节的名称( ASCII 形式)。如果所有的8 位都被用光,该字符串就没有0 结束符!典型的名称象“.data ”或“.text ”或“.bss ”形式。开头的 “. ”不是必须的, 名称也可能为 “CODE ”或“IAT”或类似的形式。请注意: 并不是所有的名称都和节中的内容相关。一个名叫 “

46、.code ”的节可能包含也可能不包含可执行代码; 它还可能只包含输入地址表;它也可能包含代码“ 和” 地址表 “ 和” 未初始化数据。要找到节中的信息,你必须通过可选头的数据目录来查询它。既不要过分相信它的名称,也不要以为节的原始数据会从节的开头就开始。2)IMAGE_SECTION_HEADER( “ 节头 ” )的下一个成员是一个32 位的、 “ PhysicalAddress(物理地址) ” 和“VirtualSize (虚拟大小) ” 组成的共用体。在目标文件中,它是内容重定位到的地址;在可执行文件中,它是内容的大小。事实上,此域似乎没被使用;因为有的链接器输入大小,有的链接器输入地

47、址,我还发现有一个链接器输入0,而所有的可执行文件都运行如风。3)下一个成员是 “ VirtualAddress (虚拟地址) ” ,是一个 32 位的值, 用来保存载入RAM(内存)后,节中数据的RVA。4)然后,我们到了32 位的 “SizeOfRawData ”(意味 “ 原始数据大小 ” ) ,它表示节中数据被大约到下一个 “FileAlignment”的整数倍时节的大小。5)下一个是 “PointerToRawData”(意味 “ 原始数据指针” ,32 位) ,它特别有用,因为它是从文件的开头到节中数据的偏移量。如果它为0,那么节的数据就不包含在文件中,并且要在名师资料总结 - -

48、 -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 11 页,共 45 页 - - - - - - - - - 载入时才定。6-9 ) 然 后 , 我 们 得 到 “PointerToRelocations”( 意 味 “ 重 定 位 指 针 ” , 32位 ) 和“ PointerToLinenumbers”(意味 “ 行数指针 ” ,也是 32 位) ,以及 “ NumberOfRelocations”(意味“ 重定位数 ” ,16 位)和 “NumberOfLinenumbers”(意味 “ 行数数

49、” ,也是 16 位) 。所以这些都是只用于目标文件的信息。可执行文件拥有一个特殊的基址重定位目录,并且行数信息 (如果真的存在的话)通常包含在有一个特殊目的的调试段中或者别的什么地方。10)节头的最后一个成员是32 位的 “Characteristics”(意味 “ 特性 ” ) ,它是一串描述节的内存如何被处理的标志:如果位 5 IMAGE_SCN_CNT_CODE(含有代码的节)被置 1,表示节中包含可执行代码。如果位 6 IMAGE_SCN_CNT_INITIALIZED_DATA(含有初始化数据的节)被置 1,表示节中包含执行开始前即取得已定义值的数据。换言之:文件中节的数据就是有意

50、义的。如果位 7 IMAGE_SCN_CNT_UNINITIALIZED_DATA(含有未初始化数据的节)被置 1,表示节中包含未初始化数据,并需于执行开始前被初始化为全0。这通常是BSS 节。如果位 9 IMAGE_SCN_LNK_INFO(链接器信息节)被置 1, 表示节中不包含映象数据,只有一些注释、 描述或者其他的文档。这些信息是目标文件的一部分,并有可能是提供给链接器的信息,比如需要哪些库文件。如果位 11 IMAGE_SCN_LNK_REMOVE(链接可删除节)被置 1, 表示数据是目标文件的、被预定于可执行文件被链接后丢弃掉的节的一部分。常和位9 连用。如 果 位 12 IMAG

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 高考资料

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com