您的位置:首页 > 运维架构 > Linux

Linux课程实践四:ELF文件格式分析

2016-05-28 15:22 573 查看

一、ELF文件格式概述

1. ELF文件

ELF:Executable and Linking Format,是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东西、以及都以什么样的格式去放这些东西。

2. 三种类型

(1)可重定位文件

编译器和汇编器创建

运行前需要被链接器处理

(2)可执行文件

完成了所有重定位工作和符号解析

除了运行时解析的共享库符号

(3)共享库文件

链接器需要的符号信息

运行时可以直接执行的代码

二、分析一个ELF文件

以一个最简单的helloworld程序为例

1. ELF文件头

使用工具查看ELF文件头:

readelf -h obj




/usr/include/elf.h
中可以找到文件头结构定义:



大小总共为64字节,换算成十六进制为0x40。在十六进制代码中找到前0x40字节,即为文件头信息部分(阅读时注意反序问题):



(1)identification

魔数部分:



第一部分:占四个字节。

7f 45 4c 46
,应读为
4c 46 45 7f
,对应ASCII码
ELF.
,表示这是一个ELF对象。

第二部分:占一个字节。

02
表示是一个64位对象。

第三部分:占一个字节。

01
表示是小端表示法。

第四部分:占一个字节。

01
表示文件头版本。

其余默认为
0


(2)information

信息部分:



e_type:两个字节

01 00
表示是一个重定位文件。

e_machine:两个字节

3e 00
表示是intel80386处理器体系结构。

e_version:四个字节

01 00 00 00
表示是当前版本。

e_entry:八个字节。

00 00 00 00 00 00 00 00
表示当前程序没有入口点。

e_phoff:八个字节

00 00 00 00 00 00 00 00
表示没有程序头表。

e_shoff:八个字节

90 02 00 00 00 00 00 00
表示段表的偏移地址在
00 00 00 00 00 00 02 90
处。

e_flags:四个字节

00 00 00 00
表示未知处理器特定标志
#define EF_SH_UNKNOWN 0x0


e_ehsize:两个字节

40 00
表示elf文件头大小为
00 40
(64个字节)。

e_phentsize:两个字节

00 00
表示重定位文件没有程序头表。

e_phnum:两个字节

00 00
表示重定位文件没有程序头表。

e_ehentsize:两个字节

40 00
表示段头大小为
00 40
(64字节),section header table中每个header的大小。

e_shnum:两个字节

0d 00
表示段表入口有13个,即段表有13段。

e_shstrndx:两个字节

0a 00
表示段表字符串在段表中的索引号,.shstrab段的段表索引号为
00 0a
,即10.

2. 通过文件头找到各个节

使用工具查看段表信息

readelf -S obj




(1)找到段表

在文件头中
e_shoff
可以找到段表偏移地址
00 00 00 00 00 00 02 90
,从这个地址去查找段表。

段表长度由
e_ehentsize
00 40
(64字节)。

段表个数由
e_shnum
可知有13个。

/usr/include/elf.h
中可以找到段表结构:



(2)分析一个段表

第一个段:全为零,不表示任何段。



第二个段:



sh_name:四个字节

20 00 00 00
表示该段名称在.shstrtab中偏移量,为.test节。

sh_type:四个字节

01 00 00 00
表示这个段拥有程序所定义的信息,其格式和含义完全由该程序确定,这里表示PROGBITS。

sh_flags:八个字节

06 00 00 00 00 00 00 00
表示alloc和execute。

sh_addr:八个字节

00 00 00 00 00 00 00 00
表示是section在内存中的虚拟地址,.o文件不需要执行,这里都是0。

sh_offset:八个字节

40 00 00 00 00 00 00 00
表示是section与文件头之间的偏移。

sh_size:八个字节

11 00 00 00 00 00 00 00
表示文件里面section占用的大小。

sh_link:四个字节

00 00 00 00
表示没有链接信息。

sh_info:四个字节

00 00 00 00
表示没有辅助信息。

sh_addralign:八个字节

01 00 00 00 00 00 00 00
表示字节对齐长度。

sh_entsize:八个字节

00 00 00 00 00 00 00 00
表示没有入口。

(3)所有段表

第三个段:



段名:.rel.text

类型:RELA

标志:info

相对文件头偏移:0x1e0

占用大小:0x30

第四个段



段名:.data

类型:PROGBITS

标志:write、alloc

相对文件头偏移:0x51

占用大小:0

第五个段



段名:.bss

类型:NOBITS

标志:write、alloc

相对文件头偏移:0x51

占用大小:0

第六个段



段名:.rodata

类型:PROGBITS

标志:alloc

相对文件头偏移:0x51

占用大小:0x0b

第七个段



段名:.comment

类型:PROGBITS

标志:merge、strings

相对文件头偏移:0x5c

占用大小:0x26

第八个段



段名:.note.GNU-stack

类型:PROGBITS

标志:无

相对文件头偏移:0x82

占用大小:0

第九个段



段名:.eh_frame

类型:PROGBITS

标志:alloc

相对文件头偏移:0x88

占用大小:0x38

第十个段



段名:.rela.eh_frame

类型:RELA

标志:info

相对文件头偏移:0x210

占用大小:0x18

第十一段



段名:.shstrtab

类型:STRTAB

标志:无

相对文件头偏移:0x228

占用大小:0x61

第十二段



段名:.symtab

类型:STRTAB

标志:无

相对文件头偏移:0xc0

占用大小:0x0108

第十三段



段名:.strtab

类型:STRTAB

标志:无

相对文件头偏移:0x1c8

占用大小:0x11

三、理解常见节

1. .text节

本节中是可执行指令的集合


通过刚才的信息,我们可以从文件中偏移0x40处找到大小为0x11的 .text节:



可以通过反汇编该程序来查看:



2. .rodata

本节是只读数据,ro代表read only


从偏移0x51处找到大小为0x0b的 .rodata节:



使用ASCII码对照表翻译数据为
hello 5317
,即.c文件中的字符串:



2. .comment

本节用来存放编译器版本信息


从偏移0x5c处找到大小为0x26的 .comment节:



使用ASCII码对照表翻译出来数据为
GCC:(Debian 5.3.1-8) 5.3.1 20160205


3. .symtab

本节存放所有section中定义的符号名字,一般是变量、函数shstrtab及symtab经常引用strtab中的字符串


从偏移0xc0处找到大小为0x0108的 .symtab节:



4. .strtab

本节是段表的字符串表


从偏移0x1c8处找到大小为0x11的 .strtab节:



数据用“0”分隔出了三部分,用ASCII码翻译:

65 6c 66 2e 63
elf.c


6d 61 69 6e
main


70 75 74 73
puts
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: