小甲鱼之PE结构学习

小甲鱼系统篇PE结构讲解笔记之小甲鱼是帅比:https://fishc.com.cn/(鱼C论坛)

每个PE文件都是以一个DOS程序开始的,一旦在DOS中执行,才能正常识别。

PE文件的第一个字节起始于一个传统的MS-DOS头部,被称作IMAGE_DOS_HEADER

IMAGE_DOS_HEADER结构:

小甲鱼之PE结构学习

小甲鱼之PE结构学习

 

重点有两个:

       +0h WORD          e_magic   //用于说明DOS文件头

       +3ch      WORD          e_lfanew  //指向PE文件头

“MZ”标识了DOS头

小甲鱼之PE结构学习

 

偏移3c,000000e0,表示PE头的起始位置。

小甲鱼之PE结构学习

PE文件头

PE文件头紧挨着DOS首部。

PE Header是PE相关结构的NT映像头(IMAGE_NT_HEADER)的简称,里面包含许多PE装载器用到的重要字段。

执行体在支持PE文件结构的操作系统中执行时,PE装载器从IMAGE_DOS_HEADER结构中的e_lfanew字段里找到PE header的起始偏移量,加上基地址(内存中)就得到了PE文件头的指针。

IMAGE_NT_HEADER:

  1. IMAGE_NT_HEADERS STRUCT
  2. {
  3. +0h        DWORD                             Signature            
  4. +4h        IMAGE_FILE_HEADER                 FileHeader
  5. +18h      IMAGE_OPTIONAL_HEADER32            OptionlHeader //可选择的32位文件头
  6. }IMAGE_NT_HEADERS ENDS

1、Signature字段:在一个有效的PE文件里,signature字段被设置为00004550和,ASCII码字符为“PE00”,标志一个PE文件头的开始。

小甲鱼之PE结构学习

2、+4h         IMAGE_FILE_HEADER          FileHeader     //

IMAGE_FILE_HEADER结构:

  1. typedef  struct_IMAGE_FILE_HEADER 
  2. {
  3.         WORD        Machine;-----------------//运行平台
  4.         WORD        NumberOfSections;---------//文件的区块数目
  5.         DWORD        TimeDateStamp;------------//文件创建日期和时间
  6.         DWORD        PointerToSymbolTable;-------//指向符号表(主要用于调试)
  7.         DWORD        NumberOfSymbols;--------//符号表中符号个数(主要用于调试)
  8.         WORD        SizeOfOptionalHeader;-----//IMAGE_FILE_HEADER32结构大小
  9.         WORD        Characteristics;//文件属性
  10. }IMAGE_FILE_HEADER*PIMAGE_FILE_HEADER;

 

小甲鱼之PE结构学习

 

Machine可执行文件的目标CPU类型:014c表示x86

NumberOfSections:文件区块数目:0005,5个区块。

TimeDateStamp:格林威治时间记录

PointerToSymbolTable

NumberOfSymbols   :这两个主要用于调试

SizeOfOptionalHeader:紧跟在IMAGE_FILE_HEADE后边的数据结构(IMAGE_OPTION_HEADER)的大小。(32位PE文件通常是000eh,64位PE+文件通常为00f0h)。

Characteristics:文件属性。DLL文件通常为:210eh,exe文件通常为0100h。

 

3、+18h      IMAGE_OPTIONAL_HEADER32            OptionlHeader:

属于IMAGE_FILE_HEADER的补充结构,用于说明其他的文件属性。

typedef struct _IMAGE_OPTIONAL_HEADER 
{
    //
    // Standard fields.  
    //
    +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
    //
    // NT additional fields.    以下是属于NT结构增加的领域。
    //
   +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[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
       //
数据目录表

} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

重要的字段:

AddressOfEntryPoint  指出文件被执行的入口地址(OEP)。

小甲鱼之PE结构学习

ImageBase:指出文件优先装入的地址。

小甲鱼之PE结构学习

SectionAlignment 字段和 FileAlignment字段:SectionAlignment字段指定了节被装入内存后的对齐单位。也就是说,每个节被装入的地址必定是本字段指定数值的整数倍。而FileAlignment字段指定了节存储在磁盘文件中时的对齐单位。

小甲鱼之PE结构学习

IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]:

    可以说是最重要的字段之一,它由16个相同的IMAGE_DATA_DIRECTORY结构组成,虽然PE文件中的数据是按照装入内存后的页属性归类而被放在不同的节中的,但是这些处于各个节中的数据按照用途可以被分为导出表、导入表、资源、重定位表等数据块,这16个IMAGE_DATA_DIRECTORY结构就是用来定义多种不同用途的数据块的(如表17.4所示)。IMAGE_DATA_DIRECTORY结构的定义很简单,它仅仅指出了某种数据块的位置和长度。

IMAGE_DATA_DIRECTORY STRUCT

 VirtualAddress DWORD ? ;数据的起始RVA

 isize DWORD ? ;数据块的长度

IMAGE_DATA_DIRECTORY ENDS

数据目录列表的含义

小甲鱼之PE结构学习

在PE文件中寻找特定的数据时就是从这些IMAGE_DATA_DIRECTORY结构开始的,比如要存取资源,那么必须从第3个IMAGE_DATA_DIRECTORY结构(索引为2)中得到资源数据块的大小和位置;同理,如果要查看PE文件导入了哪些DLL文件的哪些API函数,那就必须首先从第2个IMAGE_DATA_DIRECTORY结构得到导入表的位置和大小。