重读PE文件格式

感觉很有必要重新研究PE格式,所以重读了PE格式的相关文档,心得如下:

1.对于DOS头,其定义如下:

代码
typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    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;

 

因为我们开发的是windows下的程序,所以重要的字段有两个,一个是e_magic字段,一个是e_lfanew,e_magic字段始终为5A4D,即ASCII字符的MZ,e_lfanew保存的是PE文件头在文件中的偏移量,我想作为exe程序的装载器,首先检查DOS头的e_magic字段是否为MZ,然后读取e_lfanew字段的值,以此找到PE文件头

2.找到PE文件头,PE文件头的定义如下:

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

 

signature字段同DOS头的e_magic一样,是个标志字段,其值始终为4550,IMAGE_FILE_HEADER结构定义如下:

代码
typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
//运行平台
    WORD    NumberOfSections;//文件的节数目
    DWORD   TimeDateStamp;//文件创建日期和时间
    DWORD   PointerToSymbolTable;//指向符号表(用于调试)
    DWORD   NumberOfSymbols;//符号表中的符号数量(用于调试)
    WORD    SizeOfOptionalHeader;//IMAGE_OPTIONAL_HEADER32结构的长度
    WORD    Characteristics;//文件属性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

 

machine字段表示当前文件应该运行的平台,对于PC来说,此值应该为14C

NumberOfSections这个字段表示文件的节的数目,这个值很重要,我试着把一个文件的这个字段加1,然后发现文件不能正常装载了,因此系统应该是据此字段来装载PE文件的节的

Characteristics指明了当前PE文件是什么类型的,如果是exe,则值为10F,如果是DLL,则为210E

IMAGE_OPTIONAL_HEADER32是非常重要的一个结构,他里面有很多重要的信息,定义如下:

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

    WORD    Magic;
//10Bh=exe Image
    BYTE    MajorLinkerVersion;//链接器版本号
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
//所有含代码的节的总大小
    DWORD   SizeOfInitializedData;//所有含已初始化数据的节的总大小
    DWORD   SizeOfUninitializedData;//所有含未初始化数据的节的大小
    DWORD   AddressOfEntryPoint;//程序执行入口RVA
    DWORD   BaseOfCode;//代码的节的起始RVA
    DWORD   BaseOfData;//数据的节的起始RVA

    
//
    
// NT additional fields.
    
//

    DWORD   ImageBase;
//程序的建议装载地址
    DWORD   SectionAlignment;//内存中的节的对齐粒度
    DWORD   FileAlignment;//文件中的节的对齐粒度
    WORD    MajorOperatingSystemVersion;//操作系统主版本号
    WORD    MinorOperatingSystemVersion;//操作系统副版本号
    WORD    MajorImageVersion;//可运行于操作系统的最小版本号
    WORD    MinorImageVersion;//
    WORD    MajorSubsystemVersion;//可运行于操作系统的最小子版本号
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
//内存中整个PE映像尺寸
    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;

 

以上是简单的注释,详细解释放在下一篇文章,下午来写

posted @ 2010-03-31 11:20  认真做人,认真做事  阅读(590)  评论(0编辑  收藏  举报