首页
社区
课程
招聘
[旧帖] [原创]PE32+文件格式简单说明 0.00雪花
发表于: 2013-9-5 08:04 2500

[旧帖] [原创]PE32+文件格式简单说明 0.00雪花

2013-9-5 08:04
2500
一、PE和PE32+文件格式

    PE格式Windows所使用的32位的文件格式。PE32+则是64位Windows所使用的文件格式,在PE格式的基础上做了一些简单的修饰。PE32+格式较PE格式,没有新的结构出现,将以前的32位字段扩展成64位。在数据结构中,IMAGE_OPTIONAL_HEADER64较IMAGE_OPTIONAL_HEADER32,少了BaseOfData这个变量。以下简单的介绍以下PE32+格式,工具是我自己写的,用于显示PE32+的文件信息(工具是PE32+ Info View,演示的程序是64.exe)。

 

二、PE32+文件格式

    PE32+文件格式跟PE格式的文件层次结构一样,包含MS-DOS头部和PE32+文件头。描述PE格式的文件主要存在于winnt.h。以后的数据结构说明主要从winnt.h文件截取出来。

    (一)MS-DOS头部

    PE32+也不例外,也是以一个DOS程序开始的。当程序在DOS下执行时,DOS就能识别出这是有效的执行体,并且运行紧跟在MZ头部的DOS块(即DOS stub)。DOS块是一个有效的的EXE,在不支持PE文件格式的操作系统中,它将简单地显示一个错误提示,类似于字符串“This program cannot be run in MS-DOS mode”。我们可以根据自己的需要去实现完整的DOS代码。但通常情况下,这部分代码由编译器自动生成。我们把DOS MZ头与DOS块合成DOS文件头。

    PE32+的第一个字节也起始于一个传统的MS-DOS头部,即IMAGE_DOS_HEADER。其数据结构如下:

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header                                   
    WORD   e_magic;                     // Magic number,DOS可执行文件标记“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,DOS代码入口地址IP                
    WORD   e_cs;                        // Initial (relative) CS value,DOS代码入口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)                    
    WORD   e_oeminfo;                   // OEM information; e_oemid specific                 
    WORD   e_res2[10];                  // Reserved words                                    
    LONG   e_lfanew;                    // File address of new exe header,指向PE文件“PE”    
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;                                                       

    (二)PE32+文件头

     紧跟着DOS stub的是PE32+文件头。PE32+文件头是PE相关结构NT映像头(IMAGE_NT_HEADERS)的简称,包含许多PE装载器要用到的重要字段。执行体在支持PE32+文件结构的操作系统中,PE装载器首先从IMAGE_DOS_HEADER结构中的e_lfanew字段里找到PE32+ Header的起始偏移量,加上基址即可得到PE32+文件头。 

 IMAGE_NT_HEADERS64(还有一个是为32位的可执行文件准备得,即IMAGE_NT_HEADERS32,这两个结构几乎没有区别)由三个字段组成:

typedef struct _IMAGE_NT_HEADERS64 {                                                         
    DWORD Signature;                           //PE文件标识,"PE00"                           
    IMAGE_FILE_HEADER FileHeader;              //PE映像文件头,包含PE文件的一些基本信息      
    IMAGE_OPTIONAL_HEADER64 OptionalHeader;    //PE可选映像头,定义了更多的数据              
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;                                                   

 

1.Sinature字段

     在一个有效的PE32+文件里,Signature字段被置为00004550h,对应的ASCII码为“PE00”,#define IMAGE_NT_SIGNATURE定义了这个值。

                   define IMAGE_NT_SIGNATURE                  0x00004550  // PE00                              

     注:DOS头部的e_lfanew字段指向了“PE00”。

2.IMAGE_FILE_HEADER结构

    PE32+的IMAGE_FILE_HEADER结构和PE文件中的结构是一样的,其包含了PE文件的一些基本信息,最重要的一个域指出了IMAGE_OPTIONAL_HEADER64的大小。

typedef struct _IMAGE_FILE_HEADER {                                                         
    WORD    Machine;                      //运行平台                                        
    WORD    NumberOfSections;             //文件的区块数目                                  
    DWORD   TimeDateStamp;                //文件创建日期和时间                              
    DWORD   PointerToSymbolTable;         //指向符号表(用于调试)                          
    DWORD   NumberOfSymbols;              //符号表中符号个数(用于调试)                    
    WORD    SizeOfOptionalHeader;         //IMAGE_OPTIONAL_HEADER64的大小                   
    WORD    Characteristics;              //文件属性                                        
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;                                                   

         注:每个域的具体意义就不在此说明了,具体的可以参考相关PE文件的书籍或者资料。

    3.IMAGE_OPTIONAL_HEADER64

        IMAGE_OPTIONAL_HEADER64(可选映像头)是一个可选的结构,但由于IMAGE_FILE_HEADER结构不足以定义PE文件属性,因此可选映像头中定义了更多的数据,两者连起来就是一个完整的“PE32+头结构”。

typedef struct _IMAGE_OPTIONAL_HEADER64 {                                                        
    WORD        Magic;                            //一个标记字,PE文件为010B,PE32+为020B         
    BYTE        MajorLinkerVersion;               //链接程序的主版本号                           
    BYTE        MinorLinkerVersion;               //链接程序的此版本号                           
    DWORD       SizeOfCode;                       //所有带有IMAGE_SCN_CNT_CODE属性区块的总共大小 
    DWORD       SizeOfInitializedData;            //已初始化数据块的大小                         
    DWORD       SizeOfUninitializedData;          //未初始化数据块的大小                         
    DWORD       AddressOfEntryPoint;              //程序执行入口RVA                              
    DWORD       BaseOfCode;                       //代码段的起始RVA                              
    ULONGLONG   ImageBase;                        //代码段的起始RVA                              
    DWORD       SectionAlignment;                 //当被装入内存的区块对齐大小                   
    DWORD       FileAlignment;                    //磁盘上PE文件内的区块对齐大小                 
    WORD        MajorOperatingSystemVersion;       //操作系统的主版本号                          
    WORD        MinorOperatingSystemVersion;       //操作系统的此版本号                          
    WORD        MajorImageVersion;                //该可执行文件的主版本号,由用户自定义         
    WORD        MinorImageVersion;                //该可执行文件的次版本号,由用户自定义         
    WORD        MajorSubsystemVersion;            //所需子系统主版本号                           
    WORD        MinorSubsystemVersion;            //所需子系统次版本号                           
    DWORD       Win32VersionValue;                //通常被设置为0,从不用的字段                  
    DWORD       SizeOfImage;                      //映像装入内存后的大小                         
    DWORD       SizeOfHeaders;                    //MS-DOS头部,PE头部和区块表的组合尺寸         
    DWORD       CheckSum;                         //映像的检验和。                               
    WORD        Subsystem;                        //一个表明可执行文件所期望的子系统             
    WORD        DllCharacteristics;               //DllMain()函数何时被调用,默认为0.          
    ULONGLONG   SizeOfStackReserve;               //初始化堆栈大小                               
    ULONGLONG   SizeOfStackCommit;                //初始化实际提交堆栈大小                       
    ULONGLONG   SizeOfHeapReserve;                //初始化保留栈的大小,默认值是1MB。            
    ULONGLONG   SizeOfHeapCommit;                 //初始化实际保留栈的大小。默认值为4KB          
    DWORD       LoaderFlags;                      //与调试相关,默认值为0                        
    DWORD       NumberOfRvaAndSizes;              //数据目录的项数,这个字段一般是16.            
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];数据目录表              
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;                                             

    数据目录表IMAGE_DATA_DIRECTORY的结构定义如下:

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

数据目录表成员包括输出表(Export Table)、输入表(Import Table)等数据,具体的各项成员如下:

Export Table                      IMAGE_DIRECTORY_ENTRY_EXPORT             // Export Directory,输出表
Import Tbale                      IMAGE_DIRECTORY_ENTRY_IMPORT             // Import Directory,输入表
Resource Table                    IMAGE_DIRECTORY_ENTRY_RESOURCE           // Resource Directory,资源
Exception Table                   IMAGE_DIRECTORY_ENTRY_EXCEPTION          // Exception Directory,异常
Security Table                    IMAGE_DIRECTORY_ENTRY_SECURITY           // Security Directory,安全
Base relocation Table             IMAGE_DIRECTORY_ENTRY_BASERELOC          // Base Relocation Table,重定位表
Debug                             IMAGE_DIRECTORY_ENTRY_DEBUG              // Debug Directory,调试信息
Architecture                      IMAGE_DIRECTORY_ENTRY_ARCHITECTURE       // Architecture Specific Data,版权信息
Global Ptr                        IMAGE_DIRECTORY_ENTRY_GLOBALPTR          // RVA of GP
Thread local storage(TLS)         IMAGE_DIRECTORY_ENTRY_TLS                // TLS Directory
Load configuration                IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG        // Load Configuration Directory
Bound Import                      IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT       // Bound Import Directory in headers
Import Address Table(IAT)         IMAGE_DIRECTORY_ENTRY_IAT                // Import Address Table
Delay  Import                     IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT       // Delay Load Import Descriptors
COM Descriptor                    IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR     // COM Runtime descriptor

Reserved                                                                   //一般情况为0 

 

    4.区块表

    在PE32+文件头与原始数据之间存在一个区块表,区块表包含每个块在映像中的信息,分别指向不同的区块实体。区块表是一个IMAGE_SECTION_HEADER结构数组,其数目由IMAGE_NT_HEADER64.NumberOfSections决定。

    IMAGE_SECTION_HEADER结构如下:

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文件使用,重定位的偏移            
    DWROD  PointerToLinenumbers;                     //符号表的偏移(供调试用)               
    WORD    NumberOfRelocations;                     //在OBJ文件中使用,重定位项数目          
    WORD    NumberOfLinenumbers;                     //行号表中的行号的数目                   
    DWORD   Characteristics;                         //区块的属性值                                            
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;                                               

  

以下附上工具和演示文件:

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 480
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
楼主好厉害,学习啦,谢谢。
2013-9-5 09:28
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
好东西  123
2013-9-6 00:37
0
雪    币: 238
活跃值: (55)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
4
不错,要是能给出源代码就更好了
2013-9-6 18:38
0
雪    币: 50
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
等有空了,我加了注释之后再上传吧。
2013-9-6 22:38
0
游客
登录 | 注册 方可回帖
返回
//