初识PE结构

初识PE结构

0x01 PE文件简介

在Win32平台上(包括Windows 9x/NT/2000/XP/Server 2003/Vista/CE/7/10),可执行文件格式是PE。“PE”是“Portable Executable File Format”(可移植的执行体)的缩写。PE格式是目前Windows平台上的主流可执行文件格式。它是微软在UNIX平台的COFF(通用对象文件格式)基础上制作而成。最初设计用来提高程序在不同操作系统上的移植性,但实际上这种文件格式仅用在Windows系列操作系统下。PE文件是指32位可执行文件,也称为PE32。64位的可执行文件称为PE+或PE32+,是PE(PE32)的一种扩展形式。

PE

0x02 PE头关键字段说明

1、DOC头:

WORD   e_magic                *                "MZ标记" 用于判断是否为可执行文件        
DWORD  e_lfanew;              *                PE头相对于文件的偏移,用于定位PE文件    

2、标准PE头:

WORD    Machine;              *                程序运行的CPU型号:0x0 任何处理器,0x14C 386及后续处理器                            
WORD    NumberOfSections;     *                文件中存在的节的总数,如果要新增节或者合并节 就要修改这个值                    
DWORD   TimeDateStamp;        *                时间戳:文件的创建时间(和操作系统的创建时间无关),编译器填写的                        
DWORD   PointerToSymbolTable;                                             
DWORD   NumberOfSymbols;                                             
WORD    SizeOfOptionalHeader; *                可选PE头的大小,32位PE文件默认E0h,64位PE文件默认为F0h,大小可以自定义            
WORD    Characteristics;      *                每个位有不同的含义,可执行文件值为10F,即0 1 2 3 8位置1                             

3、可选PE头:

WORD    Magic;        *                说明文件类型:10B:32位下的PE文件,20B:64位下的PE文件                            
BYTE    MajorLinkerVersion;                                            
BYTE    MinorLinkerVersion;                                            
DWORD   SizeOfCode; *                所有代码节的和,必须是FileAlignment的整数倍,编译器填的 ,无用                            
DWORD   SizeOfInitializedData; *                已初始化数据大小的和,必须是FileAlignment的整数倍 编译器填的,无用                            
DWORD   SizeOfUninitializedData; *                未初始化数据大小的和,必须是FileAlignment的整数倍,编译器填的,无用                            
DWORD   AddressOfEntryPoint; *        程序入口                            
DWORD   BaseOfCode; *                代码开始的基址,编译器填的,无用                
DWORD   BaseOfData; *                数据开始的基址,编译器填的,无用                
DWORD   ImageBase;  *                    内存镜像基址                            
DWORD   SectionAlignment; *            内存对齐                            
DWORD   FileAlignment;    *                文件对齐                            
WORD    MajorOperatingSystemVersion;                                            
WORD    MinorOperatingSystemVersion;                                            
WORD    MajorImageVersion;                                            
WORD    MinorImageVersion;                                            
WORD    MajorSubsystemVersion;                                            
WORD    MinorSubsystemVersion;                                            
DWORD   Win32VersionValue;                                            
DWORD   SizeOfImage;   *                内存中整个PE文件的映射的尺寸,可以比实际的值大,但必须是SectionAlignment的整数倍                            
DWORD   SizeOfHeaders; *                所有头+节表按照文件对齐后的大小,否则加载会出错                    
DWORD   CheckSum; *                    校验和,一些系统文件有要求.用来判断文件是否被修改                    
WORD    Subsystem;                                            
WORD    DllCharacteristics;                                            
DWORD   SizeOfStackReserve; *        初始化时保留的堆栈大小                         
DWORD   SizeOfStackCommit; *            初始化时实际提交的大小                         
DWORD   SizeOfHeapReserve; *            初始化时保留的堆大小                             
DWORD   SizeOfHeapCommit; *            初始化时实践提交的大小                     
DWORD   LoaderFlags;                                            
DWORD   NumberOfRvaAndSizes; *        目录项数目    

0x03 节表

1、定位节表

可选PE头后面紧跟着的就是第一个节表.

2、确定节表个数

标志PE头里面的第二个成员:NumberOfSection 存储的就是一个有几个节表

3、节表各字段

#define IMAGE_SIZEOF_SHORT_NAME              8                    
typedef struct _IMAGE_SECTION_HEADER {                    
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];                    
    union {                    
            DWORD   PhysicalAddress;                    
            DWORD   VirtualSize;                    
    } Misc;                    
    DWORD   VirtualAddress;                    
    DWORD   SizeOfRawData;                    
    DWORD   PointerToRawData;                    
    DWORD   PointerToRelocations;                    
    DWORD   PointerToLinenumbers;                    
    WORD    NumberOfRelocations;                    
    WORD    NumberOfLinenumbers;                    
    DWORD   Characteristics;                    
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;    
    1、Name    8个字节,一般情况下是以"\0"结尾的ASCII吗字符串来标识的名称,内容可以自定义                            

    注意:该名称并不遵守必须以"\0"结尾的规律,如果不是以"\0"结尾,系统会截取8个字节的长度进行处理                                

    2、Misc  (双字)是该节在没有对齐前的真实尺寸,该值可以不准确                                

    3、VirtualAddress 节区在内存中的偏移地址。加上ImageBase才是在内存中的真正地址                                        

    4、SizeOfRawData  节在文件中对齐后的尺寸                                    

    5、PointerToRawData 节区在文件中的偏移                                    

    6、PointerToRelocations 在obj文件中使用 对exe无意义                                        

    7、PointerToLinenumbers 行号表的位置 调试的时候使用                                        

    8、NumberOfRelocations 在obj文件中使用  对exe无意义                                        

    9、NumberOfLinenumbers 行号表中行号的数量 调试的时候使用                                        

    10、Characteristics 节的属性    

0x04 PE加载过程

1、根据SizeOfImage的大小,开辟一块缓冲区(ImageBuffer)                                                

2、根据SizeOfHeader的大小,将头信息从FileBuffer拷贝到ImageBuffer

3、根据节表中的信息循环将FileBuffer中的节拷贝到ImageBuffer中,如下图所示:

filebuffer_imagebuffer

0x05 手工解析PE头

这里以ipmsg程序为例,使用010editor打开文件进行手工解析。

1、 DOS头

WORD  e_magic;  //5A4D
WORD  e_cblp;   //0090
WORD  e_cp;     //0003
WORD  e_crlc;   //0000
WORD  e_cparhdr;  //0004
WORD  e_minalloc; //0000
WORD  e_maxalloc; //FFFF
WORD  e_ss;       //0000
WORD  e_sp;       //00B8
WORD  e_csum;     //0000
WORD  e_ip;       //0000
WORD  e_cs;       //0000
WORD  e_lfarlc;   //0040
WORD  e_ovno;     //0000
WORD  e_res[4];   //0000 0000 0000 0000
WORD  e_oemid;    //0000
WORD  e_oeminfo;  //0000
WORD  e_res2[10]; //0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
DWORD e_lfnew;    //0000 00E8

2、 标准PE头

WORD  Machine;              //014C
WORD  NumberOfSections;     //0004
DWORD TimeDataStamp;        //4198 C850
DWORD PointerToSymbolTable; //0000 0000
DWORD NumberOfSymbols;      //0000 0000
WORD  SizeOfOptionalHeader; //00E0
WORD  Characteristics;      //010F

3、 可选PE头

WORD  Magic;                     //010B
BYTE  MajorLinkerVersion;        //06
BYTE  MinorLinkerVersion;        //00
DWORD SizeOfCode;                //0001 A000
DWORD SizeOfInitializedData;     //0000 C000
DWORD SizeOfUninitializedData;   //0000 0000
DWORD AddressOfEntryPoint;       //0001 83D7
DWORD BaseOfCode;                //0000 1000
DWORD BaseOfData;                //0001 B000
DWORD ImageBase;                 //0040 0000
DWORD SectionAlignment;          //0000 1000
DWORD FileAlignment;             //0000 1000
WORD  MajorOperatingSystemVersion; //0004
WORD  MinorOperatingSystemVersion; //0000
WORD  MajorImageVersion;           //0000
WORD  MinorImageVersion;           //0000
WORD  MajorSubsystemVersion;       //0004
WORD  MinorSubsystemVersion;       //0000
DWORD Win32VersionValue;           //0000 0000
DWORD SizeOfImage;                 //0002 7000
DWORD SizeOfHeaders;               //0000 1000
DWORD CheckSum;                    //0000 0000
WORD  Subsystem;                   //0002
WORD  DllCharacteristics;          //0000
DWORD SizeOfStackReserve;          //0010 0000
DWORD SizeOfStackCommit;           //0000 1000
DWORD SizeOfHeapReserve;           //0010 0000
DWORD SizeOfHeapCommit;            //0000 1000
DWORD LoaderFlags;                 //0000 0000
DWORD NumberOfRvaAndSizes;         //0000 0010

4、 节表

8 BYTE Name;                  //0000 0074 7865 742E .text               
DWORD  VirtualSize;           //0001 9722
DWORD  VirtualAddress;        //0000 1000
DWORD  SizeOfRawData;         //0001 A000
DWORD  PointerToRawData;      //0000 1000
DWORD  PointerToRelocation;   //0000 0000
DWORD  PointerToLinenumbers;  //0000 0000
WORD   NumberOfRelocations;   //0000
WORD   NumberOfLinenumbers;   //0000
DWORD  Characteristics;       //6000 0020

8 BYTE Name;                  //0000 6174 6164 742E .rdata               
DWORD  VirtualSize;           //0000 309E
DWORD  VirtualAddress;        //0001 B000
DWORD  SizeOfRawData;         //0000 4000
DWORD  PointerToRawData;      //0001 B000
DWORD  PointerToRelocation;   //0000 0000
DWORD  PointerToLinenumbers;  //0000 0000
WORD   NumberOfRelocations;   //0000
WORD   NumberOfLinenumbers;   //0000
DWORD  Characteristics;       //C000 0040

8 BYTE Name;                  //0000 0061 7461 642E .data               
DWORD  VirtualSize;           //0000 37D8
DWORD  VirtualAddress;        //0001 F000
DWORD  SizeOfRawData;         //0000 4000
DWORD  PointerToRawData;      //0001 F000
DWORD  PointerToRelocation;   //0000 0000
DWORD  PointerToLinenumbers;  //0000 0000
WORD   NumberOfRelocations;   //0000
WORD   NumberOfLinenumbers;   //0000
DWORD  Characteristics;       //C000 0040

8 BYTE Name;                  //0000 0063 7273 722E .rsrc               
DWORD  VirtualSize;           //0000 3FD8
DWORD  VirtualAddress;        //0002 3000
DWORD  SizeOfRawData;         //0000 4000
DWORD  PointerToRawData;      //0002 3000
DWORD  PointerToRelocation;   //0000 0000
DWORD  PointerToLinenumbers;  //0000 0000
WORD   NumberOfRelocations;   //0000
WORD   NumberOfLinenumbers;   //0000
DWORD  Characteristics;       //4000 0040

如下图所示:

petou

jiebiao