前言 
PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL)
 
简述 PE文件使用的是平面地址空间,代码和数据被合并在一起,组成庞大的组织结构。文件的内容分割为不同的区块(如.data、.idata、.text,这些区块甚至可以自己命名),区段中包含代码数据,各个区块按照页边界来对齐,区块没有限制大小,是一个连续的结构。每块都有他自己在内存中的属性,比如:这个块是否可读可写,或者只读等等。
基地址 PE文件加载到内存后,内存中的版本被称为模块 。映射文件的起始地址被成为模块句柄,可以通过模块句柄访问内存中的其他数据结构。这个初始的内存地址也被称为基地址(ImageBase)。
VA & RVA VA:进程虚拟内存的绝对地址
DOS头 在PE头的最前面有一个IMAGE_DOS_HEADER结构体,用于扩展已有的DOS EXE头
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 typedef struct _IMAGE_DOS_HEADER {           WORD   e_magic;                          WORD   e_cblp;                           WORD   e_cp;                             WORD   e_crlc;                           WORD   e_cparhdr;                        WORD   e_minalloc;                       WORD   e_maxalloc;                       WORD   e_ss;                            WORD   e_sp;                          WORD   e_csum;                           WORD   e_ip;               // DOS 代码入口 IP                  WORD   e_cs;               // DOS 代码入口 CS                             WORD   e_lfarlc;                         WORD   e_ovno;                           WORD   e_res[4];                        WORD   e_oemid;                          WORD   e_oeminfo;                        WORD   e_res2[10];                      LONG   e_lfanew;                      } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; 
两个重要成员:
e_magic:DOS签名,一般为ASCII值”MZ“e_lfanew:指示NT头的偏移 
DOS存根(stub) 由代码和数据混合而成的一个大小不固定的可选项,可以存放一些不会影响程序运行的数据,在通常的程序中,会存放This program cannot be run in Dos mode
NT头(《加密与解密) P408) NT头(PE头)结构体有三个成员:签名结构体、文件头、可选头
1 2 3 4 5 typedef  struct  _IMAGE_NT_HEADERS  {	DWORD Signatured; 	IMAGE_FILE_HEADER FileHeader; 	IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADER32, *PIMAGE_NT_HEADERS32; 
NT头:文件头 1 2 3 4 5 6 7 8 9 10 typedef  struct  _IMAGE_FILE_HEADER {     WORD Machine;                        WORD NumberOfSections;               DWORD TimeDateStamp;                 DWORD PointerToSymbolTable;          DWORD NumberOfSymbols;               WORD SizeOfOptionalHeader;           WORD Characteristics;            } 
NT头:可选头 一个NT头的可选结构,因为IMAGE_FILE_HEADER结构不足以定义PE文件的属性,所以该结构中定义了更多的数据,与IMAGE_FILE_HEADER结构连起来成为一个完整的PE文件头结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 typedef struct _IMAGE_OPTIONAL_HEADER {     WORD    Magic;                               // 标识字     BYTE    MajorLinkerVersion;                  // 连接器主版本号     BYTE    MinorLinkerVersion;                  // 连接器次版本号     DWORD   SizeOfCode;                          // 所有含有代码的区块大小     DWORD   SizeOfInitializedData;               // 所有初始化数据区块的大小     DWORD   SizeOfUninitializedData;             // 所有未初始化数据区块大小     DWORD   AddressOfEntryPoint;                 // 程序执行入口 RVA     DWORD   BaseOfCode;                          // 代码区块起始 RVA     DWORD   BaseOfData;                          // 数据区块起始 RVA     DWORD   ImageBase;                           // 默认载入基地址     DWORD   SectionAlignment;                    // 内存中区块对齐值     DWORD   FileAlignment;                       // 文件中区块对齐值     WORD    MajorOperatingSystemVersion;         // 操作系统主版本号     WORD    MinorOperatingSystemVersion;         // 操作系统次版本号     WORD    MajorImageVersion;                   // 用户自定义主版本号     WORD    MinorImageVersion;                   // 用户自定义次版本号     WORD    MajorSubsystemVersion;               // 所需子系统主版本号     WORD    MinorSubsystemVersion;               // 所需子系统次版本号     DWORD   Win32VersionValue;                   // 保留,通常为0     DWORD   SizeOfImage;                         // 映像载入内存后的总尺寸     DWORD   SizeOfHeaders;                       // DOS头、PE文件头和区块表的总大小     DWORD   CheckSum;                            // 映像校验和     WORD    Subsystem;                           // 文件子系统     WORD    DllCharacteristics;                  // 显示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; 
区块 在NT头的下面是一个IMAGE_SECTION_HEADER结构数组,每个IMAGE_SECTION_HEADER包含了它所关联的区块的信息,如位置、长度、属性,其数目在IMAGE_FILE_HEADER中指出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 typedef struct IMAGE_SECTION_HEADER { 	BYTE NAME;                        // 区块名,占8个字节 	union Misc { 		DWORD PhysicalAddress;         		DWORD VirtualSize; 	} 	DWORD VirtualAddress;             // 区块RVA地址 	DWORD SizeOfRawData;              // 文件中对齐后的尺寸 	DWORD PointerToRawData;           // 在文件中的偏移 	DWORD PointerToRelocations;       // 行号表的偏移 	WORD NumberOfRelocations;         // 在OBJ文件中使用,重定位项数目 	WORD NumberOfLinenumbers;         // 行号表中行号的数目 	DWORD Characteris;                // 区块的属性 } IMAGE_SECTIONS_HEADER; 
文件偏移与虚拟地址转换 输入表 
可执行文件使用来自其他DLL的代码或数据的动作称为输入。PE文件被载入时,Windows加载器的工作之一就是定位所有被输入的函数和数据,并让正在载入的文件可以使用那些地址。该过程通过PE表来实现。
 
输入函数:程序调用但是执行代码不在程序中的函数,其代码位于相关的DLL文件中,在调用者程序中只保留相关的函数信息。一旦模块被载入,IAT中将包含所要调用输入函数的地址 
输入表的结构 输入表以一个IMAGE_IMPORT_DESCRIPTOR(IDD)数组开始
1 2 3 4 5 6 7 8 9 10 IMAGE_IMPORT_DESCRIPTOR STRUCT      union          Characteristics           DWORD   ?                       OriginalFirstThunk        DWORD   ?              // 包含指向输入名称表的RVA     ends      TimeDateStamp                 DWORD   ?              // 32位的时间标志     ForwarderChain                DWORD   ?              // 第一个被转向的API的索引,一般为0     Name                          DWORD   ?              // DLL的名字指针     FirstThunk                    DWORD   ?              // 包含指向输入地址表的IAT的RVA IMAGE_IMPORT_DESCRIPTOR ENDS 
 (下面的看懂了再来写)