PE文件格式详解(2)

来源:互联网 发布:c语言初级程序 编辑:程序博客网 时间:2024/05/16 19:15
1.NT头
接下来说一下NT头,IMAGE_NT_HEADERS。

代码 IMAGE_NT_HEADERS结构体

typedef struct _IMAGE_NT_HEADERS{
    DWORD Signature;                //PE Signature :  50450000 ("PE"00)
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

该结构体由3个成员构成:
            签名(Signature)→值为50450000h("PE"00)
            文件头(File Header)
            可选头(Optional Header)

依然以Notepad.exe为例,使用010 Editor打开。

可以查看其IMAGE_NT_HEADERS。
IMAGE_NT_HEADERS结构体的大小为F8,非常大,接下来分别说一下文件头和可选头两个结构体。

2.NT头:文件头
文件头是表现文件大致属性的IMAGE_FILE_HEADER 结构体

代码 IMAGE_FILE_HEADER结构体

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

IMAGE_FILE_HEADERS结构体中有如下4种重要成员,(若设置不正确,将导致文件无法正常运行)。
#1.Machine
    每个CPU都拥有唯一的Machine码,兼容32位Intel x86芯片的Machine码为14C。
    
定义在winnt.h文件中的Machine码。
代码  Machine码

#define IMAGE_FILE_MACHINE_UNKNOWN    0
#define IMAGE_FILE_MACHINE_I386                0x014c    //Inter 386
#define IMAGE_FILE_MACHINE_R3000            0x0162    //MIPS little-endian,0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000            0x0166    //MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000          0x0168    //MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2   0x0169    //MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA            0x0184    //Alpha_AXP
#define IMAGE_FILE_MACHINE_POWERPC       0x01F0    //IBM Powerpc Little-Endian
#define IMAGE_FILE_MACHINE_SH3                0x01a2    //SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3E               0x01a4    //SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4                 0x01a6    //SH4 little-endian
#define IMAGE_FILE_MACHINE_ARM                0x01c0    //ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB           0x01c2
#define IMAGE_FILE_MACHINE_IA64                0x0200    //Intel 64
#define IMAGE_FILE_MACHINE_MIPS16           0x0266    //MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU        0x0366    //MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16     0x0466    //MIPS
#define IMAGE_FILE_MACHINE_ALPHA64        0x0284    //ALPHA64
#define IMAGE_FILE_MACHINE_AXP64            IMAGE_FILE_MACHINE_ALPHA64

#2.NumberOfSections
    PE文件把代码、数据、资源等一句属性分类到各个节区中储存。
    NumberOfSections用来指出文件中存在的节区数量。该值一定要大于0,其当定义的节区数量与实际节区不同时,将发生运行错误。

#3.SizeOfOptionalHeader
    IMAGE_NT_HEADER结构体的最后一个成员为IMAGE_OPTIONAL_HEADER32结构体。SizeOfOptionalHeader成员用来之处IMAGE_OPTIONAL_HEADER32结构体的长度。IMAGE_OPTIONAL_HEADER32结构体有C语言编写而成,故其大小已经确定。Windows的PE装载器需要查看IMAGE_FILE_HEADER的SizeOfOptionalHeader值,从而识别出IMAGE_OPTIONAL_HERADER32的结构体的大小。
   注:PE32+格式的文件,使用的是IMAGE_OPTIONAL_HEADER64结构体(不是IMAGE_OPTIONAL_HEADER32结构体!!!两个结构体的大小是不一样的)所以需要在 SizeOfOptionalHeader成员中明确指出结构体的大小。

#4.Characteristics
该字段用于表示文件的属性,文件是否是可运行的形态,是否为DLL文件等信息,以bit OR形式组合起来。

定义在winnt.h文件中的Characteristics值。(注意0002h与2000h

代码 Characteristics
#define IMAGE_FILE_RELOCS_STRIPPED                       0x0001    //Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE                     0x0002    //File is executable
                                                                                                     //(i.e. no unresolved externel  references). 
#define IMAGE_FILE_LINE_NUMS_STRIPPED                 0x0004    //Line numbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED               0x0008    //Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM                   0x0010    //Agressively trim working set.
#define IMAGE_FILE_LARGE_ADDRESS_AWARE             0x0020    //App can handle >2gb addresses
#define IMAGE_FILE_BYTES_RESVERSED_LO                  0x0080    //byte of machine word are reversed
#define IMAGE_FILE_32BIT_MACHINE                           0x0100    //32 bit word machine
#define IMAGE_FILE_DEBUG_STRIPPED                         0x0200    //Debugging info stripped from file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP  0x0400    //If Image is on removable media,
                                                                                                    //copy and run from the swap file
#define IMAGE_FILE_NET_RUN_FROM_SWAP                0x0800   //If Image is on Net,copy and run from the swap file.
#define IMAGE_FILE_SYSTEM                                         0x1000    //System File
#define IMAGE_FILE_DLL                                                0x2000   //File is a DLL
#define IMAGE_FILE_UP_SYSTEM_ONLY                        0x4000    //File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI                      0x8000    //byte of machine word are reversed

注:PE文件中Characteristics的值有可能不是0002h(not executable),例如:*.obj的object文件及resource DLL文件等,2000h表明PE文件是否为DLL文件。

IMAGE_FILE_HEADER的TimeDateStamp成员,该成员的值不影响文件运行,用来记录编译器创建文件的时间(并不是所有的开发工具都提供了设置该值的工具,Delphi则并没有提供)。

3.NT头:可选头
IMAGE_OPTIONAL_HEADER32是PE头结构体中最大的。

代码 IMAGE_OPTIONAL_HEADER32结构体。

typedef struct _IMAGE_DATA_DIRECTORY{
    DWORD    VirtualAddress;
    DWORD    Size;
}    IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

typedef struct _IMAGE_OPTIONAL_HEADER{

    WORD     Magic;
    BYTE        MajorLinkerVersion;
    BYTE        MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUnitializedData;
    DWORD    AddressOfEntryPoint;
    DWORD    BaseOfCode;
    DWORD    BaseOfData;
    DWORD    ImageBase;
    DWORD    SectionAlignment;
    DWORD    FileAlignment;
    WORD       MajorOperatingSystemVersion;
    WORD       MinorOperatingSystemVersion;
    WORD       MajorImageVersion;
    WORD       MinorImageVersion;
    WORD       MajorSubsystemVersion;
    WORD       MinorSubsystemVersion;
    DWORD    Win32VersionValue;
    DWORD    SizeOfImage;
    DWORD    SizeOfHeaders;
    DWORD    CheckSum;
    WORD       Subsystem;
    WORD       DllCharacteristics;
    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;

IMAGE_OPTIONAL_HEADER32结构体中有如下几种重要成员,(若设置不正确,将导致文件无法正常运行)。
#1.Magic
   为IMAGE_OPTIONAL_HEADER32结构体是,Magic码为10B;为IMAGE_OPTIONAL_HEADER64结构体时,Magic码为20B。
#2.AddressOfEntryPoint
   AddressOfEntryPoint持有EP的RVA值。该值指出程序最先执行的代码起始地址。
#3.ImageBase
   进程虚拟内存的范围为0~FFFFFFFF(32位操作系统,64位的操作系统为0~FFFFFFFFFFFFFFFF(16个))。PE文件被加载到如此大的内存中时ImageBase指出文件优先装入地址。
    EXE/DLL文件被装在到用户内存的0~7FFFFFFF(32位系统)中,SYS文件被载入内核内存的80000000~FFFFFFFF中。一般而言,使用开发工具创建好EXE文件后,其ImageBase的值为00400000,DLL文件的ImageBase为100000000(可以指定为其他值)。
   注:执行PE文件时,PE装载器先差un构建进程,再将文件载入内存,然后把EIP寄存器的值设置为ImageBase+AddressOfEntryPoint.
#4.SectionAlignment,FileAlignment
    PE文件的Body部分划分为若干节区,这些节存储着不同类别的数据。FileAlignment指定了节区在磁盘文件中的最小单位,SectionAlignment指定了节区在内存中的最小单位(SectionAlignment与FlieAlignment的值不一定相同)。磁盘文件或内存节区的大小必定为FileAlignment或SectionAlignment的整数倍。
#5.SizeOfImage
   加载PE文件到内存时,SizeOfImage指定了PE Image在虚拟内存中所占空间的大小。一般而言,文件与加载到内存之后两者的大小是不相同的。
#6.SizeOfHeader
    SizeOfHeader用来指出整个PE头的大小,当然这个值也必须为FileAlignment的整数倍。第一节区所在位置与SizeOfHeader据文件开始偏移的量相同。
#7.Subsystem
    这个值是用来区分系统驱动文件安(*.sys)和普通的可执行文件的(*.exe,*.dll)。
    值         含义                       备注
    1         Driver文件           系统驱动
    2         GUI文件                窗口应用程序
    3         CUI文件                控制台应用程序
#8.NumberOfRvaAndSizes
   NumberOfRvaAndSizes用来制定DataDirectory(IMAGE_OPTIONAL_HEADER32结构体最后一个成员)数组的个数。虽然结构体定义中明确指出了数组个数为16(#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16)但是PE装载查看的NumberOfRvaAndSizes的值来识别数组的大小(即数组大小也可能不为16)。
#9.DataDirectory
    DataDirectory是有IMAGE_DATA_DIRECTORY结构体组成的数组,数组的每项都有被定义的值。

代码 DataDirectory结构体数组   

DataDirectory[0] = EXPORT Directory
DataDirectory[1] = IMPOTR Directory
DataDirectory[2] = RESOURCE Directory
DataDirectory[3] = EXCEPTION Directory
DataDirectory[4] = SECURITY Directory
DataDirectory[5] = BASERELOC Directory
DataDirectory[6] = DEBUG Directory
DataDirectory[7] = COPYRIGHT Directory
DataDirectory[8] = GLOBALPTR Directory
DataDirectory[9] = TLS Directory
DataDirectory[A] = LOAD_CONFIG Directory
DataDirectory[B] = BOUND_IMPORT Directory
DataDirectory[C] = IAT Directory
DataDirectory[D] = DELAY_IMPORT Directory
DataDirectory[E] = COM_DESCRIPTOR Directory
DataDirectory[F] = Reserver Directory

IMAGE_OPTIONAL_HEADER
使用010 Editor查看Notepad.exe的IMAGE_OPTIONAL_HEADER整个结构体。