linux 解析elf文件格式,Linux下ELF文件解析

1. windows PE文件与Linux ELF文件概述

在windows中可执行文件是pe文件格式,Linux中可执行文件是ELF文件,其文件格式是ELF文件格式,在Linux下的ELF文件除了可执行文件(Excutable File),可重定位目标文件(RellocatableObject File)、共享目标文件(SharedObject File)、核心转储文件(CoreDump File)也都是ELF格式文件。

2.ELF文件结构分析

2.1 ELF文件查看

使用Linux下专用工具——readelf来查看elf文件信息

745491b04daa87040d8e5641b15e1758.png

查看readelf中的源码

bd185ba19ee23c08723f7db97cb5a96c.png

一个典型的ELF文件大致的结构如下:

ELF文件大致的结构文件头(ELF Header)

程序头表(Program Header Table)

代码段(.text)

数据段(.data)

bss段(.bss)

段表字符串表(.shstrtab)

段表(Section Header Table)

符号表(.symtab)

字符串表(.strtab)

重定位表(.rel.text)

重定位表(.rel.data)

2.2 FLF文件组成

2.2.1文件头

用于记录一个ELF文件的信息(多少位?能够运行的CPU平台是什么?程序的入口点在哪里)

查看ELF头

806b53e0e08431e58fe6da0b96ba3c70.png

在readelf的源码中变量类型Elf_Internal_Ehdr_,定义在internal头文件中

#define

EI_NIDENT        16                /* Size of e_ident[] */

typedef

struct elf_internal_ehdr {

unsigned char                e_ident[EI_NIDENT];   /* ELF "magic

number" */

bfd_vma                      e_entry;              /* Entry point virtual address */

bfd_size_type                e_phoff;              /* Program header table file offset */

bfd_size_type                e_shoff;              /* Section header table file offset */

unsigned long                e_version;            /* Identifies object file version */

unsigned long                e_flags;              /* Processor-specific flags */

unsigned short               e_type;               /* Identifies object file type */

unsigned short               e_machine;            /* Specifies required architecture */

unsigned int                 e_ehsize;             /* ELF header size in bytes */

unsigned int                 e_phentsize;          /* Program header table entry size */

unsigned int                 e_phnum;

/* Program header table

entry count */

unsigned int                 e_shentsize;           /* Section header table entry size */

unsigned int                 e_shnum;

/* Section header table

entry count */

unsigned int                 e_shstrndx;            /* Section header string table index */

}

Elf_Internal_Ehdr;

在Linux自带的头文件中查看,源码文件头的结构中一共有14个字段,对应到文件16进制中。

42822465e0c06c0ec2f1ef00dc27e7d7.png#define EI_NIDENT (16) 

typedef struct

{

unsigned char     e_ident[EI_NIDENT];        /* Magic number and other info */

Elf32_Half        e_type;                    /* Object file type */

Elf32_Half        e_machine;                 /* Architecture */

Elf32_Word        e_version;                 /* Object file version */

Elf32_Addr        e_entry;                   /* Entry point virtual address */

Elf32_Off         e_phoff;                   /* Program header table file offset */

Elf32_Off         e_shoff;                   /* Section header table file offset */

Elf32_Word        e_flags;                   /* Processor-specific flags */

Elf32_Half        e_ehsize;                  /* ELF header size in bytes */

Elf32_Half        e_phentsize;               /* Program header table entry size */

Elf32_Half        e_phnum;                   /* Program header table entry count */

Elf32_Half        e_shentsize;               /* Section header table entry size */

Elf32_Half        e_shnum;                   /* Section header table entry count */

Elf32_Half        e_shstrndx;                /* Section header string table index */

} Elf32_Ehdr;

2.2.2 程序头表

记录了每个Segment的相关信息,比如类型、对应文件的偏移、大小、属性等。

程序头表和段头表相对独立,它们是由ELF文件头统一管理,程序头表管理ELF文件加载后,ELF文件内可加载段到内存映像的映射关系,一般只有可执行文件中,包含程序头表。程序头表包含多个程序头表项,程序头表描述的对象称为“Segment”,Segment描述的是ELF文件加载后的数据块,段(Section)描述的是ELF文件加载前的数据块。一般来说,来说两者会存在一定的对应关系,比如代码段.text的加载信息保存在程序头表项对应存放代码的Segment中,数据段.data的加载信息保存在程序头表项对应存放数据的Segment中。有时候为了简化程序头表项的个数,会把同类型的多个段,设置整个ELF文件作为一个Segment。

f30a304feac32ff4fea33ed04e67c081.png

程序头表的数据结构/* Program segment header.  */

typedef struct

{

Elf32_Word        p_type;                 /* Segment type */

Elf32_Off         p_offset;               /* Segment file offset  Segment对应的内容在文件的偏移*/

Elf32_Addr        p_vaddr;                /* Segment virtual address Segment在内存中的线性地址*/

Elf32_Addr        p_paddr;                /* Segment physical address */

Elf32_Word        p_filesz;               /* Segment size in file */

Elf32_Word        p_memsz;                /* Segment size in memory */

Elf32_Word        p_flags;                /* Segment flags */

Elf32_Word        p_align;                /* Segment alignment */

} Elf32_Phdr;

#define        PT_NULL           0                /* Program header table entry unused */

#define        PT_LOAD           1                /* Loadable program segment */

#define        PT_DYNAMIC        2                /* Dynamic linking information */

#define        PT_INTERP         3                /* Program interpreter */

#define        PT_NOTE           4                /* Auxiliary information */

#define        PT_SHLIB          5                /* Reserved */

#define        PT_PHDR           6                /* Entry for header table itself */

#define        PT_TLS            7                /* Thread-local storage segment */

#define        PT_NUM            8                /* Number of defined types */

p_flag权限属性标志

值 说明 宏1 可执行 PE_X

2 可写 PE_W

3 可读 PE_R

2.2.3 区段头表

用于记录ELF文件的主要的数据

查看区段

2bdda38a3de993e776c5692283289362.png

区段表头的数据结构:

typedef struct

{

Elf32_Word sh_name; /* Section name (string tbl index) */

Elf32_Word sh_type; /* Section type */

Elf32_Word sh_flags; /* Section flags */

Elf32_Addr sh_addr; /* Section virtual addr at execution */

Elf32_Off sh_offset; /* Section file offset */

Elf32_Word sh_size; /* Section size in bytes */

Elf32_Word sh_link; /* Link to another section */

Elf32_Word sh_info; /* Additional section information */

Elf32_Word sh_addralign; /* Section alignment */

Elf32_Word sh_entsize; /* Entry size if section holds table */

} Elf32_Shdr;

区段头表一共有10个字段,含义如下:

(1)sh_name段名,是一个是一个4字节的偏移,记录了段名字符串在段表字符串表(“.shstrtab”段)内的偏移。段表字符串并非表的形式,而是一个文件块,保存了所有的段表字符串内容,存储在“.shstrtab”的段中,根据“.shstrtab”的偏移,加上sh_name便可以访问到每个段对应的段名字符串。

56ba12df45fcb95f13edb7bf08aa082e.png

04644caa60e3cfe0cc319fdba3ada402.png

起始地址是000017ac,第一个段表项全0,sh_name在段表项中的偏移是001b,由上图可以得到“.shstrtab”段的偏移是0016ae,

所以,计算段名的偏移应该是0x0000001b+ 0x000016ae = 0x000016c9

根据计算的结果,查看0x000016c9处:

c8b51948461f8178eb161b9079397ff2.png

(2)sh_type,表示段的类型。段的类型有很多,常见的有SHT_PROGBITS,表示程序数据,SHT_SYMTAB表示符号表,SHT_STRTAB表示字符串表,还有专门存放构造函数数组段SHT_INIT_ARRAY,析构函数数组段SHT_FINI_ARRAY。

a   .txt 代码段

b   .data 数据段

c   .radata记录常量数据

d   .symtab记录符号表(相当于PE文件的导出表)的数据

e   .strtab 串表段

f   .shstrtab 有段表 字符串表段

g   .rel .plt记录某个区段的重定位内容(相当于PE文件的导入表)

对应的宏如下:

/* Legal values for sh_type (section type).  */

#define SHT_NULL              0       /* Section header table entry unused */

#define SHT_PROGBITS          1       /* Program data */

#define SHT_SYMTAB            2       /* Symbol table */

#define SHT_STRTAB            3       /* String table */

#define SHT_RELA              4       /* Relocation entries with addends */

#define SHT_HASH              5       /* Symbol hash table */

#define SHT_DYNAMIC           6       /* Dynamic linking information */

#define SHT_NOTE              7       /* Notes */

#define SHT_NOBITS            8       /* Program space with no data (bss) */

#define SHT_REL               9       /* Relocation entries, no addends */

#define SHT_SHLIB             10      /* Reserved */

#define SHT_DYNSYM            11      /* Dynamic linker symbol table */

#define SHT_INIT_ARRAY        14      /* Array of constructors */

#define SHT_FINI_ARRAY        15      /* Array of destructors */

#define SHT_PREINIT_ARRAY     16      /* Array of pre-constructors */

(3)sh_flags,表示段标志,记录段的属性。其中0表示默认属性,1表示段可写,取值位SHF_WRITE。2表示段加载后需要为之分配内存空间,取值为SHF_ALLOC。4表示可执行,取值为SHF_EXECINSTR,段标志属性可以叠加。

(4)sh_addr,表示段加载后的线性地址

(5)sh_offset,表示段在文件内的偏移,根据此偏移可确定段的位置,读取段的内容。

(6)sh_size,表示段的大小,单位为字节。需要注意的是,如果段类型为SHT_NOBITS,段内没有数据,那么段的大小并非指文件块的大小,而是指段加载后占用内存的大小。

27419630f1fdd45c602e1d92184c21d6.png

(7~8)sh_link和sh_info表示段的链接信息,一般用于描述符号表段和重定位表段的链接信息。对于符号表段(SHT_SYMTAB),sh_link记录的是符号表使用的串表所在段(一般是,.strtab)对应段表项在段表内的索引。

5461ebe004834732c52c8d19349399f2.png

sh_info记录的是符号表最后一个局部符号的符号表项在符号表内的索引加1,一般恰好是第一个全局符号的符号表项索引,这样可以帮助连接器更快的地定位到第一个全局符号。如下图:段中符号表段的信息sh_info,刚好是局部符号+1的索引。

c8bd678e49824e43c3cbc6d1e4907894.png

对于重定位表表段(段类型是SHT_REL),sh_link记录重定位所作用的符号表段表项早段内的索引,而sh_info记录重定位所作用的段对应的段表项在段表中的索引。

6e624e51c03d1018ae59f052a960833a.png

sh_type sh_link sh_infoSHT_DYNAMIC 此表项中条目所用到的字符串表在段表中的索引

SHT_HASH 此哈希表所适用的符号表的段表索引

SHT_REL 相关符号表的段表索引 重定位所使用的段的段表索引

SHT_RELA 相关联的字符串表的段表索引 最后一个局部符号的符号表索引值+1

其它 SHN_UNDEF 0

(9)sh_addralign,表示段的对齐方式,对齐规则为 sh_offset %sh_addralign = 0,即段的文件偏移必须是sh_addralign的整数倍,sh_addralign的取值必须是2的整数倍,入1、2、4、8等。

对齐值 对齐方式 说明0 无对齐要求

1 无对齐要求

4 对齐4 满足sh_iffset % 4 = 0

16 对齐16 满足sh_iffset % 16 = 0

32 对齐32 满足sh_iffset % 32 = 0

3559489fa2c54d20b767b210903a7ab1.png

(10) sh_entsize,一般用于保存注入符号表段,重定位表段时,表示段内保存表的表项大小。例如符号表段“.symtab”内保存的符号表的表项大小为sizeof(Elf32_sym)= 16字节,重定位表段“.rel.plt”内保存的重定位表的表项大小为sizeof(Elf32_rel)= 8字节。

2.2.4 ELF符号表(Symbol Table)

ELF文件的符号表保存了程序中的符号信息,包括程序中的文件名、函数名、全局变量名等,符号表一般保存在名为“.strtab”的段内,该段对应段表项的类型为SHT_SYMTAB。符号表包含多个符号表项,每个符号表项记录了符号的名称、位置、类型等信息。

符号表象的数据结构:typedef struct

{

Elf32_Word st_name; /* Symbol name (string tbl index) */

Elf32_Addr st_value; /* Symbol value */

Elf32_Word st_size; /* Symbol size */

unsigned char st_info; /* Symbol type and binding */

unsigned char st_other; /* Symbol visibility */

Elf32_Section st_shndx; /* Section index */

} Elf32_Sym;

0200226d57198c995d2e10487b011f13.png

2.2.5 ELF重定位表(Reloc Table)

重定位表常见于可重定位目标文件内,对于静态链接生成的可可执行文件,一般不包括重定位表,动态链接生成的可执行文件暂时不讨论。重定位表一般保存在以名为“.rel”开头的段内,该段对应段表项的类型为SHT_REL,ELF文件需要重定位的段,一般都对应一个重定位表,比如代码段“.txt”的重定位表保持在“.rel.text”内,数据段“.data”的重定位表保持在“.rel.data”内。

重定位表包含多个重定位表项,每个重定位表项记录一条重定位信息,包括重定位的符号、位置、类型等。

/* Relocation table entry without addend (in section of type SHT_REL). */

typedef struct

{

Elf32_Addr r_offset; /* Address */

Elf32_Word r_info; /* Relocation type and symbol index */

} Elf32_Rel;

b73e5dcfc32be1bd83e67dfc8f52cc70.png

2.2.6 ELF串表(String Table)

ELF文件内的段表和符号表需要记录段名和符号名,这些名称都是字符串。然而,段表项和符号表项都是固定长度的数据结构,无法存储不定长的字符串。因此FLE文件将名称字符串内容集中存放在一个段内,称为串表。这些段表项和符号表项只需记录段名字符串或符号名字符串在对应串表项的位置即可。

虽然存储的字符串表的内容称为串表,但是并非表的形式,而是一个文件区域。

645294af3af7fcfa983ba4bbcb2f79fa.png

-End-

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/396173.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

应用容器公共免费部署平台

从网上信息,发现了一个公共的容器部署平台 openshift.com,可以将我们封装好的docker镜像部署到平台上, 这样就不需要拥有一台云服务器了。对于测试环境非常有用。 首先当然是需要注册。这里全英文 第二,注册之后需要选择你想要的套…

linux 内存管理优化,Linux性能优化实战 内存篇 阅读笔记

第十五讲 基础篇:Linux内存是怎么工作的(2020.6.8)这一讲相关的内容正好之前看csapp的时候总结了一下,可以直接贴出来作为总结了。Linux的内存工作原理,这又是一个特别大的话题。一切向着尽量利用物理资源的方向在发展,在没有虚拟…

傅里叶变换与大数乘法

我们知道,两个 N 位数字的整数的乘法,如果使用常规的算法,时间复杂度是 O(N2)。然而,使用快速傅里叶变换,时间复杂度可以降低到 O(N logN loglogN)。 假设我们要计算以下两个 N 位数字的乘积: a (aN-1aN-2…

linux进程管理类命令大全,Linux进程管理类命令

一、htop命令选项-d #:指定延迟时间间隔;-u UserName:仅显示指定用户的进程;-s COLUME:以指定字段进行排序;子命令:l:显示选定的进程打开的文件列表;s:跟踪选…

android抓包工具——使用fiddler4在安卓手机抓包

Fiddler是一款非常流行并且实用的http抓包工具,它的原理是在本机开启了一个http的代理服务器,然后它会转发所有的http请求和响应,因此,它比一般的firebug或者是chrome自带的抓包工具要好用的多。不仅如此,它还可以支持…

ddt数据驱动

数据驱动原理 1.测试数据为多个字典的list类型 2.测试类前加修饰ddt.ddt 3.case前加修饰ddt.data() 4.运行后用例会自动加载成三个单独的用例 5.测试结果: Testing started at 21:51 ...start!{username: selenium\xe7\xbe\xa4, psw: 232607095}end!start!{username…

Canvas入门06-线段与像素边界

我们知道,使用以下2个API可以绘制一条线段: moveTo(x, y) 向当前路径中增加一条子路径,该子路径只包含一个点,此为线段的起始点lineTo(x, y) 将线段的下一个点加入子路径中context.strokeStyle rgb(200, 200, 0); context.lineWi…

函数表达书-读书笔记

定义函数的方式有两种:一种是函数声明,另一种就是函数表达式。函数声明的语法如下: function functionName(arg0,arg1,arg2){//函数体 } 函数声明,有一个重要特征就是函数声明提升。也就是在执行代码之前会先读取函数声明&#xf…

vs2012新建项目产生的问题

当用vs新建web项目时遇到 只需下载一个vs2012的更新插件 http://download.microsoft.com/download/A/0/2/A02C37E0-77F7-448A-BD5C-F66AB1F78DBC/VS11-KB3002339.exe 点击安装更新即可. 转载于:https://www.cnblogs.com/GreenLeaves/p/5452073.html

zoj4062 Plants vs. Zombies 二分+模拟(贪心的思维)

题目传送门 题目大意:有n个植物排成一排,标号为1-n,每株植物有自己的生长速度ai,每对植物浇一次水,该株植物就长高ai,现在机器人从第0个格子出发,每次走一步,不能停留,每…

MyBatis注解模式批量insert方法

2019独角兽企业重金招聘Python工程师标准>>> 方法一:script标签方式 Insert("<script>insert into xxx (channelId,siteId) " "values " "<foreach collection\"list\" item\"item\" index\"index\&quo…

关于eclipse中文注释乱码的问题

今天打开了一个以前的android项目&#xff0c;发现中文注释都成乱码啦&#xff01;&#xff01;&#xff01; 后来在网上找了一会解决方法&#xff0c;知道了中文的编码大体是两种&#xff1a;GBK(汉字内码扩展规范)和UTF-8(8-bit Unicode Transformation Format)。 因此问题的…

python入门(5)使用文件编辑器编写代码并保存执行

python入门&#xff08;5&#xff09;使用文件编辑器编写代码并保存执行 两款文本编辑器&#xff1a; 一个是Sublime Text&#xff0c;免费使用&#xff0c;但是不付费会弹出提示框&#xff1a; 一个是Notepad&#xff0c;免费使用&#xff0c;有中文界面&#xff1a; 请注意&…

linux 批量同步,多主机目录到备份服务器批量同步脚本

为了方便同步多个主机的目录到备份服务器&#xff0c;写了如下脚本&#xff1a;#!/usr/bin/perluse strict;use File::Spec;use File::Basename;use File::Path;#设定存储路径my $storedir"/backup/";while(){chomp;my ($host,$s_path)split /\t/;my $project_namefi…

交流电的有效值rms值_交流电路的功率三角因数原来是这样理解的

点击“电工电气学习”关注即可免费订阅&#xff01;电工学习网&#xff1a;www.diangon.com关注电工学习网官方微信公众号“电工电气学习”&#xff0c;收获更多经验知识。交流电路中消耗的电能可以用直角三角形的三个边来表示&#xff0c;通常称为功率三角形我们在关于交流电路…

CSS3酷炫样式集合

1、30种炫酷CSS鼠标滑过按钮特效 2、CSS 变量实现炫酷鼠标悬浮效果 3、基于CSS3和jQuery实现跟随鼠标方位的Hover特效 4、css3金属质感登录表单 4、CSS3动态下拉菜单 5、CSS3鼠标悬浮特效 转载于:https://www.cnblogs.com/mankii/p/9922981.html

NOIP2008 普及组T4 立体图 解题报告-S.B.S.(施工未完成)

题目描述 小渊是个聪明的孩子&#xff0c;他经常会给周围的小朋友们将写自己认为有趣的内容。最近&#xff0c;他准备给小朋友们讲解立体图&#xff0c;请你帮他画出立体图。 小渊有一块面积为m*n的矩形区域&#xff0c;上面有m*n个边长为1的格子&#xff0c;每个格子上堆了一些…

HBase基础知识(三):HBase架构进阶、读写流程、MemStoreFlush、StoreFile Compaction、Region Split

1. 架构原理 1&#xff09;StoreFile 保存实际数据的物理文件&#xff0c;StoreFile以HFile的形式存储在HDFS上。每个Store会有一个或多个StoreFile&#xff08;HFile&#xff09;&#xff0c;数据在每个StoreFile中都是有序的。 2&#xff09;MemStore 写缓存&#xff0c;由于…

第一章节测试

大家在做第一章测试题时&#xff0c;需要复习如下相关知识点&#xff1a;编译型VS解释型、变量名规范、数据类型、程序交互、格式化输出、运算符、流程控制。1.简述编译型与解释型语言的区别&#xff0c;且分别列出你知道的那些语言属于编译型&#xff0c;哪些属于解释型。2.执…