note : PE file format study
发布日期:2021-06-30 22:01:46 浏览次数:2 分类:技术文章

本文共 8971 字,大约阅读时间需要 29 分钟。

参考资料

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; ///< IMAGE_ROM_OPTIONAL_HDR_X    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;}

转载地址:https://lostspeed.blog.csdn.net/article/details/10299891 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:居然发现了不同数据CRC16结果一样
下一篇:MDK的编辑器设置

发表评论

最新留言

不错!
[***.144.177.141]2024年04月07日 01时48分42秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章