闲来无事,就翻了翻书,看到PC平台上流程的可执行文件格式,感觉有点意思,就准备仔细品读一番
其实主要两大平台下的可执行文件,windows下的PE格式以及Linux下的ELF格式,他们都是COFF格式的变种。
目标文件呢?就是源代码编译后但未进行链接的那些中间文件(类似于Windows下的*.obj以及linux下的*.o)
他跟可执行文件的格式很像,跟亲兄弟一般,呵呵,姑且这么说吧,所以呢,一般跟可执行文件一起采用一种格式存储。
从广义上看,目标文件和可执行文件的格式其实几乎一样,所以可以将之看为一种类型的文件。
不光可执行文件(Windows下的*.exe或者Linux下的elf可执行文件)按照可执行文件格式存储,动态链接库(Windows下的
DLL和Linux下的*.so)以及静态链接库(Windows下的.lib和Linux下的.o)都按照可执行文件格式存储
下面还是分析一下Windows的COFF文件
COFF-通用对象文件格式(Common Object File Format),是一种很流行的对象文件格式
先来看其文件结构
有8种数据,自下而上分别为 1 文件头 (File Header)
2 可选头 (Optional Header)
3 段落头 (Section Header)
4 段落数据 (Section Data)
5 重定位表 (Relocation Directives)
6 行号表 (Line Numbers)
7 符号表 (Symbol Table)
8 字符串表 (String Table)
文件头里描述COFF文件总体属性的映像投是一个"IMAGE_FILE_HEADER"的结构,如下:
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;
这些内容从obj中导出的文件可以看出一二
FileType: COFF OBJECT
FILE HEADER VALUES
14C machine (X86)
5 number of sections
45C975E6 time date stamp Web Feb 07 14:47:02 2007
1E0 file pointer to symbol table
14 number of symbols
0 size of optional header
0 characteristics
映像头后面就是段表,其类型如下
typedef struct _IMAGE_SECTION_HEADER{
BYTE Name[8]; 段名
union{ 物理地址
DWORD PhysicalAddress;
DWORD VirtualSize;
}Misc;
DWORD VirtualAddress; /虚拟地址
DWORD SizeOfRawData; 原始数据大小
DWORD PointerToRawData; /段在文件中的位置
DWORD PointerToRelocations; /该段的重定位表在文件中的位置
DWORD PointerToLineNumbers; ///该段的行号表在文件中的位置
WORD NumberOfRelations;
WORD NumberOflineNumbers;
DWORD Characteristics; ///标志位
}IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;
如下关于导出文件中对于.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
Info
Remove
1 byte align
Raw DATA #1
00000000: 20 20 20 2F 44 45 46 41 55 4C 54 4C49 42 3C 22 /DEFAULTLIB:"
00000010: 4C 49 42 43 4D 54 22 20 LIBCMT"
Linker Directives
-----------------------
/DEFAULTLIB:"LIBCMT"
.drectve 段实际上是Directive的缩写,它的内容是编译器传递给连接器的指令,即编译器希望告诉连接器应该怎样连接这个目标文件
COFF文件中所有以".debug" 开始的段都包含着调试信息
".debug$S" 包含的是符号相关的调试信息段
".debug$P"包含的是编译头文件相关的调试信息段
".debug$T" 包含的是类型相关的调试信息段
接下来是符号表 其内容如下
000 006DC627 ABS notype Static |@comp.id
001 00000001 ABS notype Static |@feat.00
002 00000000 SECT1 notype Static |.drectve
004 00000000 SECT2 notype Static |.debug$S
006 00000004 UNDEF notype External |__global_uninit_var
007 00000000 SECT3 notype Static |.data
009 00000000 SECT3 notype External |._global_init_var
00A 00000004 SECT3 notype Static |$SG594
00B 00000008 SECT3 notype Static | ?static_var@??main@@9@9
00E 00000000 SECT4 notype() External |_func1
00F 00000000 UNDEF notype() External |_printf
010 00000020 SECT4 notype() External |_main
最左边是符号编号,也是符号在符号表中的下标
接着是符号大小,符号所表示的对象所占用的空间
符号所在的位置,ABS标识是个绝对值,即一常量,不存在于任何段中
SECT1标识符号所在本COFF文件第一个段中,UNDEF 标识符号未定义
符号类型 标量和其它符号用notype,函数为notype()
符号的可见范围,Static标识局部变量,External全局变量
符号名
IMAGE_NT_HEADERS 是PE真正的文件头,包含了一个标记和两个结构体,标记是一个常量,对于一个合法的PE文件来说,他的值
是0x00004550,文件头包含两个结构分别为映像头和PE扩展头
typedef struct _IMAGE_NT_HEADER{
DWORD signature;
IMAGE_FILE_HEADER fileHeader;
IMAGE_OPTIONAL_HEADER optionalHeader;
}IMAGE_NT_HEADER,*PIMAGE_NT_HEADER;