5.1 Windows的二進制文件格式PE/COFF
PE文件格式事實上與ELF同根同源,它們都是由COFF格式發展而來。
5.2 PE前身——COFF
在win下,Command Prompt for vs 2017,cd命令進入源代碼所在目錄:
運行命令:
“cl”是VISUAL C++的編譯器。/c參數表示只編譯,不鏈接,只會生成obj文件,不會生成exe文件。如下:
如果不加這個參數,那么cl會在編譯源代碼后,再調用link鏈接器將生產的obj文件與默認的C運行庫鏈接,生成exe文件。
“/Za”參數禁用這些C和C++的專有擴展。
可以使用下面命令查看obj的結構:
/ALL參數將打印輸出目標文件的所有相關信息,包括文件頭,每個段的屬性和段的原始數據及符號表。
下面是打印出來的所有相關信息:

Microsoft (R) COFF/PE Dumper Version 14.10.25019.0 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file SimpleSection.obj File Type: COFF OBJECT FILE HEADER VALUES 14C machine (x86) 5 number of sections 5960849C time date stamp Sat Jul 8 15:07:08 2017 1F4 file pointer to symbol table 14 number of symbols 0 size of optional header 0 characteristics SECTION HEADER #1 .drectve name 0 physical address 0 virtual address 18 size of raw data DC file pointer to raw data (000000DC to 000000F3) 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers 100A00 flags Info Remove 1 byte align RAW DATA #1 00000000: 20 20 20 2F 44 45 46 41 55 4C 54 4C 49 42 3A 22 /DEFAULTLIB:" 00000010: 4C 49 42 43 4D 54 22 20 LIBCMT" Linker Directives ----------------- /DEFAULTLIB:LIBCMT SECTION HEADER #2 .debug$S name 0 physical address 0 virtual address 74 size of raw data F4 file pointer to raw data (000000F4 to 00000167) 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers 42100040 flags Initialized Data Discardable 1 byte align Read Only RAW DATA #2 00000000: 04 00 00 00 F1 00 00 00 67 00 00 00 29 00 01 11 ....?...g...)... 00000010: 00 00 00 00 44 3A 5C 53 69 6D 70 6C 65 53 65 63 ....D:\SimpleSec 00000020: 74 69 6F 6E 5C 53 69 6D 70 6C 65 53 65 63 74 69 tion\SimpleSecti 00000030: 6F 6E 2E 6F 62 6A 00 3A 00 3C 11 00 22 00 00 07 on.obj.:.<.."... 00000040: 00 13 00 0A 00 BB 61 00 00 13 00 0A 00 BB 61 00 .....?a......?a. 00000050: 00 4D 69 63 72 6F 73 6F 66 74 20 28 52 29 20 4F .Microsoft (R) O 00000060: 70 74 69 6D 69 7A 69 6E 67 20 43 6F 6D 70 69 6C ptimizing Compil 00000070: 65 72 00 00 er.. SECTION HEADER #3 .data name 0 physical address 0 virtual address C size of raw data 168 file pointer to raw data (00000168 to 00000173) 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers C0300040 flags Initialized Data 4 byte align Read Write RAW DATA #3 00000000: 54 00 00 00 25 64 0A 00 55 00 00 00 T...%d..U... SECTION HEADER #4 .text$mn name 0 physical address 0 virtual address 4E size of raw data 174 file pointer to raw data (00000174 to 000001C1) 1C2 file pointer to relocation table 0 file pointer to line numbers 5 number of relocations 0 number of line numbers 60500020 flags Code 16 byte align Execute Read RAW DATA #4 00000000: 55 8B EC 8B 45 08 50 68 00 00 00 00 E8 00 00 00 U.ì.E.Ph....è... 00000010: 00 83 C4 08 5D C3 CC CC CC CC CC CC CC CC CC CC ..?.]?ìììììììììì 00000020: 55 8B EC 83 EC 08 C7 45 FC 01 00 00 00 A1 00 00 U.ì.ì.?Eü....?.. 00000030: 00 00 03 05 00 00 00 00 03 45 FC 03 45 F8 50 E8 .........Eü.E?Pè 00000040: 00 00 00 00 83 C4 04 8B 45 FC 8B E5 5D C3 .....?..Eü.?]? RELOCATIONS #4 Symbol Symbol Offset Type Applied To Index Name -------- ---------------- ----------------- -------- ------ 00000008 DIR32 00000000 A $SG1535 0000000D REL32 00000000 F _printf 0000002E DIR32 00000000 B ?static_var@?1??main@@9@9 (`main'::`2'::static_var) 00000034 DIR32 00000000 13 ?static_var2@?1??main@@9@9 (`main'::`2'::static_var2) 00000040 REL32 00000000 E _func1 SECTION HEADER #5 .bss name 0 physical address 0 virtual address 4 size of raw data 0 file pointer to raw data 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers C0300080 flags Uninitialized Data 4 byte align Read Write COFF SYMBOL TABLE 000 010461BB ABS notype Static | @comp.id 001 80000191 ABS notype Static | @feat.00 002 00000000 SECT1 notype Static | .drectve Section length 18, #relocs 0, #linenums 0, checksum 0 004 00000000 SECT2 notype Static | .debug$S Section length 74, #relocs 0, #linenums 0, checksum 0 006 00000000 SECT3 notype Static | .data Section length C, #relocs 0, #linenums 0, checksum AC5AB941 008 00000000 SECT3 notype External | _global_init_var 009 00000004 UNDEF notype External | _global_uninit_var 00A 00000004 SECT3 notype Static | $SG1535 00B 00000008 SECT3 notype Static | ?static_var@?1??main@@9@9 (`main'::`2'::static_var) 00C 00000000 SECT4 notype Static | .text$mn Section length 4E, #relocs 5, #linenums 0, checksum CC61DB94 00E 00000000 SECT4 notype () External | _func1 00F 00000000 UNDEF notype () External | _printf 010 00000020 SECT4 notype () External | _main 011 00000000 SECT5 notype Static | .bss Section length 4, #relocs 0, #linenums 0, checksum 0 013 00000000 SECT5 notype Static | ?static_var2@?1??main@@9@9 (`main'::`2'::static_var2) String Table Size = 0x5D bytes Summary 4 .bss C .data 74 .debug$S 18 .drectve 4E .text$mn
COFF文件結構
COFF的文件頭部包括兩部分,一個是描述文件總體結構和屬性的映像頭,另一個是描述該文件中包含的段屬性的段表。
映像:因為PE文件再裝載時被直接映射到進程的虛擬空間中運行,它時進程的虛擬空間的映像。所以PE可執行文件很多時候被叫做映像文件。
文件頭里描述COFF文件總體屬性的映像頭是一個”IMAGE_FILE_HEADER”的結構,相當於ELF中”Elf32_Ehdr”結構。
上面目標文件中這部分與這個結構對應:
File Type: COFF OBJECT FILE HEADER VALUES 14C machine (x86)//目標機器類型 5 number of sections//PE中所含段的數量 5960849C time date stamp Sat Jul 8 15:07:08 2017//PE文件創建時間 1F4 file pointer to symbol table//符號表在PE文件中的位置 14 number of symbols 0 size of optional header//optional header的大小,這個結構只存在PE可執行文件中,COFF文件中不存在 0 characteristics
COFF OBJECT也就是COFF目標文件格式。
映像頭后面就是COFF文件的段表,它是一個類型”IMAGE_SECTION_HEADER”結構數組,數組里面每一個元素代表一個段,這個結構和ELF文件中的”Elf32——Shdr”很相似。
5.3 鏈接指示信息
上面目標文件中”.drectve”內容:
SECTION HEADER #1 .drectve name 0 physical address 0 virtual address 18 size of raw data DC file pointer to raw data (000000DC to 000000F3) 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers 100A00 flags //標准位,即"IMAGE_SECTION_HEADERS"里面的Characteristics成員。 Info Remove 1 byte align//這三個組合屬性表示該段時信息段,並非程序數據 RAW DATA #1//該段在文件中的原始數據 00000000: 20 20 20 2F 44 45 46 41 55 4C 54 4C 49 42 3A 22 /DEFAULTLIB:" 00000010: 4C 49 42 43 4D 54 22 20 LIBCMT" //dumpbin對該段進行解析后的結果,它就是"cl"編譯器希望傳遞給"link"鏈接器的參數,它表示VC的靜態鏈接的多線程C庫。 Linker Directives ----------------- /DEFAULTLIB:LIBCMT
它的內容時編譯器傳給鏈接器的指令。
5.4 調試信息
COFF文件中所有以”.debug”開始的段都包含着調試信息。
- “.debug$S”表示包含的是符號相關的調試信息。
- “.debug$P”表示包含的是預編譯頭文件相關的調試信息。
- “.debug$T”表示包含的是類型相關的調試信息。
調試信息段具體格式被定義在PE格式文件標准中。
SECTION HEADER #2 .debug$S name 0 physical address 0 virtual address 74 size of raw data F4 file pointer to raw data (000000F4 to 00000167) 0 file pointer to relocation table 0 file pointer to line numbers 0 number of relocations 0 number of line numbers 42100040 flags Initialized Data Discardable 1 byte align Read Only RAW DATA #2 00000000: 04 00 00 00 F1 00 00 00 67 00 00 00 29 00 01 11 ....?...g...)... 00000010: 00 00 00 00 44 3A 5C 53 69 6D 70 6C 65 53 65 63 ....D:\SimpleSec 00000020: 74 69 6F 6E 5C 53 69 6D 70 6C 65 53 65 63 74 69 tion\SimpleSecti 00000030: 6F 6E 2E 6F 62 6A 00 3A 00 3C 11 00 22 00 00 07 on.obj.:.<.."... 00000040: 00 13 00 0A 00 BB 61 00 00 13 00 0A 00 BB 61 00 .....?a......?a. 00000050: 00 4D 69 63 72 6F 73 6F 66 74 20 28 52 29 20 4F .Microsoft (R) O 00000060: 70 74 69 6D 69 7A 69 6E 67 20 43 6F 6D 70 69 6C ptimizing Compil 00000070: 65 72 00 00
5.5 符號表
COFF符號表的內容基本和ELF文件的符號表一樣,主要是符號名。符號的類型,所在的位置
COFF SYMBOL TABLE //符號編號 符號大小 符號所在位置 符號類型,只有兩種notype和notype() 符號可見范圍 符號名 000 010461BB ABS notype Static | @comp.id //ABS表示符號是個絕對值,不存在任何段中 001 80000191 ABS notype Static | @feat.00 //notype 變量和其他符號 002 00000000 SECT1 notype Static | .drectve //表示符號所表示的對象定義在本COFF文件的第一個段中 Section length 18, #relocs 0, #linenums 0, checksum 0 004 00000000 SECT2 notype Static | .debug$S //Static局部變量,只有目標文件中可見 Section length 74, #relocs 0, #linenums 0, checksum 0 006 00000000 SECT3 notype Static | .data Section length C, #relocs 0, #linenums 0, checksum AC5AB941 008 00000000 SECT3 notype External | _global_init_var //External全局變量,可以被其他目標文件引用 009 00000004 UNDEF notype External | _global_uninit_var //表示符號未定義,即這個符號被定義在其他目標文件中 00A 00000004 SECT3 notype Static | $SG1535 00B 00000008 SECT3 notype Static | ?static_var@?1??main@@9@9 (`main::`2::static_var) 00C 00000000 SECT4 notype Static | .text$mn Section length 4E, #relocs 5, #linenums 0, checksum CC61DB94 00E 00000000 SECT4 notype () External | _func1 //notype ()函數 00F 00000000 UNDEF notype () External | _printf 010 00000020 SECT4 notype () External | _main 011 00000000 SECT5 notype Static | .bss Section length 4, #relocs 0, #linenums 0, checksum 0 013 00000000 SECT5 notype Static | ?static_var2@?1??main@@9@9 (`main::`2::static_var2)
5.6 Windows下的ELF——PE
PE文件是基於COFF的擴展,它比COFF文件多幾個結構,最主要變化:
- 文件最開始的部分不是COFF文件頭,而是DOS MZ可執行文件格式的文件頭和樁代碼。
- 原來的COFF文件頭中的”IMAGE_FILE_HEADER”部分擴展成PE文件文件頭結構”IMAGE_NT_HEADERS”,這個結構包括原來的”Image Header”及新增的PE擴展頭部結構。