PE文件结构详解

PE文件结构详解:
1.PE文件时windows下可执行文件的总称,常见的包括OCX,SYS,DLL,EXE等。
	注意:一个文件是否是PE文件和后缀名无关。
2.PE结构:
	|----------------|
	|   DOS头	 	 |
	|----------------|
	|  		|	     |
	|		|PE签名  |
	| NT头  |PE文件头|
	|		|PE可选头|
	|----------------|
	|		节表	 |
	|----------------|
	|	.rsrc资源节	 |
	|	.text代码节	 |
	|	.data数据节  |
	|----------------|

详解:	DOS头是用来兼容MS-DOS操作系统的,目的是 1.当这个文件在MS-DOS上运行时提示一段文字;2.指明NT头在文件中的位置
		NT头包含windows PE文件的主要信息,其中包括一个‘PE’字样的签名,PE文件头(IMAGE_FILE_HEADER)和PE可选头(IMAGE_OPTIONAL_HEADER32)
		节表:是PE文件后续节的描述,windows根据节表的描述加载每个节。
		节:每个节实际上是一个容器,可以包含代码、数据等等,每个节可以有独立的内存权限,比如代码节默认有读/执行权限,节的名字和数量可以自己定义,未必是上图中的三个。
3.PE文件被加载到内存以后其占用的虚拟地址空间要比在硬盘上占用的空间大一些,这是因为各个节在硬盘上是连续的,而在内存中是按页对齐的
	注意:因为存在这种对齐,所以在PE结构内部,表示某个位置的地址采用了两种方式:
		1.物理地址:针对在硬盘上存储文件中的地址,表示距离文件头的偏移;
		2.虚拟地址(RVA):针对加载到内存以后映象中的地址,表示相对内存映象头的偏移
		3.VA是进程虚拟内存的绝对地址,RVA指的是从某个基准位置开始的相对地址。计算公式如下:RVA+ImageBase=VA //ImageBase基准地址
4.DOS头结构:
typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header  
    WORD   e_magic;         //一个WORD类型,值是一个常数0x5A4D,用文本编辑器查看该值位‘MZ’,可执行文件必须都是'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;                  // Minimum extra paragraphs needed  
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed  
    WORD   e_ss;                        // Initial (relative) SS value  
    WORD   e_sp;                        // Initial SP value  
    WORD   e_csum;                      // Checksum  
    WORD   e_ip;                        // Initial IP value  
    WORD   e_cs;                        // Initial (relative) CS value  
    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)  
    WORD   e_oeminfo;                   // OEM information; e_oemid specific  
    WORD   e_res2[10];                  // Reserved words  
    LONG   e_lfanew;        //为32位可执行文件扩展的域,用来表示DOS头之后的NT头相对文件起始地址的偏移
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;  
  
 5.NT头结构:
 typedef struct _IMAGE_NT_HEADERS {  
    DWORD Signature;  //类似于DOS头中的e_magic,其高16位是0,低16是0x4550,用字符表示是'PE‘。
    IMAGE_FILE_HEADER FileHeader;  //是PE文件头,C语言的定义是这样的:
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;  
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

	PE文件头:(定义了PE文件的一些基本信息和属性,这些属性会在PE加载器加载时用到)
	typedef struct _IMAGE_FILE_HEADER {  
		WORD    Machine;  			//该文件的运行平台,是x86、x64还是I64等等
		WORD    NumberOfSections;   //该PE文件中有多少个节,也就是节表中的项数。
		DWORD   TimeDateStamp;  	//PE文件的创建时间,一般有连接器填写。
		DWORD   PointerToSymbolTable;  //COFF文件符号表在文件中的偏移
		DWORD   NumberOfSymbols;  	//符号表的数量
		WORD    SizeOfOptionalHeader;  //紧随其后的可选头的大小。
		WORD    Characteristics;  //可执行文件的属性,
	} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;  
	
	PE可选头:
	typedef struct _IMAGE_OPTIONAL_HEADER {  
		WORD    Magic;  //表示可选头的类型。0x10b 32位PE可选头  0x20b 64位PE可选头  
		BYTE    MajorLinkerVersion;  //链接器的版本号
		BYTE    MinorLinkerVersion; 
		DWORD   SizeOfCode;  	 //代码段的长度,如果有多个代码段,则是代码段长度的总和。
		DWORD   SizeOfInitializedData;  //初始化的数据长度。
		DWORD   SizeOfUninitializedData;  //未初始化的数据长度
		DWORD   AddressOfEntryPoint;  //程序入口的RVA,对于exe这个地址可以理解为WinMain的RVA
		DWORD   BaseOfCode;  //代码段起始地址的RVA
		DWORD   BaseOfData;  //数据段起始地址的RVA。
		DWORD   ImageBase;   //映象基地址,这个基地址是建议,对于DLL来说,如果无法加载,系统会自动为其选择地址。
		DWORD   SectionAlignment;  //节对齐,PE中的节被加载到内存时会按照这个域指定的值来对齐 比如0x1000
		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];  //数据目录,这是一个数组
	} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;  
	
	数据目录:(数组中的每一项对应一个特定的数据结构,包括导入表,导出表等等,具体哪一项表示什么内容请查看资料)
	typedef struct _IMAGE_DATA_DIRECTORY {  
		DWORD   VirtualAddress; // 是一个RVA
		DWORD   Size;  	//是一个大小
	} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;  	
	注意:要从这个数组中获取具体某一项的值可以通过函数获取:
	PVOID NTAPI RtlImageDirectoryEntryToData(
		PVOID Base, //Base:模块基地址。也就是数组地址
		BOOLEAN MappedAsImage, //MappedAsImage:是否映射为映象。
		USHORT Directory, //Directory:数据目录项的索引。有定义好的具体的宏
		PULONG Size		//对应数据目录项的大小
	);
	//比如Directory=0;则表示导出表大小,如果一个模块导出了函数,那么这个函数会被记录在导出表中,这样通过GetProcAddress函数就能动态获取到函数的地址
	//导出的时候,可以按照函数名导出(显示导出函数名字中有一些符号比如??@@),也可以按照序号导出,
	#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory  
	#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory  
	#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory  
	#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory  
	#define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory  
	#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table  
	#define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory  
	#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data  
	#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of GP  
	#define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS Directory  
	#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory  
	#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   // Bound Import Directory in headers  
	#define IMAGE_DIRECTORY_ENTRY_IAT            12   // Import Address Table  
	#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors  
	#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor  
	
	
 
	节区结构:
	#define IMAGE_SIZEOF_SHORT_NAME  8
	typedef struct _IMAGE_SECTION_HEADER {
		BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];//节区名称,如“.text”  不足8位则用0填充
		union {
				DWORD   PhysicalAddress;//物理地址
				DWORD   VirtualSize;//实际的节区大小
		} Misc;
		DWORD   VirtualAddress;//节区被装载到内存中的RVA地址
		DWORD   SizeOfRawData;// 在PE文件中对齐后的大小
		DWORD   PointerToRawData;// 在整个PE文件中的偏移量
		DWORD   PointerToRelocations;//节区在PE文件中的偏移
		DWORD   PointerToLinenumbers; // 行号表的偏移(供调试使用)
		WORD    NumberOfRelocations;// 在PE文件中使用,重定位项数目
		WORD    NumberOfLinenumbers;// 行号表中行号的数目
		DWORD   Characteristics;//节区的属性,如可读、可写、可执行等
	} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;


	
	
	
	

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值