天天看点

PE头解析

这两天对于PE的学习总结:

1.PE结构的应用

(1)windows下exe文件

(2)动态链接库(大部分是以dll为扩展名得文件)

2.关于PE分节

(1)节省硬盘空间   (2)一个应用程序多开

对齐  旧式的电脑 新款
硬盘对齐    200h    1000h
内存对齐  1000h    1000h

3.PE整体结构

DOS头              NT头              节表/块表              .text块               .rdata块                 data块

(后面这几个快不确定位置和数量,这些由节表确定)

下面介绍的都是几个头中重点的几个标识,所以详细的自己百度

4.    DOS头(一般运用在16位系统中 )

WORD   e_magic                *                  "MZ标记" 用于判断是否为可执行文件.  (即判断是否在windows上执行)          

DWORD  e_lfanew;             *                  PE头相对于文件的偏移,用于定位PE文件 

DOS头和NT头之间由垃圾数据填充

5.NT头

NT头分为三部分(1)PE标记(2)标准PE头(3)可选PE头

(1)PE标记   

dword   signature   (由DoS头里e_lfanew确定位置)

(2)标准PE头     fileheader 

          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;      *              文件属性,每个位有不同的含义,普通exe文件值为10Fh 即0 1 2 3 8位置1                                                                                                                                            Dll文件一般是210Eh

(3)可选pe头   optionalheader(由标准pe头里sizeOfOptionalHeader确定)

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;*                初始化时实际提交的大小                     DOS    

DWORD   SizeOfHeapReserve;*                初始化时保留的堆大小                     ...    

DWORD   SizeOfHeapCommit;*                初始化时实践提交的大小                     PE标记    

DWORD   LoaderFlags;                                    标准PE    

DWORD   NumberOfRvaAndSizes;*                目录项数目                    可选PE头    

6.节表(由标准PE头里NumberOfsections可知节表数目)

#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   *       节的属性    

(这是一个节表信息,几个节表信息连续)

7.三种不同的地址

文件中的地址(FA): 在文件地址空间中,文件载入的起始位置总是等于0,FA地址表现为一个偏移地址;

虚拟地址(VA):PE文件被映射到内存中时,在内存中的映射地址;

相对偏移地址(RVA):程序某一结构的VA减去FA的结果;

程序被装载入内存中时,由文件结构不变,故其RVA不变,但装载起始地址不变,因为很难保证计算机的运行状态时时刻刻都是一致的。