windows PE文件格式笔记(一)

  • 时间:
  • 来源:互联网
  • 文章标签:

PE简介

PE(Portable Executable)文件是windows操作系统下的可执行文件格式,使用该格式的后缀有.exe,.dll,.sys,.obj等。PE文件是指32为的可执行文件,也称PE32,64位的可执行文件称为PE+或PE32+,是PE(PE32)的一种扩展形式。

PE文件基本结构

PE文件分为DOS头、DOS块、NT头(包括PE头和PE扩展头)、节区头、节区、PE体。

在这里插入图片描述

DOS头&DOS块

DOS头结构体():

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number 字符"MZ"
    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

DOS中比较重要的是第一个成员和最后一个成员,第一个成员为MZ关键字,用作识别,
最后一个成员为PE标准头在文件中的偏移,这两个成员都不可删除或修改,否则程序无法运行,由于目前软件是运行在32位或64位系统上,而DOS头除第一个和最后一个成员其余都只在DOS系统上用到,对他们进行修改并不会影响程序运行。
在这里插入图片描述
红色区域为DOS头,蓝色区域为DOS块

DOS块中存储的其实是一段16位的汇编,拖到IDA将其强制转换为代码得到
在这里插入图片描述
功能为输出一段This program cannot be run in DOS mode然后exit。

NT头

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;                         
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

Signature 为"PE"关键字,位置由_IMAGE_DOS_HEADER最后一个成员得到

NT头第二个成员为PE标准头结构体,第三个成员为PE扩展头结构体

PE标准头

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;              
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

_IMAGE_FILE_HEADER中有四个重要成员,如果他们设置不正确程序将无法正常运行。

#1.Machine
每个CPU都拥有唯一的Machine码,兼容intel X86的Machine码为0x14C,intel X64为0x200。
#2.NumberOfSections
描述文件中存在的节区数量,必须大于0且需要与实际节区数量相同,否则将产生运行错误。
#3.SizeOfOptionalHeader
描述PE扩展头的大小,即NT头的第三个成员,由于在PE32为中为IMAGE_OPTIONAL_HEADER32,在PE32+中为IMAGE_OPTIONAL_HEADER64,两者大小不同,需要在SizeOfOptionalHeader中指出。
#4.Characteristics
用于标识文件属性,是否可运行,是否为DLL文件等信息。

PE扩展头

typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;   为_IMAGE_OPTIONAL_HEADER32时值为0x10B,64时为0x20B
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;  程序入口点RVA,重要
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    //
    // NT additional fields.
    //

    DWORD   ImageBase;    文件加载到内存时的位置,exe的位置与相同,dll不满足则会重定位
    DWORD   SectionAlignment;    节区在内存中对齐的最小单位
    DWORD   FileAlignment;       节区在文件中对齐的最小单位
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;         指定了PE image在虚拟内存中所占空间大小
    DWORD   SizeOfHeaders;       指出整个PE头的大小,第一节去所在位置与SizeOfHeader距文件偏移相同
    DWORD   CheckSum;
    WORD    Subsystem;           用来区分驱动文件(.SYS)和普通可执行文件(.EXE,.DLL)
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes; 指定最后一个成员的数组个数,PE装载器通过识别该值确认数组个数。
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

PE文件在磁盘中和在内存中的大小可能不同,那是因为两者在内存对齐是的最小单位可能不同,最小单位由SectionAlignment和FileAlignment来说明。

节区头

节区头中定义了各节区的属性,PE文件设计者将PE文件分为多个节区,用于存放不用的数据,例如代码,资源文件等。由于CPU并不区分数据和代码,如将数据和代码共同存放可能会造成数据溢出到代码段。

typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];Name成员不像C语言字符串以NULL结尾,需要指定其长度
    union {
            DWORD   PhysicalAddress; 由PE扩展头中的SectionAlignment和FileAlignment决定
            DWORD   VirtualSize;   内存中节区大小由PE扩展头中的SectionAlignment和FileAlignment决定
    } Misc;
    DWORD   VirtualAddress;          内存中节区起始地址(RVA)
    DWORD   SizeOfRawData;           磁盘文件中节区所占大小
    DWORD   PointerToRawData;        磁盘文件中节区起始地址
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;         节区属性(定义了是否可读可写可执行等)
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

本文链接http://www.taodudu.cc/news/show-1782132.html