ImageVerifierCode 换一换
格式:DOCX , 页数:20 ,大小:25.99KB ,
资源ID:7471500      下载积分:12 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/7471500.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(PE文件格式详解上.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

PE文件格式详解上.docx

1、PE文件格式详解上PE文件格式详解(上) Windows NT 3.1引入了一种名为PE文件格式的新可执行文件格式。PE文件格式的规范包含在了MSDN的CD中(Specs and Strategy, Specifications, Windows NT File Format Specifications),但是它非常之晦涩。 然而这一的文档并未提供足够的信息,所以开发者们无法很好地弄懂PE格式。本文旨在解决这一问题,它会对整个的PE文件格式作一个十分彻底的解释,另外,本文中还带有对所有必需结构的描述以及示范如何使用这些信息的源码示例。 为了获得PE文件中所包含的重要信息,我编写了一个名为PE

2、FILE.DLL的动态链接库,本文中所有出现的源码示例亦均摘自于此。这个DLL和它的源代码都作为PEFile示例程序的一部分包含在了CD中(译注:示例程序请在MSDN中寻找,本站恕不提供),你可以在你自己的应用程序中使用这个DLL;同样,你亦可以依你所愿地使用并构建它的源码。在本文末尾,你会找到PEFILE.DLL的函数导出列表和一个如何使用它们的说明。我觉得你会发现这些函数会让你从容应付PE文件格式的。介绍Windows操作系统家族最近增加的Windows NT为开发环境和应用程序本身带来了很大的改变,这之中一个最为重大的当属PE文件格式了。新的PE文件格式主要来自于UNIX操作系统所通用的

3、COFF规范,同时为了保证与旧版本MS-DOS及Windows操作系统的兼容,PE文件格式也保留了MS-DOS中那熟悉的MZ头部。 在本文之中,PE文件格式是以自顶而下的顺序解释的。在你从头开始研究文件内容的过程之中,本文会详细讨论PE文件的每一个组成部分。 许多单独的文件成分定义都来自于Microsoft Win32 SDK开发包中的WINNT.H文件,在这个文件中你会发现用来描述文件头部和数据目录等各种成分的结构类型定义。但是,在WINNT.H中缺少对PE文件结构足够的定义,在这种情况下,我定义了自己的结构来存取文件数据。你会在PEFILE.DLL工程的PEFILE.H中找到这些结构的定义

4、,整套的PEFILE.H开发文件包含在PEFile示例程序之中。 本文配套的示例程序除了PEFILE.DLL示例代码之外,还有一个单独的Win32示例应用程序,名为EXEVIEW.EXE。创建这一示例目的有二:首先,我需要测试PEFILE.DLL的函数,并且某些情况要求我同时查看多个文件;其次,很多解决PE文件格式的工作和直接观看数据有关。例如,要弄懂导入地址名称表是如何构成的,我就得同时查看.idata段头部、导入映像数据目录、可选头部以及当前的.idata段实体,而EXEVIEW.EXE就是查看这些信息的最佳示例。 闲话少叙,让我们开始吧。PE文件结构PE文件格式被组织为一个线性的数据流,

5、它由一个MS-DOS头部开始,接着是一个是模式的程序残余以及一个PE文件标志,这之后紧接着PE文件头和可选头部。这些之后是所有的段头部,段头部之后跟随着所有的段实体。文件的结束处是一些其它的区域,其中是一些混杂的信息,包括重分配信息、符号表信息、行号信息以及字串表数据。我将所有这些成分列于图1。图1.PE文件映像结构从MS-DOS文件头结构开始,我将按照PE文件格式各成分的出现顺序依次对其进行讨论,并且讨论的大部分是以示例代码为基础来示范如何获得文件的信息的。所有的源码均摘自PEFILE.DLL模块的PEFILE.C文件。这些示例都利用了Windows NT最酷的特色之一内存映射文件,这一特色

6、允许用户使用一个简单的指针来存取文件中所包含的数据,因此所有的示例都使用了内存映射文件来存取PE文件中的数据。注意:请查阅本文末尾关于如何使用PEFILE.DLL的那一段。MS-DOS头部/实模式头部如上所述,PE文件格式的第一个组成部分是MS-DOS头部。在PE文件格式中,它并非一个新概念,因为它与MS-DOS 2.0以来就已有的MS-DOS头部是完全一样的。保留这个相同结构的最主要原因是,当你尝试在Windows 3.1以下或MS-DOS 2.0以上的系统下装载一个文件的时候,操作系统能够读取这个文件并明白它是和当前系统不相兼容的。换句话说,当你在MS-DOS 6.0下运行一个Window

7、s NT可执行文件时,你会得到这样一条消息:“This program cannot be run in DOSmode.”如果MS-DOS头部不是作为PE文件格式的第一部分的话,操作系统装载文件的时候就会失败,并提供一些完全没用的信息,例如:“The name specified is not recognized as an internal or external command, operable program or batch file.”MS-DOS头部占据了PE文件的头64个字节,描述它内容的结构如下:01./WINNT.H02. 03.typedef struct _IMAG

8、E_DOS_HEADER /DOS的.EXE头部04.USHORT e_magic; /魔术数字05.USHORT e_cblp; /文件最后页的字节数06.USHORT e_cp; /文件页数07.USHORT e_crlc; /重定义元素个数08.USHORT e_cparhdr; /头部尺寸,以段落为单位09.USHORT e_minalloc; /所需的最小附加段10.USHORT e_maxalloc; /所需的最大附加段11.USHORT e_ss; /初始的SS值(相对偏移量)12.USHORT e_sp; /初始的SP值13.USHORT e_csum; /校验和14.USHO

9、RT e_ip; /初始的IP值15.USHORT e_cs; /初始的CS值(相对偏移量)16.USHORT e_lfarlc; /重分配表文件地址17.USHORT e_ovno; /覆盖号18.USHORT e_res4; /保留字19.USHORT e_oemid; /OEM标识符(相对e_oeminfo)20.USHORT e_oeminfo; /OEM信息21.USHORT e_res210; /保留字22.LONG e_lfanew; /新exe头部的文件地址23.IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;第一个域e_magic,被称为魔术数字,它

10、被用于表示一个MS-DOS兼容的文件类型。所有MS-DOS兼容的可执行文件都将这个值设为0x5A4D,表示ASCII字符MZ。MS-DOS头部之所以有的时候被称为MZ头部,就是这个缘故。还有许多其它的域对于MS-DOS操作系统来说都有用,但是对于Windows NT来说,这个结构中只有一个有用的域最后一个域e_lfnew,一个4字节的文件偏移量,PE文件头部就是由它定位的。对于Windows NT的PE文件来说,PE文件头部是紧跟在MS-DOS头部和实模式程序残余之后的。实模式残余程序实模式残余程序是一个在装载时能够被MS-DOS运行的实际程序。对于一个MS-DOS的可执行映像文件,应用程序就

11、是从这里执行的。对于Windows、OS/2、Windows NT这些操作系统来说,MS-DOS残余程序就代替了主程序的位置被放在这里。这种残余程序通常什么也不做,而只是输出一行文本,例如:“This program requires Microsoft Windows v3.1 or greater.”当然,用户可以在此放入任何的残余程序,这就意味着你可能经常看到像这样的东西:“You cantrun a Windows NT application on OS/2, its simply not possible.”当为Windows 3.1构建一个应用程序的时候,链接器将向你的可执行文件

12、中链接一个名为WINSTUB.EXE的默认残余程序。你可以用一个基于MS-DOS的有效程序取代WINSTUB,并且用STUB模块定义语句指示链接器,这样就能够取代链接器的默认行为。为Windows NT开发的应用程序可以通过使用-STUB:链接器选项来实现。PE文件头部与标志PE文件头部是由MS-DOS头部的e_lfanew域定位的,这个域只是给出了文件的偏移量,所以要确定PE头部的实际内存映射地址,就需要添加文件的内存映射基地址。例如,以下的宏是包含在PEFILE.H源文件之中的:1./PEFILE.H2. 3.#defineNTSIGNATURE(a) (LPVOID)(BYTE *)a

13、+ 4.(PIMAGE_DOS_HEADER)a)->e_lfanew)在处理PE文件信息的时候,我发现文件之中有些位置需要经常查阅。既然这些位置仅仅是对文件的偏移量,那么用宏来实现这些定位就比较容易,因为它们较之函数有更好的表现。请注意这个宏所获得的是PE文件标志,而并非PE文件头部的偏移量。那是由于自Windows与OS/2的可执行文件开始,.EXE文件都被赋予了目标操作系统的标志。对于Windows NT的PE文件格式而言,这一标志在PE文件头部结构之前。在Windows和OS/2的某些版本中,这一标志是文件头的第一个字。同样,对于PE文件格式,Windows NT使用了一个DWO

14、RD值。以上的宏返回了文件标志的偏移量,而不管它是哪种类型的可执行文件。所以,文件头部是在DWORD标志之后,还是在WORD标志处,是由这个标志是否Windows NT文件标志所决定的。要解决这个问题,我编写了ImageFileType函数(如下),它返回了映像文件的类型:01./PEFILE.C02. 03.DWORD WINAPIImageFileType (LPVOID lpFile)04.05./*首先出现的是DOS文件标志 */06.if (*(USHORT *)lpFile= IMAGE_DOS_SIGNATURE)07.08./*由DOS头部决定PE文件头部的位置 */09.if

15、 (LOWORD(*(DWORD *)NTSIGNATURE(lpFile) =10.IMAGE_OS2_SIGNATURE|11.LOWORD(*(DWORD *)NTSIGNATURE(lpFile) =12.IMAGE_OS2_SIGNATURE_LE)13.return (DWORD)LOWORD(*(DWORD *)NTSIGNATURE(lpFile);14.else if (*(DWORD *)NTSIGNATURE(lpFile) =15.IMAGE_NT_SIGNATURE)16.return IMAGE_NT_SIGNATURE;17.else18.return IMAGE

16、_DOS_SIGNATURE;19.20.else21./*不明文件种类 */22.return 0;23.以上列出的代码立即告诉了你NTSIGNATURE宏有多么有用。对于比较不同文件类型并且返回一个适当的文件种类来说,这个宏就会使这两件事变得非常简单。WINNT.H之中定义的四种不同文件类型有:1./WINNT.H2. 3.#defineIMAGE_DOS_SIGNATURE 0x5A4D / MZ4.#defineIMAGE_OS2_SIGNATURE 0x454E / NE5.#defineIMAGE_OS2_SIGNATURE_LE 0x454C / LE6.#defineIMAGE

17、_NT_SIGNATURE 0x00004550 / PE007.首先,Windows的可执行文件类型没有出现在这一列表中,这一点看起来很奇怪。但是,在稍微研究一下之后,就能得到原因了:除了操作系统版本规范的不同之外,Windows的可执行文件和OS/2的可执行文件实在没有什么区别。这两个操作系统拥有相同的可执行文件结构。现在把我们的注意力转向Windows NT PE文件格式,我们会发现只要我们得到了文件标志的位置,PE文件之后就会有4个字节相跟随。下一个宏标识了PE文件的头部:1./PEFILE.C2. 3.#definePEFHDROFFSET(a) (LPVOID)(BYTE *)a

18、+ 4.(PIMAGE_DOS_HEADER)a)->e_lfanew+ 5.SIZE_OF_NT_SIGNATURE)6.这个宏与上一个宏的唯一不同是这个宏加入了一个常量SIZE_OF_NT_SIGNATURE。不幸的是,这个常量并未定义在WINNT.H之中,于是我将它定义在了PEFILE.H中,它是一个DWORD的大小。既然我们知道了PE文件头的位置,那么就可以检查头部的数据了。我们只需要把这个位置赋值给一个结构,如下:1.PIMAGE_FILE_HEADERpfh;2.pfh= (PIMAGE_FILE_HEADER)PEFHDROFFSET(lpFile);在这个例子中,lpFi

19、le表示一个指向可执行文件内存映像基地址的指针,这就显出了内存映射文件的好处:不需要执行文件的I/O,只需使用指针pfh就能存取文件中的信息。PE文件头结构被定义为:01./WINNT.H02. 03.typedef struct _IMAGE_FILE_HEADER04.USHORT Machine;05.USHORT NumberOfSections;06.ULONG TimeDateStamp;07.ULONG PointerToSymbolTable;08.ULONG NumberOfSymbols;09.USHORT SizeOfOptionalHeader;10.USHORT Ch

20、aracteristics;11.IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;12. 13.#defineIMAGE_SIZEOF_FILE_HEADER 20请注意这个文件头部的大小已经定义在这个包含文件之中了,这样一来,想要得到这个结构的大小就很方便了。但是我觉得对结构本身使用sizeof运算符(译注:原文为“function”)更简单一些,因为这样的话我就不必记住这个常量的名字IMAGE_SIZEOF_FILE_HEADER,而只需要记住结构IMAGE_FILE_HEADER的名字就可以了。另一方面,记住所有结构的名字已经够有挑战性的了,尤其在是这些结构

21、只有WINNT.H中才有的情况下。PE文件中的信息基本上是一些高级信息,这些信息是被操作系统或者应用程序用来决定如何处理这个文件的。第一个域是用来表示这个可执行文件被构建的目标机器种类,例如DEC(R) Alpha、MIPS R4000、Intel(R) x86或一些其它处理器。系统使用这一信息来在读取这个文件的其它数据之前决定如何处理它。Characteristics域表示了文件的一些特征。比如对于一个可执行文件而言,分离调试文件是如何操作的。调试器通常使用的方法是将调试信息从PE文件中分离,并保存到一个调试文件(.DBG)中。要这么做的话,调试器需要了解是否要在一个单独的文件中寻找调试信息

22、,以及这个文件是否已经将调试信息分离了。我们可以通过深入可执行文件并寻找调试信息的方法来完成这一工作。要使调试器不在文件中查找的话,就需要用到IMAGE_FILE_DEBUG_STRIPPED这个特征,它表示文件的调试信息是否已经被分离了。这样一来,调试器可以通过快速查看PE文件的头部的方法来决定文件中是否存在着调试信息。WINNT.H定义了若干其它表示文件头信息的标记,就和以上的例子差不多。我把研究这些标记的事情留给读者作为练习,由你们来看看它们是不是很有趣,这些标记位于WINNT.H中的IMAGE_FILE_HEADER结构之后。PE文件头结构中另一个有用的入口是NumberOfSecti

23、ons域,它表示如果你要方便地提取文件信息的话,就需要了解多少个段更明确一点来说,有多少个段头部和多少个段实体。每一个段头部和段实体都在文件中连续地排列着,所以要决定段头部和段实体在哪里结束的话,段的数目是必需的。以下的函数从PE文件头中提取了段的数目:1.PEFILE.C2.int WINAPINumOfSections(LPVOID lpFile)3.4./*文件头部中所表示出的段数目 */5.return (int)(PIMAGE_FILE_HEADER)6.PEFHDROFFSET(lpFile)->NumberOfSections);7.如你所见,PEFHDROFFSET以及其

24、它宏用起来非常方便。PE可选头部PE可执行文件中接下来的224个字节组成了PE可选头部。虽然它的名字是“可选头部”,但是请确信:这个头部并非“可选”,而是“必需”的。OPTHDROFFSET宏可以获得指向可选头部的指针:1./PEFILE.H2. 3.#defineOPTHDROFFSET(a) (LPVOID)(BYTE *)a + 4.(PIMAGE_DOS_HEADER)a)->e_lfanew+ 5.SIZE_OF_NT_SIGNATURE+ 6.sizeof(IMAGE_FILE_HEADER)7.可选头部包含了很多关于可执行映像的重要信息,例如初始的堆栈大小、程序入口点的位置

25、、首选基地址、操作系统版本、段对齐的信息等等。IMAGE_OPTIONAL_HEADER结构如下:01./WINNT.H02. 03.typedef struct _IMAGE_OPTIONAL_HEADER04./05./标准域06./07.USHORT Magic;08.UCHAR MajorLinkerVersion;09.UCHAR MinorLinkerVersion;10.ULONG SizeOfCode;11.ULONG SizeOfInitializedData;12.ULONG SizeOfUninitializedData;13.ULONG AddressOfEntryPo

26、int;14.ULONG BaseOfCode;15.ULONG BaseOfData;16./17./NT附加域18./19.ULONG ImageBase;20.ULONG SectionAlignment;21.ULONG FileAlignment;22.USHORT MajorOperatingSystemVersion;23.USHORT MinorOperatingSystemVersion;24.USHORT MajorImageVersion;25.USHORT MinorImageVersion;26.USHORT MajorSubsystemVersion;27.USHO

27、RT MinorSubsystemVersion;28.ULONG Reserved1;29.ULONG SizeOfImage;30.ULONG SizeOfHeaders;31.ULONG CheckSum;32.USHORT Subsystem;33.USHORT DllCharacteristics;34.ULONG SizeOfStackReserve;35.ULONG SizeOfStackCommit;36.ULONG SizeOfHeapReserve;37.ULONG SizeOfHeapCommit;38.ULONG LoaderFlags;39.ULONG NumberO

28、fRvaAndSizes;40.IMAGE_DATA_DIRECTORYDataDirectoryIMAGE_NUMBEROF_DIRECTORY_ENTRIES;41.IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;如你所见,这个结构中所列出的域实在是冗长得过分。为了不让你对所有这些域感到厌烦,我会仅仅讨论有用的就是说,对于探究PE文件格式而言有用的。标准域首先,请注意这个结构被划分为“标准域”和“NT附加域”。所谓标准域,就是和UNIX可执行文件的COFF格式所公共的部分。虽然标准域保留了COFF中定义的名字,但是Windows NT仍然将它们

29、用作了不同的目的尽管换个名字更好一些。Magic。我不知道这个域是干什么的,对于示例程序EXEVIEW.EXE示例程序而言,这个值是0x010B或267(译注:0x010B为.EXE,0x0107为ROM映像,这个信息我是从eXeScope上得来的)。MajorLinkerVersion、MinorLinkerVersion。表示链接此映像的链接器版本。随Window NT build 438配套的Windows NT SDK包含的链接器版本是2.39(十六进制为2.27)。SizeOfCode。可执行代码尺寸。SizeOfInitializedData。已初始化的数据尺寸。SizeOfUni

30、nitializedData。未初始化的数据尺寸。AddressOfEntryPoint。在标准域中,AddressOfEntryPoint域是对PE文件格式来说最为有趣的了。这个域表示应用程序入口点的位置。并且,对于系统黑客来说,这个位置就是导入地址表(IAT)的末尾。以下的函数示范了如何从可选头部获得Windows NT可执行映像的入口点。01./PEFILE.C02. 03.LPVOID WINAPIGetModuleEntryPoint(LPVOID lpFile)04.05.PIMAGE_OPTIONAL_HEADERpoh;06.poh= (PIMAGE_OPTIONAL_HEAD

31、ER)OPTHDROFFSET(lpFile);07.if (poh!= NULL)08.return (LPVOID)poh->AddressOfEntryPoint;09.else10.return NULL;11.BaseOfCode。已载入映像的代码(“.text”段)的相对偏移量。BaseOfData。已载入映像的未初始化数据(“.bss”段)的相对偏移量。Windows NT附加域添加到Windows NT PE文件格式中的附加域为Windows NT特定的进程行为提供了装载器的支持,以下为这些域的概述。ImageBase。进程映像地址空间中的首选基地址。Windows NT的Microsoft Win32 SDK链接器将这个值默认设为0x00400000,但是你可以使用-BASE:linker开关改变这个值。SectionAlignment。从Image

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1