/** * Called from elfsh_fixup_symtab * When trying to inject part of the libc, some bss symbols have a wrong sctndx * @param symtab * @return */ elfshsect_t *elfsh_fixup_sctndx(elfshsect_t *symtab) { int index; elfsh_Sym *sym; elfsh_SAddr offset; elfsh_Shdr *shdr; elfshsect_t *sct; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); //return (symtab); // XXX sym = symtab->data; shdr = symtab->parent->sht + symtab->index; for (index = 0; index < shdr->sh_size / sizeof(elfsh_Sym); index++) { if (elfsh_get_symbol_link(sym + index) != SHN_COMMON) { if (elfsh_get_symbol_type(sym + index) == STT_SECTION) continue; sct = elfsh_get_parent_section(symtab->parent, elfsh_get_symbol_value(sym + index), &offset); if (sct == NULL) { sct = elfsh_get_section_by_index(symtab->parent, elfsh_get_symbol_link(sym + index), NULL, NULL); if (sct && elfsh_get_section_type(sct->shdr) == SHT_NOBITS) { #if __DEBUG_MAP__ printf(" [*] Symbol [%s] sctndx changed from %u to SHN_COMMON\n", elfsh_get_symbol_name(symtab->parent, sym + index), elfsh_get_symbol_link(sym + index)); #endif elfsh_set_symbol_link(sym + index, SHN_COMMON); continue; } } if (sct && elfsh_get_section_type(sct->shdr) == SHT_NOBITS) { elfsh_set_symbol_link(sym + index, SHN_COMMON); #if __DEBUG_MAP__ printf(" [*] Symbol [%s] sctndx changed to SHN_COMMON\n", elfsh_get_symbol_name(symtab->parent, sym + index)); #endif } } } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, symtab); }
/** * Retreive the file offset giving the virtual address * @param file * @param sym * @return */ int elfsh_get_symbol_foffset(elfshobj_t *file, elfsh_Sym *sym) { elfshsect_t *sect; char *name; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* If the symbol is a section, then look at the sht instead */ if (elfsh_get_symbol_type(sym) == STT_SECTION) { name = elfsh_get_symbol_name(file, sym); sect = elfsh_get_section_by_name(file, name, NULL, NULL, NULL); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (sect ? elfsh_get_section_foffset(sect->shdr) : 0)); } /* get our parent section and compute the file offset */ if (sym == NULL || file == NULL || NULL == sym->st_value) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); sect = elfsh_get_parent_section(file, sym->st_value, NULL); if (sect == NULL) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (sect->shdr->sh_offset + (sym->st_value - sect->shdr->sh_addr))); }
/** * Fill symtab and dynsym hash table for _get_*_by_name functions * @param file target file * @return */ int elfsh_init_symbol_hashtables(elfshobj_t *file) { elfsh_Sym *sym; int idx; int size; char *actual; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); // THIS FUNCTION IS DISABLED (TEST) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); if (file == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", -1); printf("Init symbol hash tables ! \n"); hash_init(&file->symhash, ELFSH_SYMHASH_NAME, 100, ASPECT_TYPE_INT); hash_init(&file->dynsymhash, ELFSH_DYNSYMHASH_NAME, 100, ASPECT_TYPE_INT); /* Symtab */ if (elfsh_get_symtab(file, &size)) { sym = (elfsh_Sym *) file->secthash[ELFSH_SECTION_SYMTAB]->data; for (idx = 0; idx < size; idx++) { actual = elfsh_get_symbol_name(file, sym + idx); if (actual) hash_add(&file->symhash, strdup(actual), (void *) idx); } } sym = (elfsh_Sym *) elfsh_get_dynsymtab(file, &size); /* Dynsym */ if (sym) { for (idx = 0; idx < size; idx++) { actual = elfsh_get_dynsymbol_name(file, sym + idx); if (actual) hash_add(&file->dynsymhash, strdup(actual), (void *) idx); } } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * The intermediate pass of theglobal algorithm for ET_REL injection * We fuze symbol tables from the ET_REL and the host binary * * @param file * @param rel * @return */ int elfsh_fuse_etrel_symtab(elfshobj_t *file, elfshobj_t *rel) { elfshsect_t *sect; elfsh_Sym newsym; elfsh_Half type; u_int index; char sctname[BUFSIZ]; elfsh_Sym *sym; int symnbr; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); sym = elfsh_get_symtab(rel, &symnbr); for (index = 0; index < symnbr; index++) { type = elfsh_get_symbol_type(sym + index); /* Avoid non-injectable symbols */ if (type != STT_FUNC && type != STT_OBJECT) continue; if (sym[index].st_shndx >= rel->hdr->e_shnum) continue; /* Find target section in ET_REL */ sect = elfsh_get_section_by_index(rel, sym[index].st_shndx, NULL, NULL); if (sect == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cant find extracted section in ET_REL\n", -1); /* Filter symbols using source section */ if (sect->shdr->sh_type != SHT_PROGBITS || !sect->shdr->sh_size || !elfsh_get_section_allocflag(sect->shdr)) continue; /* Find corresponding inserted section in ET_EXEC */ snprintf(sctname, sizeof(sctname), "%s%s", rel->name, sect->name); sect = elfsh_get_section_by_name(file, sctname, NULL, NULL, NULL); if (sect == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cant find inserted section in ET_EXEC\n", -1); #if __DEBUG_RELADD__ printf("[DEBUG_RELADD] Injected ET_REL symbol %-20s ["XFMT"] \n", elfsh_get_symbol_name(rel, sym + index), (eresi_Addr) (sect->shdr->sh_addr + sym[index].st_value)); #endif /* Add symbol in host file */ newsym = elfsh_create_symbol(sect->shdr->sh_addr + sym[index].st_value, sym[index].st_size, elfsh_get_symbol_type(sym + index), elfsh_get_symbol_bind(sym + index), 0, sect->index); if (elfsh_insert_symbol(file->secthash[ELFSH_SECTION_SYMTAB], &newsym, elfsh_get_symbol_name(rel, sym + index)) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to insert ET_REL symbol", -1); } /* Resynchronize sorted instances of symbol table */ if (elfsh_sync_sorted_symtab(file->secthash[ELFSH_SECTION_SYMTAB]) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to synchronize host symtab", -1); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Match functions from an addrtable * @param func_list function list pointer * @param count position on the list */ int trace_match_addrtable(elfshobj_t *curfile, char ***func_list, u_int *count) { eresi_Addr *alist = NULL; u_int index; char **f_list; u_int cnum; char tmpstr[256]; elfsh_Sym *sym; char *toadd; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (!func_list || !count) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid parameters", -1); f_list = *func_list; cnum = *count; /* Retrieve all called address in this binary */ if (elfsh_addr_get_func_list(curfile, &alist) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Can't get call function list", -1); for (index = 0; alist[index]; index++) { sym = elfsh_get_symbol_by_value(curfile, alist[index], 0, ELFSH_EXACTSYM); /* Find a symbol for this address */ if (sym) { toadd = elfsh_get_symbol_name(curfile, sym); } else { snprintf(tmpstr, 255, TRACE_PRE_FUNC "" AFMT, alist[index]); toadd = tmpstr; } /* Do we need to realloc ? */ if (((cnum+1) % TRACE_MATCH_ALLOCSTEP) == 0) { XREALLOC(__FILE__, __FUNCTION__, __LINE__, f_list, f_list, sizeof(char*) * (cnum + 1 + TRACE_MATCH_ALLOCSTEP), -1); /* Blank new elements */ memset(&f_list[cnum], 0x00, TRACE_MATCH_ALLOCSTEP*sizeof(char*)); /* Update the pointer, data can move during a reallocation */ *func_list = f_list; } /* If its temp string, strdup it */ if (toadd == tmpstr) toadd = strdup(tmpstr); f_list[cnum] = toadd; *count = ++cnum; } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Match a list of function from symbol tables * @param funcreg Function regex (or not ?) * @param func_list the final function list */ int trace_match_funcname(elfshobj_t *curfile, char *funcname, char ***func_list) { regex_t preg; char **f_list; u_int count = 0; elfshsect_t *sect; int num; elfsh_Sym *symtab; elfsh_Sym *sym; char funcreg[256]; char addrname[256]; size_t len; eresi_Addr addr; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (!funcname || !func_list) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid parameters", -1); len = strlen(funcname); /* We don't want to strip some part of the submited function but if you find a function/regex of this size (for this purpose) ... */ if (len > 255) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Function name is too long", -1); /* An address ? */ if (IS_VADDR(funcname)) { /* Retrieve the address */ sscanf(funcname + 2, AFMT, &addr); /* Prealloc the list */ XALLOC(__FILE__, __FUNCTION__, __LINE__, f_list, sizeof(char*)*2, -1); sym = elfsh_get_symbol_by_value(curfile, addr, 0, ELFSH_EXACTSYM); /* We have a symbol for this address */ if (sym) { f_list[0] = elfsh_get_symbol_name(curfile, sym); f_list[1] = NULL; } else { sym = elfsh_get_dynsymbol_by_value(curfile, addr, 0, ELFSH_EXACTSYM); /* We have a dynamic symbol for this address */ if (sym) { f_list[0] = elfsh_get_dynsymbol_name(curfile, sym); f_list[1] = NULL; } else { TRACE_GET_FUNC_NAME(addrname, 255, funcname); f_list[0] = strdup(addrname); f_list[1] = NULL; } } goto end; } /* Add ^ and $ if needed, else we will check too many things For example, someone wanna add "main" function, if we don't add those symbols, it will match __libc_start_main which is very special function and that can create problems and make the tracer useless */ snprintf(funcreg, 255, "%s%s%s", funcname[0] != '^' ? "^" : "", funcname, funcname[len-1] != '$' ? "$" : ""); /* Do we have a regex ? */ if (regcomp(&preg, funcreg, 0) != 0) { XALLOC(__FILE__, __FUNCTION__, __LINE__, f_list, sizeof(char*)*2, -1); f_list[0] = funcname; f_list[1] = NULL; goto end; } /* Preallocation */ XALLOC(__FILE__, __FUNCTION__, __LINE__, f_list, sizeof(char*) * TRACE_MATCH_ALLOCSTEP, -1); /* Total match case */ if (TRACE_MATCH_ALL(funcname)) { /* Match everything we can, symbol or not ! */ trace_match_addrtable(curfile, &f_list, &count); } /** * Match on symbol table */ symtab = elfsh_get_symtab(curfile, &num); if (symtab != NULL) { sect = elfsh_get_section_by_type(curfile, SHT_SYMTAB, 0, NULL, NULL, 0); /* Match function regex in the symbol table */ trace_match_symtab(sect, num, &preg, &f_list, &count, elfsh_get_symbol_name); } /** * Match on dynamic symbol table */ symtab = elfsh_get_dynsymtab(curfile, &num); if (symtab != NULL) { sect = elfsh_get_section_by_name(curfile, ELFSH_SECTION_NAME_ALTDYNSYM, NULL, NULL, &num); if (!sect) sect = elfsh_get_section_by_type(curfile, SHT_DYNSYM, 0, NULL, NULL, &num); num /= sizeof(elfsh_Sym); /* Match function regex in the dynamic symbol table */ trace_match_symtab(sect, num, &preg, &f_list, &count, elfsh_get_dynsymbol_name); } /* Do we get something ? */ if (count == 0) { XFREE(__FILE__, __FUNCTION__, __LINE__, f_list); PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Can't match a single function", -1); } end: /* Set final pointer */ *func_list = f_list; PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Return the symbol entry giving its name * @param file target file * @param name symbol name * @return symbol pointer or NULL */ elfsh_Sym *elfsh_get_symbol_by_name(elfshobj_t *file, char *name) { elfsh_Sym *sym; int idx; int size; char *actual; elfshsect_t *sect; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Check arguments */ if (file == NULL || name == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", NULL); /* Setup symtab pointers */ if (elfsh_get_symtab(file, &size) == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get SYMTAB", NULL); sect = file->secthash[ELFSH_SECTION_SYMTAB]; /* Invalid section pointer */ if (sect == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get SYMTAB (invalid section pointer)", NULL); sym = (elfsh_Sym *) sect->data; /* Invalid section data */ if (sym == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get SYMTAB data", NULL); /* if (file->symhash.ent) { //idx is the symbol number in the section idx = (int) hash_get(&file->symhash, name); #if __DEBUG_HASH_BY_NAME__ printf("[DEBUG_HASH_BY_NAME] SYM HASH Search by name for %s => %d\n", name, idx); #else //Check if idx is in the section if (idx <= 0 || idx >= sect->shdr->sh_size) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Symbol not found", NULL); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (sym + idx)); #endif } */ for (idx = 0; idx < size; idx++) { actual = elfsh_get_symbol_name(file, sym + idx); if (actual && !strcmp(actual, name)) { #if __DEBUG_HASH_BY_NAME__ printf("[DEBUG_HASH_BY_NAME] SYM ITERATE Search by name for %s => %d\n", name, idx); #endif PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (sym + idx)); } } #if __DEBUG_HASH_BY_NAME__ printf("[DEBUG_HASH_BY_NAME] SYM ITERATE Search by name for %s => NOT FOUND\n", name); #endif PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Symbol not found", NULL); }
/** * Return the dynamic symbol name giving its value, * Fill 'offset' with the difference between sym->st_value and 'value' * @param file * @param value * @param offset * @return */ char *elfsh_reverse_symbol(elfshobj_t *file, eresi_Addr value, elfsh_SAddr *offset) { elfshsect_t *sect; elfsh_Sym *sorted; int num; int index; char *str; int best; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Sanity checks */ if (!value || value == 0xFFFFFFFF) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid parameter", NULL); if (file == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", NULL); /* handle dynamic case */ if (elfsh_is_runtime_mode()) value -= file->rhdr.base; /* If there is no symtab, resolve using SHT */ if (elfsh_get_symtab(file, &num) == NULL) { sect = elfsh_get_parent_section(file, value, offset); if (sect == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "No parent section", NULL); *offset = (elfsh_SAddr) (sect->shdr->sh_addr - value); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (elfsh_get_section_name(file, sect))); } /* Else use the sorted-by-address symbol table to match what we want */ if (file->secthash[ELFSH_SECTION_SYMTAB]->altdata == NULL) elfsh_sync_sorted_symtab(file->secthash[ELFSH_SECTION_SYMTAB]); sorted = file->secthash[ELFSH_SECTION_SYMTAB]->altdata; /* Now find the best symbol -- type is more important than offset */ for (str = NULL, best = index = 0; index < num; index++) if (sorted[index].st_value <= value && DUMPABLE(sorted + index)) { if (best && !BESTYPE(sorted + index, sorted + best)) continue; *offset = (elfsh_SAddr) (value - sorted[index].st_value); best = index; str = elfsh_get_symbol_name(file, sorted + index); if (!*str) str = NULL; } if (str) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, str); PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "No valid symbol interval", NULL); }