PE結構

  PE文件的全稱是Portable Executable,意爲可移植的可執行的文件,常見的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微軟Windows操作系統上的程序文件(可能是間接被執行,如DLL)
  下圖是PE文件的基本結構
  
  這裏寫圖片描述


MZ文件頭

  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;

我們只需要關注兩個域:
e_magic :一個WORD類型,值是一個常數0x4D5A,用文本編輯器查看該值位‘MZ’,可執行文件必須都是’MZ’開頭。
e_lfanew:爲32位可執行文件擴展的域,用來表示DOS頭之後的NT頭相對文件起始地址的偏移。
下面是一個PE文件的DOS頭
這裏寫圖片描述


DOS插樁小程序

這裏寫圖片描述

這個程序實際上是在DOS環境下顯示 This program can not be run in DOS mode 或 This program must be run under Win32 之類信息的小程序


NT映像頭

緊跟着DOS小程序後面的是PE文件的NT映像頭(IMAGE_NT_HEADERS),它存放PE整個文件信息分佈的重要字段,結構定義如下

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;                         //簽名
    IMAGE_FILE_HEADER FileHeader;            //映像文件頭
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;  //可選映像頭
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

可見它由三部分組成:
(1) : Signature:類似於DOS頭中的e_magic,其高16位是0,低16是0x4550,用字符表示是’PE‘。
(2) : IMAGE_FILE_HEADER是PE文件頭,c語言的定義是這樣的:

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

每個域的具體含義如下:

這裏寫圖片描述

附1:

#define IMAGE_FILE_MACHINE_UNKNOWN         0
#define IMAGE_FILE_MACHINE_I386            0x014c  
              // Intel 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_SH3             0x01a2  
              // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP            0x01a3
#define IMAGE_FILE_MACHINE_SH3E              0x01a4  
              // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4               0x01a6  
              // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5               0x01a8  
              // SH5
#define IMAGE_FILE_MACHINE_ARM               0x01c0  
              // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB             0x01c2
#define IMAGE_FILE_MACHINE_AM33              0x01d3
#define IMAGE_FILE_MACHINE_POWERPC           0x01F0  
              // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP         0x01f1
#define IMAGE_FILE_MACHINE_IA64              0x0200  
              // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16            0x0266  
              // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64           0x0284  
              // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU           0x0366  
              // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466  
              // MIPS
#define IMAGE_FILE_MACHINE_AXP64          IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE           0x0520  
              // Infineon
#define IMAGE_FILE_MACHINE_CEF               0x0CEF
#define IMAGE_FILE_MACHINE_EBC               0x0EBC  
              // EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64             0x8664  
              // AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R              0x9041  
              // M32R little-endian
#define IMAGE_FILE_MACHINE_CEE               0xC0EE

附2:

#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 nunbers 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_REVERSED_LO         0x0080  
// Bytes 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  
// Bytes of machine word are reversed.

可以看出,PE文件頭定義了PE文件的一些基本信息和屬性,這些屬性會在PE加載器加載時用到,如果加載器發現PE文件頭中定義的一些屬性不滿足當前的運行環境,將會終止加載該PE。
(3)可選映像頭:
另一個重要的頭就是PE可選頭,別看他名字叫可選頭,其實一點都不能少,不過,它在不同的平臺下是不一樣的,例如32位下是IMAGE_OPTIONAL_HEADER32,而在64位下是IMAGE_OPTIONAL_HEADER64。爲了簡單起見,我們只看32位。

typedef struct _IMAGE_OPTIONAL_HEADER {
    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    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;

定義如下:
這裏寫圖片描述
這裏寫圖片描述

附3:

#define IMAGE_NT_OPTIONAL_HDR32_MAGIC      0x10b  // 32位PE可選頭
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC      0x20b  // 64位PE可選頭
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC       0x107  

附4:

#define IMAGE_SUBSYSTEM_UNKNOWN              0   
// Unknown subsystem.
#define IMAGE_SUBSYSTEM_NATIVE               1   
// Image doesn't require a subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_GUI          2   
// Image runs in the Windows GUI subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_CUI          3   
// Image runs in the Windows character subsystem.
#define IMAGE_SUBSYSTEM_OS2_CUI              5   
// image runs in the OS/2 character subsystem.
#define IMAGE_SUBSYSTEM_POSIX_CUI            7   
// image runs in the Posix character subsystem.
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS       8   
// image is a native Win9x driver.
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI       9   
// Image runs in the Windows CE subsystem.
#define IMAGE_SUBSYSTEM_EFI_APPLICATION      10 
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER  11
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER   12
#define IMAGE_SUBSYSTEM_EFI_ROM              13
#define IMAGE_SUBSYSTEM_XBOX                 14
#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16

附5

#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040     
// DLL can move.
#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY    0x0080    
// Code Integrity Image
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT    0x0100     
// Image is NX compatible
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200     
// Image understands isolation and doesn't want it
#define IMAGE_DLLCHARACTERISTICS_NO_SEH       0x0400     
// Image does not use SEH.  No SE handler may reside in this image
#define IMAGE_DLLCHARACTERISTICS_NO_BIND      0x0800     
// Do not bind this image.
//                                            0x1000     
// Reserved.
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER   0x2000     
// Driver uses WDM model
//                                            0x4000     
// Reserved.
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE     0x8000

附6:

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

VirtualAddress:是一個RVA。
Size:是一個大小。
這兩個數有什麼用呢?一個是地址,一個是大小,可以看出這個數據目錄項定義的是一個區域。那他定義的是什麼東西的區域呢?前面說了,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

下圖是一個PE文件的數據目錄
這裏寫圖片描述


節表

緊接着NT映像頭的是節表,節表是一個數組,每個結構包含一個節的具體信息(28H字節),節的個數由映像頭文件IMAGE_FILE_HEADER中的NumberOfSections的值決定,節表的定義如下:

typedef struct _IMAGE_SECTION_HEADER {
  BYTE  Name[IMAGE_SIZEOF_SHORT_NAME];
  union {
    DWORD PhysicalAddress;
    DWORD VirtualSize;
  } Misc;
  DWORD VirtualAddress;
  DWORD SizeOfRawData;
  DWORD PointerToRawData;
  DWORD PointerToRelocations;
  DWORD PointerToLinenumbers;
  WORD  NumberOfRelocations;
  WORD  NumberOfLinenumbers;
  DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

這裏寫圖片描述

其中節屬性如下表:
這裏寫圖片描述

在節表的後面就是節的具體數據所在了..常用的節分析,將在後面的文章中給出

發佈了42 篇原創文章 · 獲贊 37 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章