0x00 序言
本文是因为当前的COFF文件中对于当前的芯片的软件构建,COFF本身是在很久以前的文件了,所以现在在互联网上的资料极少,且当年的COFF文件主要是在替换a.out
文件格式,也就是对其的可扩展性增加。而ELF也是对于其的增加,COFF就被夹在了中间,所以这份COFF文档会和我的ELF解析差不多。
而因为COFF已经是上个世纪的不需要太对兼容负责的程序格式了,所以自然也就是直接淘汰在现在的执行序列里面了,除了固定的一些应用场景,已经越来越少看到这类文件了。
而且现在的解析器也越来越少,所以很多软件都已经是定制性的。
因为遇到了TI 的CCS文件的操作,所以准备在这里叙述一下COFF文件的结构。
笔者现在能找到的就是Linux系列的文件介绍与TI的自定义的COFF文件格式。
需要说明的是,两者比起来,TI的文件更像是前者的简化自定义版,所以这里主要介绍Linux的文件介绍。
阅读本文之前,您需要掌握的技能有:
技能名称 | 技能熟练度 | 技能教程链接 |
---|---|---|
C语言 | 熟悉 | 暂无 |
0x10 文件头说明
COFF与ELF相比,更像是一个阉割版的ELF文件,但是麻雀虽小五脏俱全。
一个标准的文件头包括了以下几个大部分:
- 文件头硬编码
- 文件头的信息说明
- 字符串头
- 未定义的段定义数据
- 重定向的段数据信息
- 标签与相关的字符串
0x11 头文件硬编码
一个严谨的文件格式肯定会定义第一个专属的文件识别编码。也就是真正意义上的文件头。
COFF的文件头规定了其文件的段个数、生成时间戳、各个区块的入口与文件的针对性的芯片与指令。
位置 | 格式定义 | 说明 | 称呼 |
---|---|---|---|
0-1 | unsigned short | 版本号以及一些文件的版本信息 | 版本信息 |
2-3 | unsigned short | 当前段的个数 | 段计数 |
4-7 | unsigned int | 时间戳,这个并不是必须的,但是规定下一般都会写入 | 时间戳 |
8-11 | unsigned int | 标识符空间的指针 | 标识符指针 |
12-15 | unsigned int | 标识符的个数 | 标志个数 |
16-17 | unsigned short | 设置相关的参数的长度,可能是0,因为有些情况下不需要 | 自定义参数 |
18-19 | unsigned short | 一些文档的格式标志,大多数时间都会同时置很多 | 文件属性 |
上面这些就是一个典型的文件头的内容了
于是可以获得如下的自定义格式:
typedef struct
{
unsigned short Version_id;
unsigned short section_h_count;
unsigned int time_about;
unsigned int symbol_point;
unsigned short optional;//需要注意的是,这里不用可以写空,但是一定要存在
unsigned short flag;
}
版本信息的定义
这里需要知道的是,版本信息虽然不是一个必须要用到的参数,但是还是有定义的一个参数。下面就是TI对其的一些定义:
版本信息 | 变量 | 说明 |
---|---|---|
IMAGE_FILE_MACHINE_UNKNOWN | 0x0 | Contents assumed to beapplicable to any machine type. |
IMAGE_FILE_MACHINE_ALPHA | 0x184 | Alpha AXP™. |
IMAGE_FILE_MACHINE_ARM | 0x1c0 | |
IMAGE_FILE_MACHINE_ALPHA64 | 0x284 | Alpha AXP™ 64-bit. |
IMAGE_FILE_MACHINE_I386 | 0x14c | Intel 386 or later, andcompatible processors |
IMAGE_FILE_MACHINE_IA64 | 0x200 | Intel IA64™ |
IMAGE_FILE_MACHINE_M68K | 0x268 | Motorola 68000 series. |
IMAGE_FILE_MACHINE_MIPS16 | 0x266 | |
IMAGE_FILE_MACHINE_MIPSFPU | 0x366 | MIPS with FPU |
IMAGE_FILE_MACHINE_MIPSFPU16 | 0x466 | MIPS16 with FPU |
IMAGE_FILE_MACHINE_POWERPC | 0x1f0 | Power PC, little endian. |
IMAGE_FILE_MACHINE_R3000 | 0x162 | |
IMAGE_FILE_MACHINE_R4000 | 0x166 | MIPS® little endian |
IMAGE_FILE_MACHINE_R10000 | 0x168 | |
IMAGE_FILE_MACHINE_SH3 | 0x1a2 | Hitachi SH3 |
IMAGE_FILE_MACHINE_SH4 | 0x1a6 | Hitachi SH4 |
IMAGE_FILE_MACHINE_THUMB | 0x1c2 |
flag参数
这些主要是这个文件的执行定义
变量 | 参数 | 定义 |
---|---|---|
IMAGE_FILE_RELOCS_STRIPPED | 0x0001 | 重定义的信息剥离 |
IMAGE_FILE_EXECUTABLE_IMAGE | 0x0002 | 本文件可以单独使用(没有外部依赖) |
IMAGE_FILE_LINE_NUMS_STRIPPED | 0x0004 | 长度数字已经剥离. |
IMAGE_FILE_LOCAL_SYMS_STRIPPED | 0x0008 | 符号区域已被剥离 |
IMAGE_FILE_AGGRESSIVE_WS_TRIM | 0x0010 | 优先优化工作的位置 |
IMAGE_FILE_LARGE_ADDRESS_AWARE | 0x0020 | 应用可以检索大于2GB的地址 |
IMAGE_FILE_16BIT_MACHINE | 0x0040 | 16位机专用,保留 |
IMAGE_FILE_BYTES_REVERSED_LO | 0x0080 | 小端编码 |
IMAGE_FILE_32BIT_MACHINE | 0x0100 | 32位芯片限定. |
IMAGE_FILE_DEBUG_STRIPPED | 0x0200 | 调试文件已经删除. |
IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP | 0x0400 | 多用于定义的多媒体文件内存区块 |
IMAGE_FILE_SYSTEM | 0x1000 | 系统文件限定. |
IMAGE_FILE_DLL | 0x2000 | 这里是个dll. |
IMAGE_FILE_UP_SYSTEM_ONLY | 0x4000 | 似乎是某个特殊机器使用的文件(UP机器) |
IMAGE_FILE_BYTES_REVERSED_HI | 0x8000 | 大端编码. |
这里的文档就是暂时的LINUX早期的文件的定义,这个其实也是可以随便定义的,但是这里依照LINUX提供的文件,讲述这个比较好一些。
但是我看了TI文件后,它们的定义几乎没几个一样的(可能是TI为了节省一些文件空间)。
0x12自定义参数
这个参数是这个文件的属性参数之一,主要的作用是告诉解析器具体的软件结构
位置 | 格式定义 | 说明 | 称呼 |
---|---|---|---|
0-1 | unsigned short | 特定的文件定义 | diy |
2-3 | unsigned short | 版本号 | version |
4-7 | unsigned long | 可执行代码尺寸 | sizeof_exec |
8-11 | unsigned long | 已被初始化的尺寸 | sizeof_init |
12-15 | unsigned long | 未初始化的尺寸 | sizeof_uninit |
16-19 | unsigned long | 当前的文件入口 | entry |
20-23 | unsigned long | 可执行代码的入口 | exec_entry |
24-27 | unsigned long | 已初始化的数据入口 | data_entry |
上面的所有入口基本上都是当前的文件入口,也就是当前的文件的真实结构。
原本文档里面有很多的表格,关于PE文档的一些与关于库文件的一些这里没有细说,现有的嵌入式也不常用。所以这里也就仅仅介绍最简单的部分。
0x20段结构
段结构是一个基本的代码结构,这只是个对于数据的定义。是一个简单的列表结构,包罗了长度,名称,地址与偏移什么的。下表就是一个典型的段结构
位置 | 长度 | 名称 | 介绍 |
---|---|---|---|
0 | 8 | 段名称 | 字符串 |
8 | 4 | 虚拟长度 | 软件真实空间的长度 |
12 | 4 | 虚拟地址 | 软件真实空间的地址 |
16 | 4 | 真实的代码尺寸 | 这个是段的尺寸,这个是8位为一个基准 |
20 | 4 | 指针的真实地址 | 文件中的指针的真实地址。 |
24 | 4 | 重定义的地址 | 如果是重定向的地址就会填进去,但是如果不是的话固定为0 |
28 | 4 | 行数指针 | 行数的地址 |
32 | 2 | 重定义的编码 | 重定义的编码。比如是1.2.3.4什么的 |
34 | 2 | 行数的编码 | 行数的个数。和上面的那个差不多 |
36 | 2 | 标志位 | 当前段的标志位 |
至于最后的一位,也是比较重要的定义项:
Flag | Value | 介绍 |
---|---|---|
IMAGE_SCN_TYPE_REG | 0x00000000 | 现已不用 |
IMAGE_SCN_TYPE_DSECT | 0x00000001 | 现已不用 |
IMAGE_SCN_TYPE_NOLOAD | 0x00000002 | 现已不用 |
IMAGE_SCN_TYPE_GROUP | 0x00000004 | 现已不用 |
IMAGE_SCN_TYPE_NO_PAD | 0x00000008 | 被更好的使用方式替代 |
IMAGE_SCN_TYPE_COPY | 0x00000010 | 现已不用 |
IMAGE_SCN_CNT_CODE | 0x00000020 | 执行代码段 |
IMAGE_SCN_CNT_INITIALIZED_DATA | 0x00000040 | 初始化的数据段 |
IMAGE_SCN_CNT_UNINITIALIZED_DATA | 0x00000080 | 未初始化的数据段 |
IMAGE_SCN_LNK_OTHER | 0x00000100 | 现已不用 |
IMAGE_SCN_LNK_INFO | 0x00000200 | 一些不怎么重要的信息段 |
IMAGE_SCN_TYPE_OVER | 0x00000400 | 现已不用 |
IMAGE_SCN_LNK_REMOVE | 0x00000800 | link段删除的标志 |
IMAGE_SCN_LNK_COMDAT | 0x00001000 | 共同的数据段的特殊标志 |
IMAGE_SCN_MEM_FARDATA | 0x00008000 | 现已不用 |
IMAGE_SCN_MEM_PURGEABLE | 0x00020000 | 现已不用 |
IMAGE_SCN_MEM_16BIT | 0x00020000 | 现已不用 |
IMAGE_SCN_MEM_LOCKED | 0x00040000 | 现已不用 |
IMAGE_SCN_MEM_PRELOAD | 0x00080000 | 现已不用 |
IMAGE_SCN_ALIGN_1BYTES | 0x00100000 | 以1个八位字节排列的定义 |
IMAGE_SCN_ALIGN_2BYTES | 0x00200000 | 以2个八位字节排列的定义 |
IMAGE_SCN_ALIGN_4BYTES | 0x00300000 | 以4个八位字节排列的定义 |
IMAGE_SCN_ALIGN_8BYTES | 0x00400000 | 以8个八位字节排列的定义 |
IMAGE_SCN_ALIGN_16BYTES | 0x00500000 | 以16个八位字节排列的定义 |
IMAGE_SCN_ALIGN_32BYTES | 0x00600000 | 以32个八位字节排列的定义 |
IMAGE_SCN_ALIGN_64BYTES | 0x00700000 | 以64个八位字节排列的定义 |
IMAGE_SCN_ALIGN_128BYTES | 0x00800000 | 以128个八位字节排列的定义 |
IMAGE_SCN_ALIGN_256BYTES | 0x00900000 | 以256个八位字节排列的定义 |
IMAGE_SCN_ALIGN_512BYTES | 0x00A00000 | 以512个八位字节排列的定义 |
IMAGE_SCN_ALIGN_1024BYTES | 0x00B00000 | 以1024个八位字节排列的定义 |
IMAGE_SCN_ALIGN_2048BYTES | 0x00C00000 | 以2048个八位字节排列的定义 |
IMAGE_SCN_ALIGN_4096BYTES | 0x00D00000 | 以4096个八位字节排列的定义 |
IMAGE_SCN_ALIGN_8192BYTES | 0x00E00000 | 以8192个八位字节排列的定义 |
IMAGE_SCN_LNK_NRELOC_OVFL | 0x01000000 | 需要外部的重定义的数据,也就是说这个地址的重定义大小已经超过寻址的空间。 |
IMAGE_SCN_MEM_DISCARDABLE | 0x02000000 | 这个段是可以被丢弃的 |
IMAGE_SCN_MEM_NOT_CACHED | 0x04000000 | 段没办法被缓存 |
IMAGE_SCN_MEM_NOT_PAGED | 0x08000000 | 这个段没有页的存在 |
IMAGE_SCN_MEM_SHARED | 0x10000000 | 这个段可以被内存共享 |
IMAGE_SCN_MEM_EXECUTE | 0x20000000 | 这个段可以被执行 |
IMAGE_SCN_MEM_READ | 0x40000000 | 这个段可以被读取 |
IMAGE_SCN_MEM_WRITE | 0x80000000 | 这个段可以被写入 |
这个是单个段的具体属性,类似于文件的只读、执行、只写等操作。
0x30 结尾
这个就是定义Windows的相关文件的结构,COFF因为过于久远,几乎已经可以追溯到可执行文件的初始结构统一上了。而现在的PE文件其实几乎和这个文件没有一点相同了(除了一些基础的文件结构)。
但是还是对于很多的现代文件的构成是一个参考。
具体的现代文件结构里程碑大概是从压缩文件与网页超文本结构出现有关。这个可能需要等到后面再说啦。
更多
本文首发自 记:COFF文件下的解析说明,更多文章可进入我的博客详查。