博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PE文件详解1——PE文件头部解析
阅读量:6082 次
发布时间:2019-06-20

本文共 6264 字,大约阅读时间需要 20 分钟。

参考书籍:《WindowsPE文件权威指南》

MSDN中winnt.h是PE文件定义的最终决定者。
EXE文件与DLL文件之间的区别完全是语义上的,二者PE结构完全相同。唯一区别用一个字段标示处这个文件是exe还是dll。许多DLL扩展,如OCX控件,控制面板等都是DLL,它们有一样的实体。

64位的Windows只是对PE格式做了一些简单的修饰,新格式叫PE32+。没有新的结构加进去,其余的改变只是简单地将以前的32位字段扩展为64位字段。

1.PE文件基本结构:

PE文件的头分为DOS头、NT头、节头。注意,这是本人的分法。这样分法会更加合理,更易理解。因为这三个部分正好构成SizeOfHeaders所指的范围,所以将它们合为“头”。

2.文件头

2.1 DOS头

用记事本打开任何一个镜像文件,其头2个字节必为字符串“MZ”,这是Mark Zbikowski的姓名缩写,他是最初的MS-DOS设计者之一。然后是一些在MS-DOS下的一些参数,这些参数是在MS-DOS下运行该程序时要用到的。在这些参数的末尾也就是文件的偏移0x3C(第60字节)处是是一个4字节的PE文件签名的偏移地址。该地址有一个专用名称叫做“E_lfanew”。这个签名是“PE00”(字母“P”和“E”后跟着两个空字节)。紧跟着E_lfanew的是一个MS-DOS程序。那是一个运行于MS-DOS下的合法应用程序。当可执行文件(一般指exe、com文件)运行于MS-DOS下时,这个程序显示“This program cannot be run in DOS mode(此程序不能在DOS模式下运行)”这条消息。用户也可以自己更改该程序,有些还原软件就是这么干的。同时,有些程序既能运行于DOS又能运行于Windows下就是这个原因。Notepad.exe整个DOS头大小为224个字节,大部分不能在DOS下运行的Win32文件都是这个值。MS-DOS程序是可有可无的,如果你想使文件大小尽可能的小可以省掉MS-DOS程序,同时把前面的参数都清0。

2.1.1 DOS头结构体

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header    WORD   e_magic;                     // Magic number                             //EXE标志 "MZ"    WORD   e_cblp;                      // Bytes on last page of file               //最后部分(页中)的字节数    WORD   e_cp;                        // Pages in file			    //文件中的全部和部分页数    WORD   e_crlc;                      // Relocations				    //重定位表中的指针数    WORD   e_cparhdr;                   // Size of header in paragraphs	            //头部尺寸,以段落为单位    WORD   e_minalloc;                  // Maximum extra paragraphs needed          //所需的最大附加段    WORD   e_ss;                        // Initial (relative) SS value              //初始的SS值    WORD   e_sp;                        // Initial SP value			    //初始的SP值	    WORD   e_csum;                      // Checksum				    //补码校检值    WORD   e_ip;                        // Initial IP value			    //初始的IP值    WORD   e_cs;                        // Initial (relative) CS value		    //初始的CS值    WORD   e_lfarlc;                    // File address of relocation table	    //重定位表的字节偏移量    WORD   e_ovno;                      // Overlay number			    //覆盖号    WORD   e_res[4];                    // Reserved words			    //保留字    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)           //OEM标识符    WORD   e_oeminfo;                   // OEM information; e_oemid specific        //OEM信息    WORD   e_res2[10];                  // Reserved words                           //保留字    LONG   e_lfanew;                    // File address of new exe header           //PE头相对于文件的偏移地址  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
注意:DOS头后是一个整个DOS Stub字节块,其内容随使用的链接器的不同而不同,PE中并没有与之相关的结构

2.2 NT头

紧跟着PE文件签名之后,是NT头。NT头分为三个部分,1.PE文件标识2.PE文件头3.PE扩展头

2.2.1 NT头结构体

typedef struct _IMAGE_NT_HEADERS {    DWORD Signature;								//PE文件标识 “PE\0\0”    IMAGE_FILE_HEADER FileHeader;						//PE文件头    IMAGE_OPTIONAL_HEADER32 OptionalHeader;					//PE扩展头} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

(1)PE文件标准PE头(用于判断PE文件是exe还是dll,得到节的总量)

typedef struct _IMAGE_FILE_HEADER {    WORD    Machine;                         //运行平台     WORD    NumberOfSections;                //PE中节的数量    DWORD   TimeDateStamp;           	     //文件创建日期和时间    DWORD   PointerToSymbolTable;	     //指向符号表(用于调试)    DWORD   NumberOfSymbols;	 	     //符号表中的符号数量(用于调试)    WORD    SizeOfOptionalHeader;  	     //扩展头结构长度    WORD    Characteristics;		     //文件属性} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

(2)PE扩展头(虽然是扩展头,但更像真正的PE头,非常重要,包含各种属性)

typedef struct _IMAGE_OPTIONAL_HEADER {    //    // Standard fields.    //    WORD    Magic;                               //魔幻字  0x10b 32位 0x20b 64位    BYTE    MajorLinkerVersion;             	 //链接器版本号    BYTE    MinorLinkerVersion;		   	 //链接器版本号    DWORD   SizeOfCode;			  	 //所有含代码节的总大小    DWORD   SizeOfInitializedData;	   	 //初始化的数据长度。    DWORD   SizeOfUninitializedData; 		 //未初始化的数据长度。    DWORD   AddressOfEntryPoint;     		 //程序入口的RVA    DWORD   BaseOfCode;		   		 //代码段起始地址的RVA    DWORD   BaseOfData;			    	 //数据段起始地址的RVA    //    // NT additional fields.    //    DWORD   ImageBase;				 //映象(加载到内存中的PE文件)的基地址,这个基地址是建议,对于DLL来说,如果无法加载到这个地址,系统会自动为其选择地址。    DWORD   SectionAlignment;			 //内存中节对齐粒度,PE中的节被加载到内存时会按照这个域指定的值来对齐,比如这个值是0x1000,那么每个节的起始地址的低12位都为0。    DWORD   FileAlignment;			 //文件中节对齐粒度,SectionAlignment必须大于或等于FileAlignment。    WORD    MajorOperatingSystemVersion;	 //所需操作系统的版本号    WORD    MinorOperatingSystemVersion;	 //    WORD    MajorImageVersion;			 //映象的版本号,这个是开发者自己指定的,由连接器填写。    WORD    MinorImageVersion;			 //    WORD    MajorSubsystemVersion;		 //所需子系统版本号    WORD    MinorSubsystemVersion;		 //    DWORD   Win32VersionValue;			 //保留,必须为0。    DWORD   SizeOfImage;			 //映象的大小,PE文件加载到内存中空间是连续的,这个值指定占用虚拟空间的大小。    DWORD   SizeOfHeaders;			 //所有文件头(包括节表)的大小,这个值是以FileAlignment对齐的。    DWORD   CheckSum;				 //映象文件的校验和。    WORD    Subsystem;				 //运行该PE文件所需的子系统    WORD    DllCharacteristics;			 //DLL的文件属性,只对DLL文件有效    DWORD   SizeOfStackReserve;			 //运行时为每个线程栈保留内存的大小。    DWORD   SizeOfStackCommit;			 //运行时为每个线程栈保留内存的大小。    DWORD   SizeOfHeapReserve;                   //运行时为进程堆保留内存大小。    DWORD   SizeOfHeapCommit;			 //运行时进程堆初始占用内存大小。    DWORD   LoaderFlags;			 //保留,必须为0。    DWORD   NumberOfRvaAndSizes;		 //数据目录的项数    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];//数据目录,这是一个数组,定义了PE文件中所有出现的不同类型的数据目录信息} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

2.3 数据目录项(节头)

注:总的数据目录一共由16个相同的_IMAGE_DATA_DIRECTORY组成。

2.3.1 结构体

typedef struct _IMAGE_DATA_DIRECTORY {    DWORD   VirtualAddress;								//数据的起始RVA			    DWORD   Size;									//数据块的大小} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

2.3.2 节表项的数据结构

typedef struct _IMAGE_SECTION_HEADER {    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];            //8个字节的节名    union {                                           //            DWORD   PhysicalAddress;		      //节区大小            DWORD   VirtualSize;    } Misc;    DWORD   VirtualAddress;			      //节区RVA地址    DWORD   SizeOfRawData;			      //在文件中对齐后的地址    DWORD   PointerToRawData;			      //在文件中的偏移    DWORD   PointerToRelocations;		      //在OBJ文件中使用    DWORD   PointerToLinenumbers;		      //行号表的位置(调试用)    WORD    NumberOfRelocations;		      //OBJ文件中使用    WORD    NumberOfLinenumbers;		      //行号表中行号的数量    DWORD   Characteristics;			      //节的属性} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

 

转载于:https://www.cnblogs.com/Toring/p/6628303.html

你可能感兴趣的文章
centos使用docker下安装mysql并配置、nginx
查看>>
关于HTML5的理解
查看>>
需要学的东西
查看>>
Internet Message Access Protocol --- IMAP协议
查看>>
Linux 获取文件夹下的所有文件
查看>>
对 Sea.js 进行配置(一) seajs.config
查看>>
第六周
查看>>
解释一下 P/NP/NP-Complete/NP-Hard 等问题
查看>>
javafx for android or ios ?
查看>>
微软职位内部推荐-Senior Software Engineer II-Sharepoint
查看>>
sql 字符串操作
查看>>
【转】Android布局优化之ViewStub
查看>>
网络安全管理技术作业-SNMP实验报告
查看>>
根据Uri获取文件的绝对路径
查看>>
Flutter 插件开发:以微信SDK为例
查看>>
.NET[C#]中NullReferenceException(未将对象引用到实例)是什么问题?如何修复处理?...
查看>>
边缘控制平面Ambassador全解读
查看>>
Windows Phone 7 利用计时器DispatcherTimer创建时钟
查看>>
程序员最喜爱的12个Android应用开发框架二(转)
查看>>
vim学习与理解
查看>>