PE简介
PE文件衍生于早期建立的COFF文件格式,EXE和DLL文件实际上用的是同一种文件格式,唯一的区别就是用一个字段标识出这个文件是EXE还是DLL。64位Windows格式为PE32+。只是简单的将以前的32位字段扩展到64位。
重要要点
要认识到PE文件不是作为单一内存映射文件被装入内存的。
PE加载器通过遍历PE文件决定哪一部分被映射。
磁盘上的数据结构布局和内存中的数据结构布局是一致的。
PE文件被装入内存后,内存中的版本称为模块。起始地址(也被称为基地址ImageBase)被当做模块句柄
按照默认设置,用VC++建立起来的EXE文件基地址是00400000h,DLL文件基地址是10000000h
PE尽管有一个首选的载入基址,但是他们可以载入到进程空间的任何地方,所以不能依赖PE的载入点,所以出现了相对虚拟地址RVA(Relative Virtual Address).PE用语里,实际的内存基址称为VA(Virtual Address)
VA = ImageBase + RVA
PE文件结构:
DOS头
由DOS MZ头和DOS stub组成,其中最重要的是e_magic 和 e_lfanew(file address of new header)
**e_magic **为固定的5A4Dh,其ascii值为“MZ”
e_lfanew为真正的PE文件头(PE Header)的相对偏移(很重要!!!) 位于开始的3C处,占用四个字节。
PE文件头
PE文件头是NT映像头的简称,即IMAGE_NT_HEADER
由三个字段组成
IMAGE_NT_HEADERS STRUCT
Signatrue DWORD ;其ASCII值为”PE00”
FileHeader IMAGE_FILE_HEADER
OptionalHeader IMAGE_OPTIONAL_HEADER32
IMAGE_FILE_HEADER STRUCT
Machine WORD 运行平台
NumberOfSections WORD 区块数目
TimeDateStamp DWORD 时间戳(自从GMT开始的秒数)
PointerToSymbolTable DWORD 符号表指针(用于调试)
NumberOfSymbols DWORD 符号表符号个数
SizeOfOptionalHeader WORD 可选头大小(IMAGE_OPTIONAL_HEADER32)
Characteristics WORD 文件属性(通过相关的位运算得到的)
IMAGE_FILE_HEADER ENDS
可选映像头(IMAGE_OPTIONAL_HEADER32):
IMAGE_OPTIONAL_HEADER32 STRUCT
+18h WORD Magic; // 标志字, ROM 映像(0107h),普通可执行文件(010Bh)
+1Ah BYTE MajorLinkerVersion; // 链接程序的主版本号
+1Bh BYTE MinorLinkerVersion; // 链接程序的次版本号
+1Ch DWORD SizeOfCode; // 所有含代码的节的总大小
+20h DWORD SizeOfInitializedData; // 所有含已初始化数据的节的总大小
+24h DWORD SizeOfUninitializedData; // 所有含未初始化数据的节的大小
+28h DWORD AddressOfEntryPoint; // 程序执行入口RVA
+2Ch DWORD BaseOfCode; // 代码的区块的起始RVA
+30h DWORD BaseOfData; // 数据的区块的起始RVA
+34h DWORD ImageBase; // 程序的首选装载地址
+38h DWORD SectionAlignment; // 内存中的区块的对齐大小
+3Ch DWORD FileAlignment; // 文件中的区块的对齐大小
+40h WORD MajorOperatingSystemVersion; // 要求操作系统最低版本号的主版本号
+42h WORD MinorOperatingSystemVersion; // 要求操作系统最低版本号的副版本号
+44h WORD MajorImageVersion; // 可运行于操作系统的主版本号
+46h WORD MinorImageVersion; // 可运行于操作系统的次版本号
+48h WORD MajorSubsystemVersion; // 要求最低子系统版本的主版本号
+4Ah WORD MinorSubsystemVersion; // 要求最低子系统版本的次版本号
+4Ch DWORD Win32VersionValue; // 莫须有字段,不被病毒利用的话一般为0
+50h DWORD SizeOfImage; // 映像装入内存后的总尺寸
+54h DWORD SizeOfHeaders; // 所有头 + 区块表的尺寸大小
+58h DWORD CheckSum; // 映像的校检和
+5Ch WORD Subsystem; // 可执行文件期望的子系统
+5Eh WORD DllCharacteristics; // DllMain()函数何时被调用,默认为 0
+60h DWORD SizeOfStackReserve; // 初始化时的栈大小
+64h DWORD SizeOfStackCommit; // 初始化时实际提交的栈大小
+68h DWORD SizeOfHeapReserve; // 初始化时保留的堆大小
+6Ch DWORD SizeOfHeapCommit; // 初始化时提交的堆大小
+70h DWORD LoaderFlags; // 与调试有关,默认为 0
+74h DWORD NumberOfRvaAndSizes; // 下边数据目录的项数,这个字段自Windows NT 发布以来一直是16
+78h IMAGE_DATA_DIRECTORY DataDirectory[16]; // 数据目录表(数目固定为16,很重要!!!)
IMAGE_OPTIONAL_HEADER32 ENDS
数据目录表成员如下:
• #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_COPYRIGHT 7 // (X86 usage)
• #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 -
先记录这两部分 后面的区块之后再补上~