实例解析PE结构

1 (PE结构图)

  PE文件中,代码,已初始化的数据,资源和重定位信息等数据都被按照属性分类放到不同的section(节区)中。而每个节区的属性和位置用一个IMAGE_SECTION_HEADER结构来描述,所有的IMAGE_SECTION_HEADER结构组成一个节表(section table),节表数据在PE文件中被存放在所有节数据之前。

  由于数据是按照属性在节中放置的,不同用途但是属性想同的数据(如导入表,导出表以及.const段指定的只读数据)可能被放在同一个节中,所以PE文件中还用一系列的数据目录结构IMAGE_DATA_DIRECTORY来分别指明这些数据的位置,数据目录表和其他描述文件属性的数据合在一起称为PE文件头,PE文件头被放置在节和节表的前面,如图1。

  PE头部分包含了DOS头和NT头,PE文件中的DOS部分由MZ格式的文件头和可执行代码部分组成,可执行代码被称为"DOS块"(DOS stub).MZ格式的文件头由IMAGE_DOS_HEADER结构定义。

IMAGE_DOS_HEADER STRUCT
{
WORD    e_magic //Magic DOS signature MZ(4Dh 5Ah)     DOS可执行文件标记
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  //Minimun extra paragraphs needs
WORD    e_maxalloc  //Maximun extra paragraphs needs
WORD    e_ss  //intial(relative)SS value    DOS代码的初始化堆栈SS
WORD    e_sp  //intial SP value               DOS代码的初始化堆栈指针SP
WORD    e_csum  //Checksum
WORD    e_ip  //    intial IP value                   DOS代码的初始化指令入口[指针IP]
WORD    e_cs  //intial(relative)CS value                    DOS代码的初始堆栈入口
hWORD    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
DWORD   e_lfanew     //Offset to start of PE header             指向PE文件头
} IMAGE_DOS_HEADER ENDS

  DOS头文件第一个字段e_magic被定义成字符“MZ”作为标识,e_lfanew字段指向了真正的PE头(NT头),这个位置总是以8字节为单位对齐的。

  从DOS文件头的e_lfanew字段(文件头偏移003ch)得到真正的PE头位置,PE头由IMAGE_NT_HEADER结构定义。

typedef struct _IMAGE_NT_HEADERS {
  DWORD                 Signature;   //PE文件标识
  IMAGE_FILE_HEADER     FileHeader;
  IMAGE_OPTIONAL_HEADER OptionalHeader;
} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;

 那么如何解析DOS头和NT头地址呢?

1. 打开文件

2. 创建一个文件映射对象

3. 文件内存视图映射

4. 获取DOS文件头和NT文件头地址

HANDLE fHandle = CreateFile(
                            "1.exe",
                            GENERIC_READ,
                            FILE_SHARE_READ,
                            NULL,
                            OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL);

    if ( INVALID_HANDLE_VALUE == fHandle) 
    {
        std::cout << "打开文件失败: " << GetLastError() << std::endl;
        exit(-1);
    }
    // 创建一个文件映射对象
    HANDLE mapHandle = CreateFileMapping(
                                    fHandle,
                                    NULL,
                                    PAGE_READONLY,
                                    0,
                                    0,
                                    NULL);
    if( NULL == mapHandle )
    {
        std::cout << "打开文件映射对象失败: " << GetLastError() << std::endl;
        CloseHandle(mapHandle);
    }
    // 文件内存视图映射
    LPVOID strContet = MapViewOfFile(
                                mapHandle,
                                FILE_MAP_READ,
                                0,
                                0,
                                0);

    LPBYTE lpBaseAddress = (LPBYTE)strContet;
    PIMAGE_DOS_HEADER dosHead = (PIMAGE_DOS_HEADER)lpBaseAddress;
    PIMAGE_NT_HEADERS ntHead = (PIMAGE_NT_HEADERS)(lpBaseAddress + dosHead->e_lfanew);

  

 

原文地址:https://www.cnblogs.com/persuit/p/6062430.html