基础技术-ELF系列2-ELF文件进阶与libelf库

news2024/12/28 22:01:37

成就更好的自己

本篇是基础技术系列中ELF相关技术的第二篇,将会详细介绍一下ELF文件的结构。

没有看过之前的文章的朋友请重新开始,博主观点比较清奇,否则可能会有一些不太明白的地方:

基础技术-ELF系列(1)-ELF文件基础-CSDN博客


目录

Libelf的简要说明

ELF格式说明

ELF头结构体- GElf_Ehdr

节头结构体- GElf_Shdr

程序头结构体- GElf_Phdr

符号描述结构体- GElf_Sym


Libelf的简要说明

近期工作上有一个小任务,需要在不进行编译的条件下,对比几个库之间是否存在符号重复;原本可以使用nm或者readelf可以通过人肉方式去筛查,但为了减少重复工作,就打算通过程序进行对比;一般来讲使用C/C++的话都会使用libelf进行ELF文件的解析,但是一搜才发现讲ELF的都不是很细致更别提libelf了,这也是撰写本系列文章的根本原因。

Libelf的包名大多是情况下叫做libelf-dev或者libelf-devel,一般的系统不一定会带有这个包,需要通过apt或者yum进行安装,或通过源码的方式进行编译安装。

Apt安装命令:apt install libelf-dev

Yum安装命令:yum install elfutils-libelf-devel

源码地址:GitHub - WolfgangSt/libelf: libelf

Libelf是一个对ELF文件进行解析的的一个库,按照既定的规则调用病解析这个库你可以查看一个ELF文件中的所有想要知道的结构和信息。

目前网上关于ELF文件的解析都会莫名奇妙的拿出来一些结构体进行讲解,实际上,这些结构体都是出自这个库中的libelf.hgelf.h

ELF格式说明

主要与ELF格式相关的结构体有下面这几种:

  1. GElf_Ehdr:存放ELF文件头的结构,对应于ELF文件的ELF头;
  2. GElf_Shdr:存放单个节头的结构,对应于节头表中的单个节头;
  3. GElf_Phdr:存放单个程序头的结构,对应于程序头表中的单个程序头;
  4. GElf_Sym:存放一个节中一个符号的结构,对应于节中的一个符号描述,注意指的不是符号的内容,而是这个符号的一个描述结构,包括这个符号的名称,实际数据对应地址等信息;

还有几种中间类型结构体暂时没有用到,下一篇博客会进行说明。了解了这些基本结构,就可以解析ELF文件了。这张图我这里不做解释,大家可以参考上篇文章内容和这里所说的进行对比理解一下(理解了才能往下看,对吧)。

接下来是对上述结构体中的内容进行简单说明。

ELF头结构体- GElf_Ehdr

typedef struct
{
  unsigned char   e_ident[EI_NIDENT];      /* Magic number and other info */
  Elf64_Half   e_type;                  /* Object file type */
  Elf64_Half   e_machine;           /* Architecture */
  Elf64_Word e_version;             /* Object file version */
  Elf64_Addr  e_entry;         /* Entry point virtual address */
  Elf64_Off    e_phoff;         /* Program header table file offset */
  Elf64_Off    e_shoff;          /* Section header table file offset */
  Elf64_Word e_flags;          /* Processor-specific flags */
  Elf64_Half   e_ehsize;        /* ELF header size in bytes */
  Elf64_Half   e_phentsize;          /* Program header table entry size */
  Elf64_Half   e_phnum;             /* Program header table entry count */
  Elf64_Half   e_shentsize;          /* Section header table entry size */
  Elf64_Half   e_shnum;              /* Section header table entry count */
  Elf64_Half   e_shstrndx;           /* Section header string table index */
} Elf64_Ehdr;

成员

意义

e_ident

16 字节数组,用于标识 ELF 对象,始终以“\x7fELF”开头

e_type

指定 该ELF文件类型,是可执行文件还是重定位还是其他的

e_machine

该ELF文件使用或运行的目标架构

e_version

使用的ELF版本

e_entry

若为可执行文件,则为程序的虚拟地址入口。有时候可以为0

e_phoff

表示程序头表中首个程序头对于该文件的偏移量,单位字节

e_shoff

表示节头表中首个节头对于该文件的偏移量,单位字节

e_flags

与处理器相关的一些标志

e_ehsizeEhdr 

ELF文件头大小,单位字节。(通常在 64 位 ELF 中为 64 字节,在 32 位中为 52 字节)

e_phentsize

ELF文件中单个程序头的大小,单位字节

e_phnum

ELF文件中程序头的数量

e_shentsize

ELF文件中单个节头的大小,单位字节

e_shnum

ELF文件中节头的数量

e_shstrndx

存放每个节的名称字符串的字符串表

节头结构体- GElf_Shdr

typedef struct
{
  Elf64_Word sh_name;              /* Section name (string tbl index) */
  Elf64_Word sh_type;         /* Section type */
  Elf64_Xword      sh_flags;        /* Section flags */
  Elf64_Addr  sh_addr;        /* Section virtual addr at execution */
  Elf64_Off    sh_offset;       /* Section file offset */
  Elf64_Xword      sh_size;          /* Section size in bytes */
  Elf64_Word sh_link;          /* Link to another section */
  Elf64_Word sh_info;          /* Additional section information */
  Elf64_Xword      sh_addralign;        /* Section alignment */
  Elf64_Xword      sh_entsize;            /* Entry size if section holds table */
} Elf64_Shdr;

成员

意义

sh_name

节名称,实际上是个偏移值,是一个基于在ELF头中的e_shstrndx指定的节中进行偏移取字符串的偏移值

sh_type

该节的类型

sh_flags

该节的内容是什么操作属性的,可读可写可执行等

sh_addr

若该节处于某个要加载到进程空间的段中,该项说明该节数据内容第一个字节在进程空间所处的虚拟地址

sh_offset

该节数据内容第一个字节基于该ELF文件的偏移量

sh_size

该节数据内容长度,单位字节

sh_link

与该节类型相关的另一个节的节头索引,比如对于类型为SHT_SYMTAB, SHT_DYNSYM的节,该项表示该节相关联的字符串表节的节头索引

sh_info

~

sh_addralign

若该节的内容为代码,则包含与对齐相关的信息

sh_entsize

某些节中包含固定大小的项目,如符号表。对于这类节,该成员给出每个表项的长度字节数

特殊节

  1. .init:执行初始化任务的可执行代码,需要在执行二进制文件中的任何其他代码之前运行(SHF_EXECINSTR类型),系统在将控制权转移到二进制文件的主入口点之前执行 .init 部分中的代码。
  2. .fini:与.init相反,它具有在主程序完成后必须运行的可执行代码。
  3. .text:是程序的main所在位置(SHT_PROGBITS类型),包含用户定义的代码。
  4. .bss:包含未初始化的数据(SHT_NOBITS类型)。它不占用磁盘空间而占用内存,因此所有数据通常在运行时初始化为零,flag是可写的。
  5. .data:程序初始化数据(SHT_PROGBITS类型),flag是可写的。
  6. .rodata:只读数据,例如代码使用的字符串和常量。
  7. .plt:过程链接表,用于动态链接的代码,有助于在 got(全局偏移表)的帮助下从动态库调用外部函数。
  8. .got.plt:存储外部函数解析地址的表。默认情况下可写。
  9. .rel.*:包含有关在链接或运行时如何修复或修改 ELF 对象或进程映像的各个部分的信息(SHT_REL类型)。
  10. .rela.*:包含有关如何在链接或运行时修复或修改 ELF 对象或进程映像的各个部分的信息(带加​​数)(类型SHT_RELA)。
  11. .dynamic:动态链接结构。包含结构表ElfN_Dyn,还包含指向动态链接器所需的其他重要信息的指针。
  12. .init_array:包含指向用作构造函数的函数的指针数组(初始化二进制文件时依次调用这些函数)。在gcc中,您可以通过__attribute__((constructor)将其标记为构造函数。默认情况下,中有一个.init_array用于执行frame_dummy的条目。
  13. .fini_array:包含指向用作析构函数的函数指针数组。
  14. .shstrtab:保存节名称的节,通过节头中的name的值进行偏移获取名称字符串。
  15. .symtab:包含静态符号的符号表
  16. .strtab:保存相关符号名称的节,通过sym结构中的name进行偏移获取名称字符串。
  17. .dynsym:与.symtab相同,但包含动态链接而非静态链接所需的符号。
  18. .dynstr:与.strtab相同,但包含动态链接而不是静态链接所需的字符串。
  19. .rel.dyn:全局变量重定位表。
  20. .rel.plt:函数重定位表。

程序头结构体- GElf_Phdr

typedef struct
{
  Elf64_Word p_type;                 /* Segment type */
  Elf64_Word p_flags;          /* Segment flags */
  Elf64_Off    p_offset;         /* Segment file offset */
  Elf64_Addr  p_vaddr;        /* Segment virtual address */
  Elf64_Addr  p_paddr;        /* Segment physical address */
  Elf64_Xword      p_filesz;          /* Segment size in file */
  Elf64_Xword      p_memsz;             /* Segment size in memory */
  Elf64_Xword      p_align;          /* Segment alignment */
} Elf64_Phdr;

成员

意义

p_type

该段的类型

p_flags

该段的内容是什么操作属性的,可读可写可执行等

p_offset

该段数据内容第一个字节基于该ELF文件的偏移量

p_vaddr

该段数据内容第一个字节在进程空间所处的虚拟地址

p_paddr

该段数据内容第一个字节在进程空间所处的物理地址,一般用不到

p_filesz

该段在磁盘中占用的大小,单位字节

p_memsz

该段在内存中占用的大小,单位字节,与上一点的区别在于有些段需要在内存中占用空间而不在磁盘中占用,比如.bss

符号描述结构体- GElf_Sym

typedef struct
{
  Elf64_Word st_name;        /* Symbol name (string tbl index) */
  unsigned char   st_info;           /* Symbol type and binding */
  unsigned char st_other;           /* Symbol visibility */
  Elf64_Section     st_shndx;       /* Section index */
  Elf64_Addr  st_value;        /* Symbol value */
  Elf64_Xword      st_size;           /* Symbol size */
} Elf64_Sym;

成员

意义

st_name

符号名称对应的偏移量,可通过与符号所属节st_shndx的节头中的sh_link成员指定的字符串节进行偏移得到名称字符串

st_info

指定符号的类型和绑定属性,分为BIND和TYPE两种信息组合得到

st_other

~

st_shndx

存放该符号描述所属的节的节头索引

st_value

与该符号相关联的值,存放的都是该符号数据内容的偏移或地址等信息,根据节类型不同情况不同

st_size

该符号数据的尺寸数据,根据符号类型不同情况不同

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

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

相关文章

【设计模式】JAVA Design Patterns——Data Transfer Object(数据传递对象模式)

🔍目的 次将具有多个属性的数据从客户端传递到服务器,以避免多次调用远程服务器 🔍解释 真实世界例子 我们需要从远程数据库中获取有关客户的信息。 我们不使用一次查询一个属性,而是使用DTO一次传送所有相关属性。 通俗描述 使用…

pytorch-16 复现经典网络:LeNet5与AlexNet

一、相关概念 对于(10,3,227,227)数据表示,10张3通道的图,图的大小(特征数)为227*227. 通道数:作为卷积的输入通道数和输出通道数。 特征数:特征图的大小 步长stride和填充padding&…

文章结尾,铺垫下一章带来的期待

你是否容易在阅读时打瞌睡? 是否有很多买回来的书,放在书架上一年甚至几年都未读完,积满了灰尘? 但是,对于小说和电视剧,你却完全停不下来。每集片尾的预告激发了你持续观看下一集的渴望,带来了无限的期待…… 当你撰写文章或编写工具书时,内容可能呈现出乏味的面貌…

二叉树习题精讲-单值二叉树

单值二叉树 965. 单值二叉树 - 力扣(LeetCode)https://leetcode.cn/problems/univalued-binary-tree/description/ 判断这里面的所有数值是不是一样 方案1:遍历 方案2:拆分子问题 /*** Definition for a binary tree node.* struc…

数据库自动化管理的六大等级

什么是数据库自动化管理? 数据库自动化管理是指通过使用工具和流程,在尽量减少人为干预的情况下,管理和执行与数据库相关的任务。主要目的当然是提高效率,减少人为错误,确保一致性,并解放 DBA 和开发者&am…

系统思考—决策

风险来自于你不知道你在做什么。——沃伦巴菲特 今天和一个合作伙伴的创始人交流,她提出了一个引人深思的问题:“策略性陪伴和战略复盘,什么原因不由客户自己来做?”这个问题让我深入思考了第三方策略性陪伴顾问的独特价值和重要…

《征服数据结构》块状链表

摘要: 1,块状链表的介绍 2,块状链表的代码实现(Java和C) 1,块状链表的介绍 前面我们讲过数组和链表,数组具有 O(1)的查询时间,O(N)的删除,O(N)的插入,而链表具…

java 对接农行支付相关业务(二)

文章目录 农行掌银集成第三方APP1:掌银支付对接快e通的流程1.1 在农行网站上注册我们的app信息([网址](https://openbank.abchina.com/Portal/index/index.html))1.2:java整合农行的jar包依赖1.3:把相关配置信息整合到项目中1.4:前端获取授权码信息1.5:后端根据授权码信…

Unity【入门】环境搭建、界面基础、工作原理

Unity环境搭建、界面基础、工作原理 Unity环境搭建 文章目录 Unity环境搭建1、Unity引擎概念1、什么是游戏引擎2、游戏引擎对于我们的意义3、如何学习游戏引擎 2、软件下载和安装3、新工程和工程文件夹 Unity界面基础1、Scene场景和Hierarchy层级窗口1、窗口布局2、Hierarchy层…

Spring Cloud Alibaba-06-Sleuth链路追踪

Lison <dreamlison163.com>, v1.0.0, 2024.4.03 Spring Cloud Alibaba-06-Sleuth链路追踪 文章目录 Spring Cloud Alibaba-06-Sleuth链路追踪为什么使用链路追踪常见链路追踪解决方案Sleuth概述概述Sleuth术语 Sleuth Zipkin 原理Sleuth原理简述Zipkin 原理简述 Sleut…

剪画小程序:自媒体创作的第一步:如何将视频中的文案提取出来?

自媒体创作第一步&#xff0c;文案提取无疑是至关重要的一环。 做自媒体之所以要进行文案提取&#xff0c;有以下重要原因&#xff1a; 首先&#xff0c;提高效率。通过文案提取&#xff0c;可以快速获取关键信息&#xff0c;避免在无关紧要的内容上浪费时间&#xff0c;从而…

OpenEuler安装

1.下载镜像文件 2.新建虚拟机 版本选替他linux5.x内核64位 内存选4G 磁盘大小选40GB 内存和磁盘大小不能按默认&#xff0c;不然会很卡甚至没反应 优先使用英语 安装目的地一开始会有警告标志&#xff0c;点进去点完成 输入密码时不能太短还要保证拥有至少三种字符类型 等待安…

【数据结构】AVL树——平衡二叉搜索树

个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 祝福语&#xff1a;愿你拥抱自由的风 目录 二叉搜索树 AVL树概述 平衡因子 旋转情况分类 左单旋 右单旋 左右双旋 右左双旋 AVL树节点设计 AVL树设计 详解单旋 左单旋 右单旋 详解双旋 左右双旋 平衡因子情况如…

基于微信小程序+ JAVA后端实现的【微信小程序跑腿平台】设计与实现 (内附设计LW + PPT+ 源码+ 演示视频 下载)

项目名称 项目名称&#xff1a; 《微信小程序跑腿平台的设计与实现》 项目技术栈 该项目采用了以下核心技术栈&#xff1a; 后端框架/库&#xff1a; Java, SSM框架数据库&#xff1a; MySQL前端技术&#xff1a; 微信小程序, HTML…&#xff08;其它相关技术&#xff09; …

.BFS.

BFS &#xff08;Breadth-First Search&#xff09;是一种用于遍历或搜索树&#xff08;tree&#xff09;或图&#xff08;graph&#xff09;的算法。 这个算法从根&#xff08;或某个任意节点&#xff09;开始&#xff0c;并探索最近的邻居节点&#xff0c; 然后再探索那些节点…

adb的常见操作和命令

最近学习adb的时候&#xff0c;整理了一些adb的使用场景&#xff0c;如&#xff1a;adb与设备交互&#xff0c;adb的安装、卸载&#xff0c;adb命令启动&#xff0c;通过命令清除缓存&#xff0c;文件传输和日志操作。 adb的两大作用&#xff1a;在app测试的时候可以提供监控日…

如何高效测试防火墙的NAT64与ALG应用协议转换能力

在本文开始介绍如何去验证防火墙&#xff08;DUT&#xff09;支持NAT64 ALG应用协议转换能力之前&#xff0c;我们先要简单了解2个比较重要的知识点&#xff0c;即&#xff0c;NAT64和ALG这两个家伙到底是什么&#xff1f; 网络世界中的“翻译官” - NAT64技术 简而言之&…

【Linux安全】iptables防火墙(二)

目录 一.iptables规则的保存 1.保存规则 2.还原规则 3.保存为默认规则 二.SNAT的策略及应用 1.SNAT策略的典型应用环境 2.SNAT策略的原理 2.1.未进行SNAT转换后的情况 2.2.进行SNAT转换后的情况 3.SNAT策略的应用 3.1.前提条件 3.2.实现方法 三.DNAT策略及应用 1…

学习笔记——数据通信基础——数据通信网络(网络工程师)

网络工程师 网络工程&#xff0c;就是围绕着网络进行的一系列的活动&#xff0c;包括∶网络规划、设计、实施、调试、排错等。网络工程设计的知识领域很宽广&#xff0c;其中路由和交换是计算机网络的基本。 网络工程师∶是在网络工程领域&#xff0c;掌握专业的网络技术&…

Go 使用 RabbitMQ---------------之一

RabbitMQ 是一种消息代理。消息代理的主要目的是接收、存储并转发消息。在复杂的系统设计和微服务架构中,RabbitMQ 经常被用作中间件来处理和转发系统之间的消息,以确保数据的一致性和可靠性。正是因为提供了可靠的消息机制、跟踪机制和灵活的消息路由,常常被用于排队算法、…