新手学习PE文件结构
我就是学习逆向分析的菜狗,想好好学习下PE文件结构,为后面的逆向分析做基础,现在我就把自己学习PE文件结构的心得铺出来,让自己有个学习记录。
本次PE文件分析主要是64位WIN7系统下的notepad.exe文件。
拿010eidtor打开之后是这个样子:
我们开始系统学习,学习前先看一张图,是PE文件的整体结构图,这张图很经典转载于各个PE文件学习的论坛,从图中我们知道PE文件由5个主要结构体构成,还有个OTHERS结构体(此结构体并不重要所以不再讨论范围内),图如果看不清把图下载下来在看:
一、PE文件的组成
首先我们得知道一个PE文件由5个结构构成:
1.【IMAGE_DOS_HEADER】 DOS头部结构体
看一下IMAGE_DOS_HEADER结构体定义内容:
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;
这个结构体占有64个字节*(WORD占2个字节,DWORD占4个字节),重要的有2个字段需要了解,1是e_magic,占2个字节,通常MZ开头,2 是e_lfanew它指明了PE文件的起始位置。
2.【IMAGE_NT_HEADERS】 PE头部结构体
该结构体分为32位、64位2种形态,基本相同:
32位:
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
64位:
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
其中最重要的是IMAGE_FILE_HEADER FileHeader、IMAGE_OPTIONAL_HEADER这2个结构,这2个结构是单独拿出来讲的,其中Signature是个标识符就是类似MZ开头的那样,在这里是PE\0\0(50 45 00 00);
3.【IMAGE_FILE_HEADER】文件头部结构体
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; //表示可执行文件的CPU类型
WORD NumberOfSections; //表示PE文件的节区个数
DWORD TimeDateStamp; //表示文件何时被创建
DWORD PointerToSymbolTable; //很少使用
DWORD NumberOfSymbols; //很少使用
WORD SizeOfOptionalHeader; //表示IMAGE_OPTIONAL_HEADER大小
WORD Characteristics; //表示文件类型
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
Machine:
该字段是WORD类型,占用2字节。表示可执行文件的目标CPU类型。取值如下:
#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 // ARM Thumb/Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian
#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
NumberOfSections:
该字段WORD类型,占用2字节。表示PE文件的节区的个数
TimeDataStamp:
该字段表明了文件是合适被创建的,这个值是从1970年1月1日以来用格林威治时间计算的秒数。
PointerToSymbolTable:
符号表,指向COFF符号表(主要用于调试) 。
NumberOfSymbols:
符号表中的符号数。
SizeOfOptionalHeader:
该字段为WORD类型,占用2字节。该字段指定了IMAGE_OPTIONAL_HEADER结构的大小。
这里注意下 在计算IMAGE_OPTIONAL_HEADER的大小是应该从IMAGE_FILE_HEADER的这个字段来获取,而不应该直接使用sizeof(IMAGE_OPTIONAL_HEADER)计算。IMAGE_OPTIONAL_HEADER结构体的大小是可能会改变的。
Characteristics:
该字段为WORD类型,占用2字节。它指定了文件的类型,例如DLL文件,系统文件.其取值定义如下:
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved external 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 // Aggressively 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.
4.【IMAGE_OPTIONAL_HEADER】可选头结构体
5.【IMAGE_SECTION_HEADER】节表结构体