PE文件 PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件
PE文件是指32位可执行文件,也称为PE32。64位的可执行文件称为PE+或PE32+,是PE(PE32)的一种扩展形式
而不是PE64
结构 网上找了个图
PE文件结构分为五个部分:
DOS文件头
DOS加载模块
PE文件头
区段表
区段
Dos头 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 定义 typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // Magic number 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 WORD e_cs; // Initial (relative) CS value 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 } IMAGE_DOS_HEADER , *PIMAGE_DOS_HEADER ;
我们只需要关注两个域:
e_magic:一个WORD类型,值是一个常数0x4D5A,用文本编辑器查看该值位‘MZ’,可执行文件必须都是’MZ’开头。
e_lfanew:为32位可执行文件扩展的域,用来表示DOS头之后的NT头相对文件起始地址的偏移。
Dos头的特征是4D5A也就是MZ开头。这里面比较有用的信息是最后两个字节(Dos头只有64字节)。
PE头 1 2 3 4 5 6 7 定义 typedef struct _IMAGE_NT_HEADERS { DWORD Signature ; IMAGE_FILE_HEADER FileHeader ; IMAGE_OPTIONAL_HEADER32 OptionalHeader ; } IMAGE_NT_HEADERS32 , *PIMAGE_NT_HEADERS32 ;
PE文件头分为三个结构,第一个为签名字段,第二个为文件头字段,第三个为可选头字段。
Signature:在一个PE文件中Signature字段被设置为4550h,ASCII码为”PE00“。
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 34 35 36 37 38 39 typedefstruct_IMAGE_OPTIONAL_HEADER { WORD Magic;// 标志字, ROM 映像(0107 h),普通可执行文件(010 Bh) BYTE MajorLinkerVersion;// 链接程序的主版本号 BYTE MinorLinkerVersion;// 链接程序的次版本号 DWORD SizeOfCode;// 所有含代码的节的总大小 DWORD SizeOfInitializedData;// 所有含已初始化数据的节的总大小 DWORD SizeOfUninitializedData;// 所有含未初始化数据的节的大小 DWORD AddressOfEntryPoint;// 程序执行入口RVA DWORD BaseOfCode;// 代码的区块的起始RVA DWORD BaseOfData;// 数据的区块的起始RVA // // NT additional fields. 以下是属于NT结构增加的领域。// 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;// 所有头 + 区块表的尺寸大小 DWORD CheckSum;// 映像的校检和 WORD Subsystem;// 可执行文件期望的子系统 WORD DllCharacteristics;// DllMain()函数何时被调用,默认为 0 DWORD SizeOfStackReserve;// 初始化时的栈大小 DWORD SizeOfStackCommit;// 初始化时实际提交的栈大小 DWORD SizeOfHeapReserve;// 初始化时保留的堆大小 DWORD SizeOfHeapCommit;// 初始化时实际提交的堆大小 DWORD LoaderFlags;// 与调试有关,默认为 0 DWORD NumberOfRvaAndSizes;// 下边数据目录的项数,这个字段自Windows NT 发布以来一直是16 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; // 数据目录表} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
区段表 区段表分为.text表、.data表、.rsrc表,区段表相当于区段的目录,里面包含着每个区段的信息,如区段名称、区段大小、区段基地址、区段偏移地址等。
.text:代码段,是在编译或汇编结束时产生的一种块,它的内容全部是指令代码。也有的编译器将该段命名为.code .data:初始化的数据块,是初始化的数据块,包含那些编译时被初始化的变量、字符串 .idata:输入表,包含其他外来dll的函数和数据信息,也就是输入表,也有人称之为导入表。 .rsrc:资源数据块,包含模块的全部资源数据,如图标、菜单、位图等。 .reloc:重定位表,用于保存基址的重定位表。即当装在程序不能按照连接器所指定的地址装载文件是,需要对指令或已经初始化的变量进行调整,该块中也包含了调整过程中所需要的一些数据,如果装载能够正常装在则忽略此段中的数据。 .edata:导出表,是pe文件的输出表,以供其他模块使用,并不是每个pe文件都有此数据段,因为有的文件并不需要输出一些函数,该数据段常见于动态连接库文件中。 .radata:存放调试目录、说明字符串,该数据块并不常见主要是用于存放一些调试信息。
区段