2017-06-29 42 views
-1

我编写了一些代码来搜索共享库的ELF标头中的符号。如果我解析存储在我的磁盘上的共享对象文件,代码将起作用。在运行时读取加载共享对象的ELF标题

现在,我想使用此代码来解析加载的共享库的ELF头。作为一个例子,libdl库被映射到当前进程中:

b7735000-b7738000 r-xp 00000000 08:01 315560  /lib/i386-linux-gnu/libdl.so.2 
b7738000-b7739000 r--p 00002000 08:01 315560  /lib/i386-linux-gnu/libdl.so.2 
b7739000-b773a000 rw-p 00003000 08:01 315560  /lib/i386-linux-gnu/libdl.so.2 

地址的(第一个)映射包含ELF头。我试图读取此标题并提取.dynsym部分中的dlopen符号。但是,标题与磁盘上'plain'.so文件的标题略有不同。例如,.shstrtab版本的偏移量为0.因此,无法获取节的名称。

我想问为什么ELF标题在加载库期间发生变化,以及在哪里可以找到“缺失”部分。加载库之后甚至可以解析ELF头文件? 有没有人知道任何文章解释共享库/它的ELF头被映射到进程时的布局?

目前我使用以下函数遍历ELF头。如果libdl_start指向内存映射libdl.so.2文件,代码工作正常。但是,如果它指向由链接器映射的区域,则get_dynstr_section未找到dynstr部分。

int get_libdl_functions() 
{ 
    Elf32_Ehdr *ehdr = libdl_start; 
    Elf32_Shdr *shdr, *shdrs_start = (Elf32_Shdr *)(((char *)ehdr) + ehdr->e_shoff); 
    Elf32_Sym *symbol, *symbols_start; 
    char *strtab = get_dynstr_section(); 
    int sec_it = 0, sym_it = 0; 

    rt_info->dlopen = NULL; 
    rt_info->dlsym = NULL; 

    if(strtab == NULL) 
     return -1; 

    for(sec_it = 0; sec_it < ehdr->e_shnum; ++sec_it) { 
     // Iterate over all sections to find .dynsym 
     shdr = shdrs_start + sec_it; 
     if(shdr->sh_type == SHT_DYNSYM) 
     { 
      // Ok we found the right section 
      symbols_start = (Elf32_Sym *)(((char *)ehdr) + shdr->sh_offset); 
      for(sym_it = 0; sym_it < shdr->sh_size/sizeof(Elf32_Sym); ++sym_it) { 
       symbol = symbols_start + sym_it; 
       if(ELF32_ST_TYPE(symbol->st_info) != STT_FUNC) 
        continue; 

       if(strncmp(strtab + symbol->st_name, DL_OPEN_NAME, sizeof DL_OPEN_NAME) && !rt_info->dlopen) { 
        //printf("Offset of dlopen: 0x%x\n", symbol->st_value); 
        dlopen = ((char *)ehdr) + symbol->st_value; 
       } else if(strncmp(strtab + symbol->st_name, DL_SYM_NAME, sizeof DL_SYM_NAME) && !rt_info->dlsym) { 
        //printf("Offset of dlsym: 0x%x\n", symbol->st_value); 
        dlsym = ((char *)ehdr) + symbol->st_value; 
       } 

       if(dlopen != 0 && dlsym != 0) 
        return 0; 
      } 
     } 
    } 

    return -1; 
} 

void *get_dynstr_section() 
{ 
    Elf32_Ehdr *ehdr = libdl_start; 
    Elf32_Shdr *shdr, *shdrs_start = (Elf32_Shdr *)(((char *)ehdr) + ehdr->e_shoff); 
    char *strtab = ((char *)ehdr) + ((shdrs_start + ehdr->e_shstrndx))->sh_offset; 
    int sec_it = 0; 

    for(sec_it = 0; sec_it < ehdr->e_shnum; ++sec_it) { 
     // Iterate over all sections to find .dynstr section 
     shdr = shdrs_start + sec_it; 
     if(shdr->sh_type == SHT_STRTAB && strncmp(strtab + shdr->sh_name, DYNSTR_NAME, sizeof DYNSTR_NAME)) 
      return ((char *)ehdr) + shdr->sh_offset; 
    } 

    return NULL; 
} 

回答

1

为什么图书馆

负载时的ELF标题更改为不。你的问题是基于错误的假设,但由于你没有显示任何实际的代码,很难猜测你做错了什么。

更新:

在此代码:

*shdrs_start = (Elf32_Shdr *)(((char *)ehdr) + ehdr->e_shoff); 

你认为部分头被加载到内存中。但是在运行时段标题是不需要,并且如果它们最终加载到内存中,那只是偶然。

你需要从ehdr自己的e_shoff中自己将它们从磁盘读取到内存中(或mmap它们)。

+0

我添加了我用来将ELF标题迭代到原始问题的代码。 – PraMiD

+0

@PraMiD据我所知,你的问题是“'get_dynstr_section'找不到dynstr部分”。但是你没有显示它的代码。你如何期待任何人来帮助你?您应该尝试构建一个https://stackoverflow.com/help/mcve。 –

+0

问题中包含'get_dynstr_section'的代码。在'get_libdl_functions'之后# – PraMiD