Skip to content

Instantly share code, notes, and snippets.

@sitano
Created October 5, 2021 15:19
Show Gist options
  • Save sitano/55a8fc47058de2774914d43d46b19346 to your computer and use it in GitHub Desktop.
Save sitano/55a8fc47058de2774914d43d46b19346 to your computer and use it in GitHub Desktop.
Scan allocable .dynsym symbol table from loaded elf image
// dl_iterate_phdr(scan_dynsym, NULL);
//
// better see the impl from musl: https://github.com/esmil/musl/blob/194f9cf93da8ae62491b7386edf481ea8565ae4e/src/ldso/dynlink.c#L1451
#define UINTS_PER_WORD (__WORDSIZE / (CHAR_BIT * sizeof (unsigned int)))
static ElfW(Word)
gnu_hashtab_symbol_count(const unsigned int *const table) {
const unsigned int *const bucket = table + 4 + table[2] * (unsigned int)(UINTS_PER_WORD);
unsigned int b = table[0];
unsigned int max = 0U;
while (b-->0U)
if (bucket[b] > max)
max = bucket[b];
return (ElfW(Word))max;
}
// Reference:
// https://stackoverflow.com/questions/15779185/list-all-the-functions-symbols-on-the-fly-in-c
//
/* Callback for dl_iterate_phdr.
* Is called by dl_iterate_phdr for every loaded shared lib until something
* else than 0 is returned by one call of this function.
*/
static int
scan_dynsym(struct dl_phdr_info* info) {
/* ElfW is a macro that creates proper typenames for the used system architecture
* (e.g. on a 32 bit system, ElfW(Dyn*) becomes "Elf32_Dyn*") */
ElfW(Dyn *) dyn;
ElfW(Sym *) sym;
ElfW(Word *) hash;
char *strtab = NULL;
char *sym_name = NULL;
ElfW(Word) sym_cnt = 0;
/* Iterate over all headers of the current shared lib
* (first call is for the executable itself) */
for (size_t header_index = 0; header_index < info->dlpi_phnum; header_index++) {
/* Further processing is only needed if the dynamic section is reached */
if (info->dlpi_phdr[header_index].p_type == PT_DYNAMIC) {
/* Get a pointer to the first entry of the dynamic section.
* It's address is the shared lib's address + the virtual address */
dyn = (ElfW(Dyn)*)(info->dlpi_addr + info->dlpi_phdr[header_index].p_vaddr);
while(dyn->d_tag != DT_NULL) {
switch(dyn->d_tag) {
case DT_HASH: {
hash = (ElfW(Word *))dyn->d_un.d_ptr;
sym_cnt = hash[1];
}
break;
case DT_GNU_HASH: {
hash = (ElfW(Word *))dyn->d_un.d_ptr;
sym_cnt = gnu_hashtab_symbol_count(hash);
}
break;
case DT_STRTAB: {
/* Get the pointer to the string table */
strtab = (char *)dyn->d_un.d_ptr;
}
break;
case DT_SYMTAB: {
/* Get the pointer to the first entry of the symbol table */
sym = (ElfW(Sym *))dyn->d_un.d_ptr;
/* Iterate over the symbol table */
for (ElfW(Word) sym_index = 0; sym_index < sym_cnt; sym_index++) {
/* get the name of the i-th symbol.
* This is located at the address of st_name
* relative to the beginning of the string table. */
sym_name = &strtab[sym[sym_index].st_name];
printf("%s %d %d |\n", sym_name, ELF64_ST_TYPE(sym[sym_index].st_info), sym[sym_index].st_other);
}
}
break;
default:
// printf(">> %d \n", dyn->d_tag);
// Unsupported dyn->d_tag?
break;
}
/* move pointer to the next entry */
dyn++;
}
} else {
printf(">> info->dlpi_phdr[%d].p_type=%d \n", header_index, info->dlpi_phdr[header_index].p_type);
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment