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;
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.