C语言实现读取elf文件的字符串表,符号表

任务: 读取符号表中的func,并将其函数名、函数首地址、函数大小(函数地址范围)保存起来。

两个c语言相关函数:
fread:

int fread(void *buffer,int size,int count,FILE *fp);

fread()──从fp所指向文件的当前位置开始,一次读入size个字节,重复count次,并将读入的数据存放到从buffer开始的内存中; buffer是存放读入数据的起始地址(即存放何处)。

fseek:

int fseek(FILE *stream, long offset, int fromwhere);

第一个参数file指针 第二个参数移动的偏移量 第三个参数移动到哪里 分别用3个宏

SEEK_SET 即0 文件开头
SEEK_CUR 即1 文件当前位置
SEEK_END 即2 文件结尾
fseek(fp,100L,SEEK_SET);把fp指针移动到离文件开头100字节处;
fseek(fp,100L,SEEK_CUR);把fp指针移动到离文件当前位置100字节处;
fseek(fp,100L,SEEK_END);把fp指针退回到离文件结尾100字节处。

#include <elf.h>

typedef struct {
    char name[64];
    paddr_t addr;      //the function head address
    Elf32_Xword size;
} Symbol;

Symbol *symbol = NULL;  //dynamic allocate memory  or direct allocate memory (Symbol symbol[NUM])

void parse_elf(const char *elf_file)
{
    
    if(elf_file == NULL) return;
    
    FILE *fp;
    fp = fopen(elf_file, "rb");
    
    if(fp == NULL)
    {
        printf("failed to open the elf file!\n");
        exit(0);
    }
	
    Elf32_Ehdr edhr;
	//读取elf头
    if(fread(&edhr, sizeof(Elf32_Ehdr), 1, fp) <= 0)
    {
        printf("fail to read the elf_head!\n");
        exit(0);
    }

    if(edhr.e_ident[0] != 0x7f || edhr.e_ident[1] != 'E' || 
       edhr.e_ident[2] != 'L' ||edhr.e_ident[3] != 'F')
    {
        printf("The opened file isn't a elf file!\n");
        exit(0);
    }
    
    fseek(fp, edhr.e_shoff, SEEK_SET);

    Elf32_Shdr shdr;
    char *string_table = NULL;
    //寻找字符串表
    for(int i = 0; i < edhr.e_shnum; i++)
    {
        if(fread(&shdr, sizeof(Elf32_Shdr), 1, fp) <= 0)
        {
            printf("fail to read the shdr\n");
            exit(0);
        }
        
        if(shdr.sh_type == SHT_STRTAB)
        {
            //获取字符串表
            string_table = malloc(shdr.sh_size);
            fseek(fp, shdr.sh_offset, SEEK_SET);
            if(fread(string_table, shdr.sh_size, 1, fp) <= 0)
            {
                printf("fail to read the strtab\n");
                exit(0);
            }
        }
    }
    
    //寻找符号表
    fseek(fp, edhr.e_shoff, SEEK_SET);
    
    for(int i = 0; i < edhr.e_shnum; i++)
    {
        if(fread(&shdr, sizeof(Elf32_Shdr), 1, fp) <= 0)
        {
            printf("fail to read the shdr\n");
            exit(0);
        }

        if(shdr.sh_type == SHT_SYMTAB)
        {
            fseek(fp, shdr.sh_offset, SEEK_SET);

            Elf32_Sym sym;

            size_t sym_count = shdr.sh_size / shdr.sh_entsize;
            symbol = malloc(sizeof(Symbol) * sym_count);

            for(size_t j = 0; j < sym_count; j++)
            {
                if(fread(&sym, sizeof(Elf32_Sym), 1, fp) <= 0)
                {
                    printf("fail to read the symtab\n");
                    exit(0);
                }

                if(ELF32_ST_TYPE(sym.st_info) == STT_FUNC)
                {
                    const char *name = string_table + sym.st_name;
                    strncpy(symbol[func_num].name, name, sizeof(symbol[func_num].name) - 1);
                    symbol[func_num].addr = sym.st_value;
                    symbol[func_num].size = sym.st_size;
                    func_num++;
                }
            }
        }
    }
    fclose(fp);
    free(string_table);
}

需要注意符号表中的st_name(符号名称),它其实不是一个字符串,而是一个数值,代表的是目标文件中字符串表(.strtab节)中的一个索引值, 那里才真正存储着该符号的名称对应的字符串,也正是这个原因,我们需要读取字符串表的首地址,并将其存入string_table变量中。

通过上述代码,也可以看出,在了解了elf文件的一些结构体后,解析elf文件就主要靠fread函数与fseek函数,fseek函数用于不断调整fp文件指针的位置,然后fread再读取对应的节头表、字符串表、符号表等,并将其保存在所定义的变量中,最后再通过此变量,获取到我们需要的数据。😀😀😀

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C语言中的ELF(Executable and Linkable Format)文件段头部是用来描述ELF文件的各个段的信息的数据结构。ELF文件是一种可执行文件和可链接文件的标准格式,用于在Linux和其他Unix系统上执行和链接程序。 ELF文件段头部位于ELF文件的头部,用于描述ELF文件的各个段(段是一组相关的数据或代码的有序集合),包括代码段、数据段、BSS段等等。每个段头部项都包含了段的一些重要信息,如起始地址、大小、访问权限等等。 段头部的作用是让操作系统或程序加载器能够正确地加载和执行ELF文件的各个段。通过读取段头部,系统可以确定每个段应该被放置在内存的哪个位置,并且可以根据段的访问权限进行适当的内存保护。此外,段头部还包含其他一些元数据,如字符串的偏移量、符号表的偏移量等,这些信息可以帮助调试器和其他工具分析和查找ELF文件的内容。 段头部是一个固定大小的数据结构,每个项的大小是固定的,并且项的数量也是固定的。ELF文件的第一个段头部项被保留用于描述ELF文件本身,其他项则用于描述ELF文件中的各个段。程序员可以使用c语言中的结构体来示段头部项,并通过读取ELF文件的头部来获取段头部的起始地址,从而遍历和分析整个段头部。 总之,C语言中的ELF文件段头部是用来描述ELF文件的各个段的信息的数据结构,它能够帮助操作系统或程序加载器正确地加载和执行ELF文件,并提供了一些用于分析和查找ELF文件内容的元数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值