note : PE file format study

来源:互联网 发布:java培训骗局 编辑:程序博客网 时间:2024/04/19 16:07

参考资料


http://msdn.microsoft.com/en-us/library/ms680195(v=vs.85).aspx


http://msdn.microsoft.com/en-us/magazine/cc301805.aspx
<<Inside Windows An In-Depth Look into the Win32 Portable Executable File Format>>


http://msdn.microsoft.com/en-us/library/ms809762.aspx
<<Peering Inside the PE: A Tour of the Win32 Portable Executable File Format>>


备注

PE文件结构中分x86和X64两种版本,  记录笔记的时候以 _X 代替

_X means 32 or 64

e.g.     IMAGE_NT_HEADERS32, IMAGE_NT_HEADERS64 以 IMAGE_NT_HEADERS_X代替


PE文件被加载后,在内存中的实体叫映像 (Image)


PE文件从前到后的结构顺序

  Dos头

  NT头 = 文件头 + 可选头

  节区头

PE结构定义

Dos头

    typedef struct _IMAGE_DOS_HEADER        {        WORD   e_magic; ///< 有效性标记        ...        LONG   e_lfanew; ///< offset NtHeaders        } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

IMAGE_DOS_HEADER 不分x86/x64

PE文件有效性 = (IMAGE_DOS_SIGNATURE == e_magic);


Nt头

    typedef struct _IMAGE_NT_HEADERS    {        ULONG Signature; ///< 有效性标记        IMAGE_FILE_HEADER FileHeader; ///< 文件头        IMAGE_OPTIONAL_HEADER_X OptionalHeader; ///< 可选头    } IMAGE_NT_HEADERS_X, *PIMAGE_NT_HEADERS_X;

PE文件有效性 = (IMAGE_NT_SIGNATURE == IMAGE_NT_HEADERS->Signature)

IMAGE_FILE_HEADER 不分x86/x64

IMAGE_OPTIONAL_HEADER 有x86/x64 区别.


文件头

文件头属于Nt头, 内容全在Nt头结构中

    typedef struct _IMAGE_FILE_HEADER {        WORD    Machine; ///< Windows平台类型, x86, x64, etc        WORD    NumberOfSections; ///< 扇区数量        ...        WORD    SizeOfOptionalHeader; ///< 可选头size        ...    } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

    Windows平台类型为 IMAGE_FILE_HEADER.Machine, 值为 IMAGE_FILE_MACHINE_X
    e.g. IMAGE_FILE_MACHINE_I386


可选头

可选头属于Nt头, 内容全在Nt头结构中
typedef struct _IMAGE_OPTIONAL_HEADER {    //    // Standard fields.    //    WORD    Magic; ///< <span style="color: rgb(42, 42, 42); font-family: 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 17px; ">IMAGE_ROM_OPTIONAL_HDR_X</span>    BYTE    MajorLinkerVersion;    BYTE    MinorLinkerVersion;    DWORD   SizeOfCode; ///< 所有代码节的size之和    DWORD   SizeOfInitializedData; ///< 所有被初始化的数据节size之和    DWORD   SizeOfUninitializedData; ///< 所有未被初始化数据size之和    DWORD   AddressOfEntryPoint; ///< 入口地址, OEP ?    DWORD   BaseOfCode; ///< 代码节开始地址    DWORD   BaseOfData; ///< 数据节开始地址, X64版本没有这个成员!    //    // NT additional fields.    //    DWORD   ImageBase; ///< PE映像在内存的开始地址    DWORD   SectionAlignment;    DWORD   FileAlignment;    WORD    MajorOperatingSystemVersion;    WORD    MinorOperatingSystemVersion;    WORD    MajorImageVersion;    WORD    MinorImageVersion;    WORD    MajorSubsystemVersion;    WORD    MinorSubsystemVersion;    DWORD   Win32VersionValue;    DWORD   SizeOfImage; ///< PE映像的size    DWORD   SizeOfHeaders;    DWORD   CheckSum;    WORD    Subsystem; ///< 是Dos程序, 还是Window程序. IMAGE_SUBSYSTEM_X    WORD    DllCharacteristics; ///< Dll被装入的方式    DWORD   SizeOfStackReserve; ///< 进程栈保留size    DWORD   SizeOfStackCommit;    DWORD   SizeOfHeapReserve; ///< 进程堆保留size    DWORD   SizeOfHeapCommit;    DWORD   LoaderFlags;    DWORD   NumberOfRvaAndSizes;    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; ///< 数据目录数组, 没有x86/x64区别} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

typedef struct _IMAGE_OPTIONAL_HEADER64 {    WORD        Magic;    BYTE        MajorLinkerVersion;    BYTE        MinorLinkerVersion;    DWORD       SizeOfCode;    DWORD       SizeOfInitializedData;    DWORD       SizeOfUninitializedData;    DWORD       AddressOfEntryPoint;    DWORD       BaseOfCode;    ULONGLONG   ImageBase; ///< size变大    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;    ULONGLONG   SizeOfStackReserve; ///< size变大    ULONGLONG   SizeOfStackCommit; ///< size变大    ULONGLONG   SizeOfHeapReserve; ///< size变大    ULONGLONG   SizeOfHeapCommit; ///< size变大    DWORD       LoaderFlags;    DWORD       NumberOfRvaAndSizes;    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;

IMAGE_OPTIONAL_HEADER64 没有 BaseOfData 成员
其余成员有些变成了ULONGLONG

可选头.Magic 直接能看出可选头是哪种了
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC      0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC      0x20b
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC       0x107

DataDirectory数组索引宏


#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory#define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table#define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory//      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7   // (X86 usage)#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of GP#define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS Directory#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   // Bound Import Directory in headers#define IMAGE_DIRECTORY_ENTRY_IAT            12   // Import Address Table#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16
数据目录最后一个是保留的, 所以只有15个数据目录可以使用.

保留一份自己定义的数据目录索引, 含义看得清楚些
#ifndef IMAGE_DIRECTORY_ENTRIES_EXPORT_TABLE#define IMAGE_DIRECTORY_ENTRY_EXPORT_TABLE 0#define IMAGE_DIRECTORY_ENTRY_IMPORT_TABLE 1#define IMAGE_DIRECTORY_ENTRY_RESOURCE_TABLE 2#define IMAGE_DIRECTORY_ENTRY_EXCEPTION_TABLE 3#define IMAGE_DIRECTORY_ENTRY_CERTIFICATE_TABLE 4#define IMAGE_DIRECTORY_ENTRY_BASE_RELOCATION_TABLE 5#define IMAGE_DIRECTORY_ENTRY_DBGINFO 6#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE_SPECIFIC_DATA 7#define IMAGE_DIRECTORY_ENTRY_GLOBAL_POINTER_REGISTER 8#define IMAGE_DIRECTORY_ENTRY_TLS_TABLE 9#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG_TABLE 10#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT_TABLE 11#define IMAGE_DIRECTORY_ENTRY_IMPORT_ADDRESS_TABLE 12#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT_DESCRIPTOR 13#define IMAGE_DIRECTORY_ENTRY_CLR_HEADER 14#define IMAGE_DIRECTORY_ENTRY_RESERVED 15#endif // #ifndef IMAGE_DIRECTORY_ENTRIES_EXPORT_TABLE



节区头

#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER)        \    ((ULONG_PTR)(ntheader) +                                            \     FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) +                 \     ((ntheader))->FileHeader.SizeOfOptionalHeader   \    ))

由 IMAGE_FIRST_SECTION 看出, Nt头后跟的是一组节区头

    typedef struct _IMAGE_SECTION_HEADER    {        ...        ULONG   VirtualAddress; ///< 本扇区头开始地址        ULONG   SizeOfRawData;  ///< 本扇区长度        ...    } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

    节区头数量:              PIMAGE_NT_HEADERS->FileHeader->NumberOfSections
    本节区开始地址 :     PIMAGE_SECTION_HEADER->VirtualAddress
    本节区长度 :             PIMAGE_SECTION_HEADER->SizeOfRawData

PE读取类的定义

PE分析程序编译结果为 X86/x64, 被分析的文件 x86/x64 都有.
需要根据PE映像内的x86/x64标记, 分别分析

/// @file       PeImage.h/// @brief      PE映像基类#ifndef __PE_IMAGE_H__#define __PE_IMAGE_H__class CPeImage{public:    CPeImage();    virtual ~CPeImage();    virtual BOOL Load(BYTE * pcImgMemory, LONGLONG llSize) = 0;private:    void DataInit();    void DataUnInit();protected:    IMAGE_DOS_HEADER m_DosHeader;};#endif // #ifndef __PE_IMAGE_H__

/// @file       PeImageX86.h/// @brief      PE X86映像类#ifndef __PE_IMAGE_X86_H__#define __PE_IMAGE_X86_H__#include "PeImage.h"class CX86PeImage : public CPeImage{public:    CX86PeImage();    virtual ~CX86PeImage();    virtual BOOL Load(BYTE * pcImgMemory, LONGLONG llSize);private:    void DataInit();    void DataUnInit();private:    IMAGE_NT_HEADERS32 m_NtHeader;};#endif // #ifndef __PE_IMAGE_X86_H__

/// @file       PeImageX64.h/// @brief      PE X64映像类#ifndef __PE_IMAGE_X64_H__#define __PE_IMAGE_X64_H__#include "PeImage.h"class CX64PeImage : public CPeImage{public:    CX64PeImage();    virtual ~CX64PeImage();    virtual BOOL Load(BYTE * pcImgMemory, LONGLONG llSize);private:    void DataInit();    void DataUnInit();private:    IMAGE_NT_HEADERS64 m_NtHeader;};#endif // #ifndef __PE_IMAGE_X64_H__

根据PE平台不同,进行不同的读取

BOOL CpeParse::parseImage(BYTE * pcImgMemory, LONGLONG llSize){    BOOL    bRc = FALSE;    DWORD   dwOsType = 0;    if (NULL == pcImgMemory)        return bRc;    /// 确定 PE Os版本, x86/x64 ?    bRc = fnGetPeOsTypeFromMemory((ULONG_PTR)pcImgMemory, llSize, dwOsType);    if (!bRc)            return bRc;    m_bPeX86 = IsPeOsType(dwOsType, TRUE);    m_bPeX64 = IsPeOsType(dwOsType, FALSE);    /// 按照x86/x64分别进行分析    if (m_bPeX86)        bRc = m_PeImgX86.Load(pcImgMemory, llSize);    else if (m_bPeX64)        bRc = m_PeImgX64.Load(pcImgMemory, llSize);    return bRc;}