pyelftools,一个能解析ELF文件的Python库,嵌入式开发的分析利器

多精彩内容在公众号。

ELF(Executable and Linkable Format)文件格式是一种用于表示可执行文件、目标文件、共享库和核心转储的标准文件格式。它被广泛应用于Linux和许多类Unix操作系统中。ELF文件格式的设计允许程序和数据的高效存储,同时也支持程序的链接和加载。以下是ELF文件格式的详细介绍:

ELF文件的主要组成部分:

  1. ELF头 (ELF Header):

    • 位于文件的开始位置,主要用来定位文件的其他部分。

    • 包含文件的魔数(Magic Number)、文件类型、目标架构、入口点地址、节头表和程序头表的位置等信息。

  2. 节头表 (Section Header Table):

    • 描述文件中的各个节(sections)的信息,如节的名称、类型、属性、内存地址、文件偏移、大小等。

    • 节是ELF文件中存储数据的基本单位,例如代码、数据、符号表、重定位信息等。

  3. 程序头表 (Program Header Table):

    • 描述文件中的各个段(segments),这些段在程序加载到内存时会被映射到虚拟内存中。

    • 包含段的类型、属性、文件偏移、虚拟地址、物理地址、大小等信息。

ELF文件的结构细节:

  • ELF头:

    • 魔数:用于识别文件是否为ELF格式,以及文件的字节序(大端或小端)。

    • 文件类型:指示文件是可执行文件、共享对象还是核心转储等。

    • 目标架构:指明文件适用的CPU架构,如x86、ARM等。

    • 入口点地址:程序的执行入口点。

    • 节头表和程序头表的偏移量、大小和数量:用于在文件中定位这些表的具体位置。

  • 节头表:

    • 节名称:节的名称,通常是一个字符串。

    • 节类型:指示节的类型,如代码节、数据节等。

    • 属性:节的访问权限(读、写、执行)。

    • 内存地址和文件偏移:节在内存和文件中的起始位置。

    • 节大小:节的长度。

    • 链接信息:与其他节的链接关系。

    • 地址对齐:节的对齐要求。

    • 表项大小:如果节包含表项,其大小信息。

  • 程序头表:

    • 段类型:指示段的类型,如加载时需要映射到内存的段。

    • 属性:段的访问权限和是否需要加载到内存。

    • 文件偏移和虚拟地址:段在文件中的位置和加载到内存后的地址。

    • 物理地址:段在物理内存中的地址(通常与虚拟地址相同)。

    • 文件大小和内存大小:段在文件和内存中的大小。

    • 对齐:段的对齐要求。

首先来看一段c代码

​​​​​​​

#include <stdio.h>unsigned int test=2;void para_add(){    test+=1;    printf("test=%d\n",test);}
void main(){    int i=1;    printf("i=%d\n",i);    para_add();}

执行gcc -o test test.c后会生成ELF的目标文件test

执行file test可以看到test文件的属性

图片

用readelf -h test命令可以看到test文件的头信息

图片

如果用objdump -x test 可以看到test中section中的具体信息

现在我们用python的pyelftools库来解析这个文件。代码如下

​​​​​​​

from elftools.elf.elffile import ELFFilefrom elftools.elf.sections import SymbolTableSection
def parse_elf_file(elf_file_path):    # 打开ELF文件    print(elf_file_path)    with open(elf_file_path, 'rb') as f:        elffile = ELFFile(f)
        # 检查是否是ELF文件        if not elffile:            print('This is not a valid ELF file.')            return                # 获取ELF头部信息        header = elffile.header        # 打印ELF文件的头部信息        print('  Magic:', header.e_ident['EI_MAG'])        print('  Class:', '64-bit' if header.e_ident['EI_CLASS'] == 3 else '32-bit')        print('  Data:', '2\'s complement, little-endian' if header.e_ident['EI_DATA'] == 1 else 'not little-endian')        print('  Entry point address:', hex(header.e_entry))        print('  Section header offset:', hex(header.e_shoff))        print('  Section header size:', header.e_shentsize)        print('  Number of section headers:', header.e_shnum)        print('  version:',header.e_version)        print('  Section header string table index:', header.e_shstrndx)        
        # 遍历节(section)头        for section in elffile.iter_sections():            if isinstance(section, SymbolTableSection):                # 如果是符号表节,则打印符号信息                print('\nSymbol Table Section:', section.name)                for symbol in section.iter_symbols():                    # print(dir(symbol.entry),symbol.entry.st_info)                    pass                    print('  Symbol name:', symbol.entry.st_name)                    print('  Symbol binding:', 'global' if symbol.entry.st_info['bind'] == 0 else 'local')                    print('  Symbol type:', 'function' if symbol.entry.st_info['type'] == 2 else 'object')                    print('  Symbol section index:', symbol.entry.st_shndx)                    print('  Symbol value:', hex(symbol.entry.st_value))                    print('  Symbol size:', hex(symbol.entry.st_size))
# 替换为你的ELF文件路径elf_file_path = 'home/linux_network/test'parse_elf_file(elf_file_path)

执行结果如下。首先是header部分的解析。和前面命令的结果也能对上。然后是26个section的信息统计

图片

  • 25
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿与代码

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值