Search code examples
clinuxelf

How to access the address of a function I bring from a shared object in a debugger using ELF file, RELA and then finding it in GOT?


I have the name of an exe file and the function I'm looking for. Knowing it's a global function coming from a shared object. I searched for the section of RELA, and then by using sh_link I found the dynsym and dynstr. So by using the index of each RELA entry, I found the name of the symbol in dynstr, and then returned the offset of the RELA entry that had the same symbol name as the function I got.

Then in the debugger I used ptrace and peektext to find the data that the offset holds. However it doesn't seem to work. What am I missing? It does return me the offset, but can't give me the address from GOT. or sometimes it just doesn't find the symbol I'm looking for.

Also I should mention that the question is only using Lazy binding

Code:

unsigned long find_symbol_address(const char* symbol_name, const char* executable_path) {

 int elf_fd = open(executable_path, O_RDONLY);

void *elf = mmap(NULL, lseek(elf_fd, 0, SEEK_END), PROT_READ, MAP_PRIVATE, elf_fd, 0);
Elf64_Ehdr* elf_header = (Elf64_Ehdr*)elf;
Elf64_Shdr* section_h_arr = (Elf64_Shdr*)((char*)elf + elf_header->e_shoff);

Elf64_Shdr sh_str_section = section_h_arr[elf_header->e_shstrndx];

char *sh_str_tbl = (char*)elf + sh_str_section.sh_offset;
Elf64_Half sections_amount = elf_header->e_shnum;

int symbols_amount = 0;

Elf64_Half index_dyn;
Elf64_Half index_str;
Elf64_Rela  *rela;
Elf64_Sym  *dyn;
char *strtab;
char* curr_symbol_name; 
Elf64_Addr offset;



printf("func name %s\n",symbol_name);
for (int j = 0; j < elf_header->e_shnum; j++) {
printf("[%2d] %s\n", j, sh_str_tbl + section_h_arr[j].sh_name);
}

for(int i = 0; i < sections_amount; i++) {

    if(section_h_arr[i].sh_type==SHT_RELA){
    printf("rela is - [%2d] %s\n", i, sh_str_tbl + section_h_arr[i].sh_name);
    rela=(Elf64_Rela*)((char*)elf + section_h_arr[i].sh_offset);
    symbols_amount=section_h_arr[i].sh_size / section_h_arr[i].sh_entsize;
    dyn=(Elf64_Sym*)((char*)elf + section_h_arr[section_h_arr[i].sh_link].sh_offset);
    strtab = ((char*)elf + section_h_arr[section_h_arr[section_h_arr[i].sh_link].sh_link].sh_offset);
    
    for (int j=0;j<symbols_amount;j++)
    {
    
        index_dyn=ELF64_R_SYM(rela[j].r_info);
    
        index_str=ELF64_ST_BIND(dyn[index_dyn].st_info);
    
        curr_symbol_name= strtab + dyn[j].st_name;
    
        printf("current symbol - %s\n",curr_symbol_name);
            
        if (strcmp(curr_symbol_name,symbol_name)==0)
            {
                offset=rela[j].r_offset;
                return offset;
            }

            
        }
    }
    
    
}
return 0;
    
    
    
    

}



//after I get the offset, I used this to get the data from that address.
unc_addr=ptrace(PTRACE_PEEKTEXT, child_pid, offset, NULL);
func_addr=func_addr-6;

Solution

  • so it was something very minor.

    instead of : curr_symbol_name= strtab + dyn[j].st_name;

    I had to use curr_symbol_name= strtab + dyn[index_dyn].st_name;

    It still encounters some problems when a function is being called from a shared object as well, making the address I had to change over the time.