PE手动解析

写这个是为了个人动手练习,不当“视频观察师”。

DOS头

16进制编辑器打开,首先两字节是0x5A4D(Ascii的MZ),在0x3C处,是e_lfanew,两个字节,储存着PE头的偏移,此文件中是0x00E0,找过去,发现0x5045(Ascii的PE),是PE头标志Signature,四个字节

image-20220723173323548

PE头

image-20220723180155920

PE头标志

四字节。高两字节为0x00,低两字节为0x4550

PE标准头

头标志后面跟着PE标准头,二十字节

Machine

文件的运行平台,此文件中为0x014C,是Intel 386平台。

NumberOfSections

该PE文件中的节数量,也就是节表中的项数,两个字节。此处是0x0003,一共三个节。

TimeDateStamp

PE文件的创建时间,四字节。此处是0x48022587,十进制为1208100231。

image-20220723175100911

PointerToSymbolTable

COFF在文件中的偏移。四字节,此处是空。

NumberOfSymbols

符号表数量,四字节。此处为空。

SizeOfOptionalHeaders

PE可选头的长度,两个字节。此处是0x00E0

Characteristics

可执行文件的属性,两个字节,是相关属性对应的16进制按位相或的结果。此处是0x010F,即0x0100(32位)、0x00010x0002(可执行)、0x00040x0008是这个文件的属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Characteristics的可选值
#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可选头

上面标准头SizeOfOptionalHeader指明长度是0x00E0,即224字节,这是32位可执行文件,一般是244字节。

image-20220723181230914

Magic

魔术字,表示可选头的类型,两字节。此处是0x010B

MajorLinkerVersion

链接器版本号,一字节。此处是0x07

MinorLinkerVersion

链接器版本号,一字节,此处是0x0A

SizeOfCode

代码段总长度,四字节。此处是0x00007800

SizeOfInitializedCode

初始化的数据长度,比如全局变量,四字节。此处是0x00008800

SizeOfUnInitializedCode

未初始化数据的长度,四字节。此处是0.

AddressOfEntryPoint

OEP入口点偏移,四字节。此处是0x0000739D

BaseOfCode

代码段起始地址偏移,四字节。此处是0x00001000

BaseOfData

数据段起始地址偏移,四字节。此处是0x00009000

ImageBase

基址,四字节。此处是0x01000000

SectionAlignment

节被夹在到内存中按照这个值对齐,四字节。此处是0x00001000.

FileAlignment

节在文件中按此值对齐,四字节。此处是0x00000200

MajorOperatingSystemVersion

操作系统版本号,两字节。此处是0x0005.

MinorOperatingSystemVersion

所需最小操作系统版本号,两字节,此处是0x0001.

MajorImageVersion

映像的版本号,两字节。此处是0x0005.

MinorImageVersion

最小映像的版本号,两字节,此处是0x0001.

MajorSubsystemVersion

所需子系统版本号,两字节。此处是0x0004.

MinorSubsystemVersion

最小所需子系统版本号,两字节。此处是0x0000.

Win32VersionValue

保留,必须为0,四字节

SizeOfImage

映像的大小,PE加载到内存是连续的,这个值指定占用虚拟空间的大小,四字节。此处是0x00013000.

SizeOfHeaders

所有头加节表的大小,以FileAlignment对齐,四字节。此处是0x00000400.

CheckSum

文件校验和,四字节。此处是0x00018ADA.

Subsystem

运行该PE文件所需的子系统,两字节。此处是0x0002.

DllCharacteristics

DLL的文件属性,只对DLL文件有效,两字节。此处是0x0800.

SizeOfStackReserve

四字节。此处是0x00040000.

SizeOfStackCommit

四字节。此处是0x00011000.

SizeOfHeapReserve

四字节。此处是0x00100000.

SizeOfHeapCommit

四字节。此处是0x00001000.

LoaderFlags

保留,必须为0,四字节

NumberOfRvaAndSizes

数据目录的项数,即下面这个数组的项数,四字节。此处是0x00000010.

IMAGE_DATA_DIRECTORY

数据目录,这是一个数组,如图都是它的。

image-20220723185619661

节表

在PE可选头中的SizeOfHeaders指明了头加节表的长度,此处是0x400,即1024字节。
而PE标准头的SizeOfOptionalHeaders指明了可选头的长度,此处是0x00E0,即244字节。
PE标准头长度24字节。DOS头长度224字节。

所以节表长度为 1024-244-244-24=552 字节。如图所示都是节表的部分。

image-20220723190651164

Name数组

八个字节,该节的名称。此处为0x00000074 7865742E(.text).

Misc

该节在没有对齐前的真实大小,该值可能不准确,联合体,四个字节。此处为0x00007748.

VirtualAddress

节区在内存中的偏移地址,加上ImageBase才是在内存中的真正地址,四个字节。此处是0x00001000.

SizeOfRawData

节在内存中对齐后的大小,四个字节。此处是0x00007800.

PointerToRawData

节在内存中的偏移,四个字节。此处是0x00000400.

PointerToRelocations

在obj文件中使用,对exe无意义,四个字节

PointerToLinenumbers

行号表的位置,调试时使用,四个字节

NumberOfRelocations

在obj文件中使用,对exe无意义,两个字节

NumberOfLinenumbers

行号表中行号的数量,调试的时候使用,两个字节

Characteristics

表示该节的属性,四个字节。此处是0x60000020.

后面紧跟着是.data节,就不分析了。