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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章