普通PE文件的基本格式
我以notepad.exe为例子说明pe文件的基本格式,因为notepad.exe具有普通PE文件的基本格式。
以下是整个PE文件的全貌:
//@2015/10/22这样比较容易看明白!大家看上面的图就好,下面的我也不删了。
文件偏移 | 文件 |
---|---|
00000000 | DOS头 |
00000040 | DOS存根 |
000000e0 | NT头 |
000001d8 | 节区头(“.text”) |
00000200 | 节区头(“.data”) |
00000228 | 节区头(“.rsrc”) |
NULL | |
00000400 | 节区(“.text”) |
NULL | |
00007c00 | 节区(“.data”) |
NULL | |
00008400 | 节区(“.rsrc”) |
NULL | |
00010800 |
一、PE头
1.1、DOS头
地址 | HEX数据 | 数据 | 注释 |
---|---|---|---|
01000000 | 4D 5A | ASCII “MZ” | ; DOS EXE Signature |
01000002 | 9000 | DW 0090 | ; DOS_PartPag = 90 (144.) |
01000004 | 0300 | DW 0003 | ; DOS_PageCnt = 0x3 |
01000006 | 0000 | DW 0000 | ; DOS_ReloCnt = 0x0 |
01000008 | 0400 | DW 0004 | ; DOS_HdrSize = 0x4 |
0100000A | 0000 | DW 0000 | ; DOS_MinMem = 0x0 |
0100000C | FFFF | DW FFFF | ; DOS_MaxMem = FFFF (65535.) |
0100000E | 0000 | DW 0000 | ; DOS_ReloSS = 0x0 |
01000010 | B800 | DW 00B8 | ; DOS_ExeSP = 0xB8 |
01000012 | 0000 | DW 0000 | ; DOS_ChkSum = 0x0 |
01000014 | 0000 | DW 0000 | ; DOS_ExeIP = 0x0 |
01000016 | 0000 | DW 0000 | ; DOS_ReloCS = 0x0 |
01000018 | 4000 | DW 0040 | ; DOS_TablOff = 0x40 |
0100001A | 0000 | DW 0000 | ; DOS_Overlay = 0x0 |
1.2 DOS 存根
DOS存根是个可选项,且大小不固定,通常包含“this program connot be run in dos mode”这个句子。
1.3、NT头 (IMAGE_NT_HEADERS)
地址 | HEX数据 | 数据 | 注释 |
---|---|---|---|
010000E0 | 50 45 00 00 | ASCII “PE” ; | PE signature (PE) |
010000E4 | 4C01 | DW 014C ; | Machine = IMAGE_FILE_MACHINE_I386 每个cpu拥有唯一的machine码 |
010000E6 | 0300 | DW 0003 ; | NumberOfSections = 0x3 文件中存在的节区的数量 |
010000E8 | 87520248 | DD 48025287 ; | TimeDateStamp = 0x48025287 |
010000EC | 00000000 | DD 00000000 ; | PointerToSymbolTable = 0x0 |
010000F0 | 00000000 | DD 00000000 ; | NumberOfSymbols = 0x0 |
010000F4 | E000 | DW 00E0 ; | SizeOfOptionalHeader = E0 (224.) |
010000F6 | 0F01 | DW 010F ; | Characteristics = EXECUTABLE_IMAGE |
characteristics 这个字段用于标识文件的属性,文件是否是可运行的形态,是否为DLL文件等信息,其中IMAG_FILE_EXECUTABLE_IMAGE = 0x0002表示文件是可执行的,IMAGE_FILE_DLL = 0x2000 表示这个文件是DLL文件
1.4、NT头 (可选头)
IMAGE_OPTIONAL_HEADER32
结构体说明:
以下是我在OllyDbg中获取到的数据,对比学习
地址 | HEX数据 | 数据 | 注释 |
---|---|---|---|
010000F8 | 0B01 | DW 010B ; | MagicNumber = PE32 |
010000FA | 07 | DB 07 ; | MajorLinkerVersion = 0x7 |
010000FB | 0A | DB 0A ; | MinorLinkerVersion = A (10.) |
010000FC | 00780000 | DD 00007800 ; | SizeOfCode = 7800 (30720.) |
01000100 | 00880000 | DD 00008800 ; | SizeOfInitializedData = 8800 (34816.) |
01000104 | 00000000 | DD 00000000 ; | SizeOfUninitializedData = 0x0 |
01000108 | 9D730000 | DD 0000739D ; | AddressOfEntryPoint = 0x739D |
0100010C | 00100000 | DD 00001000 ; | BaseOfCode = 0x1000 |
01000110 | 00900000 | DD 00009000 ; | BaseOfData = 0x9000 |
01000114 | 00000001 | DD 01000000 ; | ImageBase = 0x1000000 |
01000118 | 00100000 | DD 00001000 ; | SectionAlignment = 0x1000 |
0100011C | 00020000 | DD 00000200 ; | FileAlignment = 0x200 |
01000120 | 0500 | DW 0005 ; | MajorOSVersion = 0x5 |
01000122 | 0100 | DW 0001 ; | MinorOSVersion = 0x1 |
01000124 | 0500 | DW 0005 ; | MajorImageVersion = 0x5 |
01000126 | 0100 | DW 0001 ; | MinorImageVersion = 0x1 |
01000128 | 0400 | DW 0004 ; | MajorSubsystemVersion = 0x4 |
0100012A | 0000 | DW 0000 ; | MinorSubsystemVersion = 0x0 |
0100012C | 00000000 | DD 00000000 ; | Reserved |
01000130 | 00300100 | DD 00013000 ; | SizeOfImage = 13000 (77824.) |
01000134 | 00040000 | DD 00000400 ; | SizeOfHeaders = 400 (1024.) |
01000138 | DA8A0100 | DD 00018ADA ; | CheckSum = 0x18ADA |
0100013C | 0200 | DW 0002 ; | Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI |
0100013E | 0080 | DW 8000 ; | DLLCharacteristics = 0x8000 |
01000140 | 00000400 | DD 00040000 ; | SizeOfStackReserve = 40000 (262144.) |
01000144 | 00100100 | DD 00011000 ; | SizeOfStackCommit = 11000 (69632.) |
01000148 | 00001000 | DD 00100000 ; | SizeOfHeapReserve = 100000 (1048576.) |
0100014C | 00100000 | DD 00001000 ; | SizeOfHeapCommit = 1000 (4096.) |
01000150 | 00000000 | DD 00000000 ; | LoaderFlags = 0x0 |
01000154 | 10000000 | DD 00000010 ; | NumberOfRvaAndSizes = 10 (16.) |
01000158 | 00000000 | DD 00000000 ; | Export Table address = 0x0 |
0100015C | 00000000 | DD 00000000 ; | Export Table size = 0x0 |
01000160 | 04760000 | DD 00007604 ; | Import Table address = 0x7604 |
01000164 | C8000000 | DD 000000C8 ; | Import Table size = C8 (200.) |
01000168 | 00B00000 | DD 0000B000 ; | Resource Table address = 0xB000 |
0100016C | 207F0000 | DD 00007F20 ; | Resource Table size = 7F20 (32544.) |
01000170 | 00000000 | DD 00000000 ; | Exception Table address = 0x0 |
01000174 | 00000000 | DD 00000000 ; | Exception Table size = 0x0 |
01000178 | 00000000 | DD 00000000 ; | Certificate File pointer = 0x0 |
0100017C | 00000000 | DD 00000000 ; | Certificate Table size = 0x0 |
01000180 | 00000000 | DD 00000000 ; | Relocation Table address = 0x0 |
01000184 | 00000000 | DD 00000000 ; | Relocation Table size = 0x0 |
01000188 | 50130000 | DD 00001350 ; | Debug Data address = 0x1350 |
0100018C | 1C000000 | DD 0000001C ; | Debug Data size = 1C (28.) |
01000190 | 00000000 | DD 00000000 ; | Architecture Data address = 0x0 |
01000194 | 00000000 | DD 00000000 ; | Architecture Data size = 0x0 |
01000198 | 00000000 | DD 00000000 ; | Global Ptr address = 0x0 |
0100019C | 00000000 | DD 00000000 ; | Must be 0 |
010001A0 | 00000000 | DD 00000000 ; | TLS Table address = 0x0 |
010001A4 | 00000000 | DD 00000000 ; | TLS Table size = 0x0 |
010001A8 | A8180000 | DD 000018A8 ; | Load Config Table address = 0x18A8 |
010001AC | 40000000 | DD 00000040 ; | Load Config Table size = 40 (64.) |
010001B0 | 50020000 | DD 00000250 ; | Bound Import Table address = 0x250 |
010001B4 | D0000000 | DD 000000D0 ; | Bound Import Table size = D0 (208.) |
010001B8 | 00100000 | DD 00001000 ; | Import Address Table address = 0x1000 |
010001BC | 48030000 | DD 00000348 ; | Import Address Table size = 348 (840.) |
010001C0 | 00000000 | DD 00000000 ; | Delay Import Descriptor address = 0x0 |
010001C4 | 00000000 | DD 00000000 ; | Delay Import Descriptor size = 0x0 |
010001C8 | 00000000 | DD 00000000 ; | COM+ Runtime Header address = 0x0 |
010001CC | 00000000 | DD 00000000 ; | Import Address Table size = 0x0 |
010001D0 | 00000000 | DD 00000000 ; | Reserved |
010001D4 | 00000000 | DD 00000000 ; | Reserved |
1.4、节区头 是由IMAGE_SECTION_HEADER 结构体组成的数组
1.4.1 code字段
地址 | HEX数据 | 数据 | 注释 |
---|---|---|---|
010001D8 | 2E 74 65 78 | ASCII “.text” ; | SECTION |
010001E0 | 48770000 | DD 00007748 ; | VirtualSize(内存中中节区所占大小) =7748 (30536.) |
010001E4 | 00100000 | DD 00001000 ; | VirtualAddress(内存中节区起始地址=RVA) = 0x1000 |
010001E8 | 00780000 | DD 00007800 ; | SizeOfRawData(磁盘文件中节区所占大小) = 7800 (30720.) |
010001EC | 00040000 | DD 00000400 ; | PointerToRawData(磁盘文件中节区其实地址) = 0x400 |
010001F0 | 00000000 | DD 00000000 ; | PointerToRelocations = 0x0 |
010001F4 | 00000000 | DD 00000000 ; | PointerToLineNumbers = 0x0 |
010001F8 | 0000 | DW 0000 ; | NumberOfRelocations = 0x0 |
010001FA | 0000 | DW 0000 ; | NumberOfLineNumbers = 0x0 |
010001FC | 20000060 | DD 60000020 ; | Characteristics节区属性 = CODE &EXECUTE &READ |
//这个Characteristics由下面的值组合而成
#define IMAGE_SCN_CNT_CODE 0x00000020 //section contains code
#define ... 0x00000040 //section contains initialized data
#define ... 0x00000080 //section contains uninitialized data
#define ... 0x20000000 //section is executable
#define ... 0x40000000 //section is readable
#define ... 0x80000000 //section is writable
1.4.2 data字段
地址 | HEX数据 | 数据 | 注释 |
---|---|---|---|
01000200 | 2E 64 61 74 | ASCII “.data” ; | SECTION |
01000208 | A81B0000 | DD 00001BA8 ; | VirtualSize = 1BA8 (7080.) |
0100020C | 00900000 | DD 00009000 ; | VirtualAddress = 0x9000 |
01000210 | 00080000 | DD 00000800 ; | SizeOfRawData = 800 (2048.) |
01000214 | 007C0000 | DD 00007C00 ; | PointerToRawData = 0x7C00 |
01000218 | 00000000 | DD 00000000 ; | PointerToRelocations = 0x0 |
0100021C | 00000000 | DD 00000000 ; | PointerToLineNumbers = 0x0 |
01000220 | 0000 | DW 0000 ; | NumberOfRelocations = 0x0 |
01000222 | 0000 | DW 0000 ; | NumberOfLineNumbers = 0x0 |
01000224 | 400000C0 | DD C0000040 ; | Characteristics = INITIALIZED_DATA |
1.4.3 source字段
地址 | HEX数据 | 数据 | 注释 |
---|---|---|---|
01000228 | 2E 72 73 72 | ASCII “.rsrc” ; | SECTION |
01000230 | 207F0000 | DD 00007F20 ; | VirtualSize = 7F20 (32544.) |
01000234 | 00B00000 | DD 0000B000 ; | VirtualAddress = 0xB000 |
01000238 | 00800000 | DD 00008000 ; | SizeOfRawData = 8000 (32768.) |
0100023C | 00840000 | DD 00008400 ; | PointerToRawData = 0x8400 |
01000240 | 00000000 | DD 00000000 ; | PointerToRelocations = 0x0 |
01000244 | 00000000 | DD 00000000 ; | PointerToLineNumbers = 0x0 |
01000248 | 0000 | DW 0000 ; | NumberOfRelocations = 0x0 |
0100024A | 0000 | DW 0000 ; | NumberOfLineNumbers = 0x0 |
0100024C | 40000040 | DD 40000040 ; | Characteristics = INITIALIZED_DATA |
01000250 | A2 | DB A2 | 、、 |
RVA to RAW
RVA 是虚拟内存地址
RAW是文件偏移
RAW -PointerToRawData = RVA - VirtualAddress
RAW = RVA - VirtualAddress + PointerToRawData
RVA + ImageBase = VirtuelAddress
VA 是进程虚拟内存的绝对地址,