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.0Copyright (C) Microsoft Corporation. All rights reserved.Dump of file SimpleSection.objFile Type: COFF OBJECTFILE HEADER VALUES14C machine (x86)5 number of sections5960849C time date stamp Sat Jul 8 15:07:08 20171F4 file pointer to symbol table14 number of symbols0 size of optional header0 characteristicsSECTION HEADER #1.drectve name0 physical address0 virtual address18 size of raw dataDC file pointer to raw data (000000DC to 000000F3)0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers100A00 flagsInfoRemove1 byte alignRAW DATA #100000000: 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:LIBCMTSECTION HEADER #2.debug$S name0 physical address0 virtual address74 size of raw dataF4 file pointer to raw data (000000F4 to 00000167)0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers42100040 flagsInitialized DataDiscardable1 byte alignRead OnlyRAW DATA #200000000: 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:\SimpleSec00000020: 74 69 6F 6E 5C 53 69 6D 70 6C 65 53 65 63 74 69 tion\SimpleSecti00000030: 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) O00000060: 70 74 69 6D 69 7A 69 6E 67 20 43 6F 6D 70 69 6C ptimizing Compil00000070: 65 72 00 00 er..SECTION HEADER #3.data name0 physical address0 virtual addressC size of raw data168 file pointer to raw data (00000168 to 00000173)0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbersC0300040 flagsInitialized Data4 byte alignRead WriteRAW DATA #300000000: 54 00 00 00 25 64 0A 00 55 00 00 00 T...%d..U...SECTION HEADER #4.text$mn name0 physical address0 virtual address4E size of raw data174 file pointer to raw data (00000174 to 000001C1)1C2 file pointer to relocation table0 file pointer to line numbers5 number of relocations0 number of line numbers60500020 flagsCode16 byte alignExecute ReadRAW DATA #400000000: 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 #4Symbol SymbolOffset Type Applied To Index Name-------- ---------------- ----------------- -------- ------00000008 DIR32 00000000 A $SG15350000000D REL32 00000000 F _printf0000002E 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 _func1SECTION HEADER #5.bss name0 physical address0 virtual address4 size of raw data0 file pointer to raw data0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbersC0300080 flagsUninitialized Data4 byte alignRead WriteCOFF SYMBOL TABLE000 010461BB ABS notype Static | @comp.id001 80000191 ABS notype Static | @feat.00002 00000000 SECT1 notype Static | .drectveSection length 18, #relocs 0, #linenums 0, checksum 0004 00000000 SECT2 notype Static | .debug$SSection length 74, #relocs 0, #linenums 0, checksum 0006 00000000 SECT3 notype Static | .dataSection length C, #relocs 0, #linenums 0, checksum AC5AB941008 00000000 SECT3 notype External | _global_init_var009 00000004 UNDEF notype External | _global_uninit_var00A 00000004 SECT3 notype Static | $SG153500B 00000008 SECT3 notype Static | ?static_var@?1??main@@9@9 (`main'::`2'::static_var)00C 00000000 SECT4 notype Static | .text$mnSection length 4E, #relocs 5, #linenums 0, checksum CC61DB9400E 00000000 SECT4 notype () External | _func100F 00000000 UNDEF notype () External | _printf010 00000020 SECT4 notype () External | _main011 00000000 SECT5 notype Static | .bssSection length 4, #relocs 0, #linenums 0, checksum 0013 00000000 SECT5 notype Static | ?static_var2@?1??main@@9@9 (`main'::`2'::static_var2)String Table Size = 0x5D bytesSummary4 .bssC .data74 .debug$S18 .drectve4E .text$mn
COFF文件结构
COFF的文件头部包括两部分,一个是描述文件总体结构和属性的映像头,另一个是描述该文件中包含的段属性的段表。
映像:因为PE文件再装载时被直接映射到进程的虚拟空间中运行,它时进程的虚拟空间的映像。所以PE可执行文件很多时候被叫做映像文件。文件头里描述COFF文件总体属性的映像头是一个”IMAGE_FILE_HEADER”的结构,相当于ELF中”Elf32_Ehdr”结构。
上面目标文件中这部分与这个结构对应:
File Type: COFF OBJECTFILE HEADER VALUES14C 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 symbols0 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 name0 physical address0 virtual address18 size of raw dataDC file pointer to raw data (000000DC to 000000F3)0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers100A00 flags //标准位,即"IMAGE_SECTION_HEADERS"里面的Characteristics成员。InfoRemove1 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 name0 physical address0 virtual address74 size of raw dataF4 file pointer to raw data (000000F4 to 00000167)0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers42100040 flagsInitialized DataDiscardable1 byte alignRead OnlyRAW DATA #200000000: 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:\SimpleSec00000020: 74 69 6F 6E 5C 53 69 6D 70 6C 65 53 65 63 74 69 tion\SimpleSecti00000030: 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) O00000060: 70 74 69 6D 69 7A 69 6E 67 20 43 6F 6D 70 69 6C ptimizing Compil00000070: 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 0004 00000000 SECT2 notype Static | .debug$S //Static局部变量,只有目标文件中可见Section length 74, #relocs 0, #linenums 0, checksum 0006 00000000 SECT3 notype Static | .dataSection length C, #relocs 0, #linenums 0, checksum AC5AB941008 00000000 SECT3 notype External | _global_init_var //External全局变量,可以被其他目标文件引用009 00000004 UNDEF notype External | _global_uninit_var //表示符号未定义,即这个符号被定义在其他目标文件中00A 00000004 SECT3 notype Static | $SG153500B 00000008 SECT3 notype Static | ?static_var@?1??main@@9@9 (`main::`2::static_var)00C 00000000 SECT4 notype Static | .text$mnSection length 4E, #relocs 5, #linenums 0, checksum CC61DB9400E 00000000 SECT4 notype () External | _func1 //notype ()函数00F 00000000 UNDEF notype () External | _printf010 00000020 SECT4 notype () External | _main011 00000000 SECT5 notype Static | .bssSection length 4, #relocs 0, #linenums 0, checksum 0013 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扩展头部结构。