0x00 前言
了解一个程序的结构在逆向过程中是非常重要的,虽然也有很多工具可以直接读取到PE文件的结构,但是作为一个有信仰的逆向学习者,个人认为有必要从根本上去理解,所以今天就结合一个简单的32位.exe程序配合WinHex浅浅分析一下PE文件结构,将会将文章分为多篇对PE文件结构进行分析,第一篇主要对PE文件的整体结构和DOS头进行剖析。
0x01 PE文件结构概述
PE文件可以大概分为:DOS头、NT头、节表、.idata段、.text段、.data段,本文将一一对其进行分析。
结构示意图如下:

0x02 DOS头
DOS头的字段有
IMAGE_DOS_HEADER
typedef struct _IMAE_DOS_HEADER {
WORD e_magic; //2
WORD e_cblp; //2
WORD e_cp; //2
WORD e_crlc; //2
WORD e_cparhdr; //2
WORD e_minalloc; //2
WORD e_maxalloc; //2
WORD e_ss; //2
WORD e_sp; //2
WORD e_csum; //2
WORD e_ip; //2
WORD e_cs; //2
WORD e_lfarlc; //2
WORD e_ovno; //2
WORD e_res[4]; //2
WORD e_oemid; //2
WORD e_oeminfo; //2
WORD e_res2[10]; //2
LONG e_lfanew; //4
} IMAGE_DOS-HEADER, *PIMAGE_DOS_HEADER;
共占据64个字节,结合WinHex查看如下图所示:

图中标记的位置即整个DOS头的内容,我们依次按字段进行分析:
- e_magic:0x00,占两个字节,即4D 5A,是DOS的签名,PE文件的e_magic一般都是MZ(MZ标签是MS-DOS原架构师Mark Zbikowski姓名的首字母缩写)。
- e_cblp:0x02,占两个字节,即90 00,是文件最后页的字节数,由于win32是小端序,所以这个程序的文件最后页的字节数为0x0090字节。
- e_cp:0x04,占两个字节,即03 00,是文件的页数,该程序共有0x0003页。
- e_crlc:0x06,占两个字节,即00 00,是重定义元素个数,即引用第三方链接库、虚拟变量等,该文件重定义元素个数为0。
- e_cparhdr:0x08,占两个字节,即04 00,参数头大小。
- e_minalloc:0x0A,占两个字节,即00 00,最小所需附加段大小。
- e_maxalloc:0x0C,占两个字节,即00 00,最小所需附加段大小。
- e_ss:0x0E,初始代码段地址。
- e_sp:0x10,初始栈内存地址。
- e_csum:0x12,校验和,是对整个PE文件的校验和,如未开启校验和,则该字段为0。
- e_ip:0x14,初始化EIP指针的地址。
- e_cs:0x16,初始化CS段的地址。
- e_lfarlc:0x18,重定向表的文件地址。
- e_ovno:0x1A,覆盖号。
- e_res[4]:0x1C,保留字段。
- e_oemid:0x24,OEM标识符,厂商序列号。
- e_oeminfo:0x26,OEM信息。
- e_res2[10]:0x28,保留字段。
- e_lfanew:0x3C,PE头的偏移地址,该文件的PE头位置在0x0000C0。
其中最重要的DOS头为e_magic和e_lfanew,e_magic是用于确定文件是否为PE文件,e_lfanew的用于确定PE头的位置。
0x03 DOS存根
从地址0x40至0xBF为DOS的存根,该段不会影响PE文件的正常运行。

0x04 NT头
NT头可分为三部分,依次为PE签名,PE文件头以及PE可选头。

NT头的字段如下:
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
-
Signature字段为双字型数据,占4个字节,是PE文件的签名。
-
FileHeader字段是PE文件头,以下是FileHeader的字段,后面再展开说明。
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;
- OptionalHeader字段是PE的可选头,以下是OptionalHeader的字段,后面再展开说明。
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;
0x05 节表
节表(SECTION)即区块表,定义了PE文件中所有节的属性,SECTION字段如下,再下篇再展开叙述:
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;
0x06 结语
也是刚开始学逆向没多久,文章的目的一个是归纳总结学习内容,一个是希望把学到的内容分享出来与志同道合之士一起学习进步,文章中如有错误的地方,请各位师傅批评指正,非常感谢!下篇我会继续对FileHeader、OptionalHeader、.idata段、.text段以及,data段进行逐一分析。
1371

被折叠的 条评论
为什么被折叠?



