pe文件结构

PE文件的全称是Portable Executable,意为可移植的可执行文件,是微软Windows操作系统上广泛使用的程序文件格式(包括间接被执行的文件,如DLL)。PE文件被称为“可移植的”是因为在所有平台(如x86、Alpha、MIPS等)上实现的Windows NT及其后续版本(如Windows 95、Windows 2000、Windows XP、Windows Vista、Windows 7、Windows 8、Windows 10等)都使用相同的可执行文件格式。

ELF(Executable and Linking Format可执行可链接格式)文件结构是Linux平台的可执行文件,相比于pe文件,在不同内核编译的ELF文件在不同内核的环境下是无法使用的。

PE文件的识别

判断一个文件是不是PE文件,不能只看他能不能运行,而是要看他符不符合"PE指纹"。

PE指纹是指用于识别PE文件的一种特征标识。

具体来说,PE指纹的识别过程通常包括以下几个步骤:

  1. 观察前两个字节:打开PE文件,以二进制方式(010editor)查看文件的前两个字节。在PE文件中,这两个字节通常是“MZ”,这是DOS可执行文件的标志,用于兼容旧版DOS系统。虽然“MZ”并不是PE文件特有的,但它通常作为PE文件头部的开始。

  2. 查找PE标识:在文件偏移量为0x3C(即第60个字节)的位置,有一个DWORD值,它指向DOS块末尾的PE文件头的偏移量。根据这个偏移量,可以找到PE文件头的开始位置。在PE文件头的开始位置,紧接着“MZ”之后,通常会有“PE”或“PE\0\0”(即50 45 00 00)这样的字节序列,这是PE文件的真正标识。

  3. 验证PE头结构:一旦找到PE标识,就可以进一步验证PE文件头的结构是否符合PE格式的标准。PE文件头包含了关于文件的重要信息,如目标机器类型、节的数量、入口点地址等。

如果以上步骤都满足,那么这就是一个PE文件,如下例:

 而作为反例,下面这个apk文件就不满足

PE文件的整体结构

1.DOS部分

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
  DWORD e_lfanew;          // File address of new exe header 
 } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

DOS头是一个结构体,占2*16+4+14*2=64个字节。里面的e_magic和e_lfanew是鉴定PE指纹重要的依据,非常重要。

DOS块是PE文件格式中用于保持向下兼容性的一个部分,它位于DOS文件头和PE文件头之间。虽然在现代Windows系统中,DOS块的内容通常不会被执行,只会向终端输出一行字:“This program cannot be run in DOS mode”,但它仍然是PE文件格式的一个重要组成部分。程序员可以根据自己的需求来设计和实现DOS块的内容,以提高程序的兼容性和用户体验。

2.PE文件头

PE文件头包括PE标识符(4字节)、IMAGE_FILE_HEADER结构体(20字节)和IMAGE_OPTIONAL_HEADER结构体。IMAGE_FILE_HEADER结构体是标准文件头,IMAGE_OPTIONAL_HEADER结构体是可选文件头。

1.IMAGE_FILE_HEADER结构体

  • 内容:包含了关于PE文件的基本信息,如机器类型(如x86或x64)、节的数量、时间戳、文件属性等。
  • 关键字段
    • Machine:指定了PE文件的目标机器类型,如0x014C表示x86,0x8664表示x64。
    • NumberOfSections:文件中节的数量。
    • TimeDateStamp:文件创建的时间。
    • SizeOfOptionalHeader:IMAGE_OPTIONAL_HEADER32结构的大小
typedef struct _IMAGE_FILE_HEADER {
  WORD  Machine;        // 可运行在什么样的CPU上。
  WORD  NumberOfSections;   // 文件的区块(节)数
  DWORD  TimeDateStamp;     // 文件的创建时间。
  DWORD  PointerToSymbolTable; // 指向符号表(用于调试)
  DWORD  NumberOfSymbols;    // 符号表中符号的个数(用于调试)
  WORD  SizeOfOptionalHeader; // IMAGE_OPTIONAL_HEADER32结构的大小,可改变,32位为E0,64位为F0
  WORD  Characteristics;    // 文件属性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

2.IMAGE_OPTIONAL_HEADER结构

typedef struct _IMAGE_OPTIONAL_HEADER {
  //
  // Standard fields.
  //
   
 * WORD  Magic;         //说明文件的类型 PE32:10BH PE32+:20BH  Rom映像文件:107H
  BYTE  MajorLinkerVersion;   //链接器主版本号
  BYTE  MinorLinkerVersion;   //链接器次版本号
 * DWORD  SizeOfCode;       //所有代码节的总和(基于文件对齐) 编译器填的
 * DWORD  SizeOfInitializedData; //包含所有已经初始化数据的节的总大小 编译器填的 
 * DWORD  SizeOfUninitializedData;//包含未初始化数据的节的总大小 编译器填的
  
 * DWORD  AddressOfEntryPoint;  //程序入口RVA  在大多数可执行文件中,这个地址不直接指向Main、 
                   WinMain或DIMain函数,而指向运行时的库代码并由它来调用上述函数
 * DWORD  BaseOfCode;       //代码起始RVA,编译器填的  
 * DWORD  BaseOfData;       //数据段起始RVA,编译器填的  
  
  //
  // NT additional fields.
  //
  
 * DWORD  ImageBase;       //内存镜像基址 ,可链接时自己设置
 * DWORD  SectionAlignment;    //内存对齐   一般一页大小4k
 * DWORD  FileAlignment;     //文件对齐   一般一扇区大小512字节,现在也多4k
  WORD  MajorOperatingSystemVersion; //标识操作系统版本号 主版本号
  WORD  MinorOperatingSystemVersion; //标识操作系统版本号 次版本号
  WORD  MajorImageVersion;   //PE文件自身的主版本号 
  WORD  MinorImageVersion;   //PE文件自身的次版本号 
  WORD  MajorSubsystemVersion; //运行所需子系统主版本号
  WORD  MinorSubsystemVersion; //运行所需子系统次版本号
  DWORD  Win32VersionValue;   //子系统版本的值,必须为0
 * DWORD  SizeOfImage; //内存中整个PE文件的映射的尺寸,可比实际的值大,必须是SectionAlignment            
                         的整数倍  
 * DWORD  SizeOfHeaders;     //所有头+节表按照文件对齐后的大小,否则加载会出错
 * DWORD  CheckSum;        //校验和,一些系统文件有要求.用来判断文件是否被修改 
  WORD  Subsystem;       //子系统  驱动程序(1) 图形界面(2) 控制台、DLL(3)
  WORD  DllCharacteristics;   //文件特性 不是针对DLL文件的
 * DWORD  SizeOfStackReserve;   //初始化时保留的栈大小 
 * DWORD  SizeOfStackCommit;   //初始化时实际提交的大小 
 * DWORD  SizeOfHeapReserve;   //初始化时保留的堆大小
 * DWORD  SizeOfHeapCommit;    //初始化时保留的堆大小
  DWORD  LoaderFlags; 
  DWORD  NumberOfRvaAndSizes;  //数据目录项数目
  IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; //数据目录表
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

默认情况下它在32位下是224字节,在64位下是240字节,也可以通过IMAGE_FILE_HEADER结构的成员去获取/修改扩展PE头的宽度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值