ELF文件格式
0x00 准备
ELF全称Executable and Linking Format,ELF文件主要有3种,在文件内部有2个byte用来指明该ELF文件的类型(后文详述)。为了分析ELF文件的结构,准备好一个简单的c语言“hello world”程序,编译该文件得到ELF文件。
hw.c
#include <stdio.h>
int main(){
printf("hello world!\n");
return ;
}
命令:gcc -c hw.c
得到文件hw.o
命令:gcc hw.c -o hw
得到文件hw
在分析的过程中会:
- 使用hexdump命令查看ELF文件的二进制数据
- 使用readelf命令查看ELF文件的结构分析
- 使用objdump命令查看ELF文件的信息
命令:hexdump -C hw
得到ELF文件hw的二进制显示:
f c |.ELF............|
e |..>.....@.@.....|
c8 |@...............|
e b |....@...@.....|
|........@.......|
|@.@.....@.@.....|
f8 f8 |................|
|................|
|......@.....|
c |@.............|
a0 c |................|
b0 |................|
c0 |..@.......@.....|
d0 c c |................|
|.. .............|
f0 e e |..........`.....|
........
0x01 ELF文件头(ELF Header):前64字节
ELF文件的前64个字节(这里指的是64位系统下,32位系统下稍有不同,是52个字节)描述了ELF文件的基本信息,被称为ELF头
先分析前16个byte(0-15)
(0-3)byte:7f 45 4c 46
这个是ELF文件的魔数,每一种文件一般都有魔数,用来表明该文件的类型,例如java的class文件的魔数就是前4个byte :CAFEBABE
(4)byte : 02
这个字节标识此ELF文件的平台类型,有3个可选值
0x00 :无效文件
0x01 :32bit平台目标文件(ELF文件)
0x02 :64bit平台目标文件
这里是值为0x02表明是在64位系统下编译的
(5)byte:01
这个字节标识二进制文件的编码类型,有3个可选值
0x00:无效编码
0x01:小印第安排序(最大有意义的字节占有最低的地址)
0x02:大印第安排序(最大有意义的字节占有最高的地址)
这里的值为0x01表明此ELF文件使用的是小印第安排序
(6)byte:01
这个字节指明ELF文件格式的版本,当前必须为0x01
(7)byte :00 00 00 00 00 00 00 00 00
OS/ABI
(8)byte : 00
ABI version
(9-15)byte : 00 00 00 00 00 00 00
当前没有意义,但是在将来可能有意义,规定必须每个byte都设置为0x00 ,但是其实不设置为0x00也可以,例如病毒程序就可以用这些byte来表明改ELF文件是否已经被感染,或者是处于其他什么状态
再分析后48个byte(16-63)
(16-17)byte 02 00
这2个字节表明文章开头所说的ELF文件的类型,(5)byte表明ELF文件是小印第安排序,因此这2个字节的值为0x0002 ,说明这是一个可执行文件。这2个字节的可选值如下:
0x0000 : 未知
0x0001 : 重定位文件
0x0002 : 可执行文件
0x0003 : 共享库文件
0x0004 : 核心文件
0xff00 - 0xffff : 处理器相关
(18-19)byte 3e 00
这2个字节表明机器架构,0x003e说明是x86_64机器
这个值的部分可选值有:
0x00 : No Manchine
0x02 : SPARC
0x03 : Intel 80386
0x12 : Sun SPARC 32+
0x2b : SPARC V9
0x3e : ADM 64
(20-23)byte 01 00 00 00
这4个字节说明此目标文件的版本,当前的版本均为1
(24-31)byte 40 04 40 00 00 00 00 00
这8个字节是程序入口点地址,也就是main函数的逻辑地址,在64位系统下用8个字节表示,32为系统下只有4个字节,这个值说明main函数的逻辑地址为:0x0000000000040440c8 19 00 00 00 00 00 00
(32-39)byte 40 00 00 00 00 00 00 00
这8个字节是程序头表(program header table)在目标文件中的偏移地址,这里的值为0x40,即64,说明程序头表从第64字节开始,也就是紧接着ELF Header之后。如果没有程序头表,这个值为0
(40-47)byte c8 19 00 00 00 00 00 00
这8个字节是节头表(section header table)在目标文件中的偏移地址,这里的值为0x19c8 ,说明节头表在目标文件的6600字节。如果没有节头表这个值为0
(48-51)byte 00 00 00 00
这4个字节就是一个与处理器相关的标识(flag)
(52-53)byte 40 00
这2个字节说明ELF Header本身的大小,64位系统的下是64字节,所以是0x0040
(54-55)byte 38 00
这2个字节标识在程序头表中每个程序头的大小(以字节为单位,每个程序头的大小都是一样的),此ELF文件中每个程序头的大小为0x38个字节
(56-57)byte 09 00
这2个字节说明程序头表中程序头的个数, 没有的话就是0,此ELF文件有9个程序头
(58-59)byte 40 00
这2个字节标识在节头表中每个节头的大小(以字节为单位,每个节头的大小都是一样的),此ELF文件每个节头的大小是0x40,即64个字节
(60-61)byte 1e 00
这2个字节标识节头表中节头的个数,没有的话就是0,0x1e说明ELF文件有30个节头
(62-63)byte 1b 00
这2个字节表示的值是一个节头表的索引值(因此这个值0x1b必然小于总数0x1e),通过这个索引值,可以在节头表中找到一个特殊的节头,在这个节头中有每个节头的字符串名字信息。没有这样一个特殊的节头的话这个值就是0