/** * Display the symbol table */ int cmd_sym() { elfshsect_t *sct; elfsh_Sym *symtab; regex_t *tmp; int num; char logbuf[BUFSIZ]; int ret; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); symtab = elfsh_get_symtab(world.curjob->curfile, &num); if (symtab == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Can't retrieve symtab", -1); sct = elfsh_get_section_by_type(world.curjob->curfile, SHT_SYMTAB, 0, NULL, NULL, 0); snprintf(logbuf, BUFSIZ, " [SYMBOL TABLE]\n [Object %s]\n\n", world.curjob->curfile->name); revm_output(logbuf); FIRSTREGX(tmp); ret = ds(world.curjob->curfile, sct, num, tmp, elfsh_get_symbol_name); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, ret); }
/** * Return the used offset in .strtab or -1 if failed * @param file * @param s * @param name * @return */ int elfsh_set_symbol_name(elfshobj_t *file, elfsh_Sym *s, char *name) { elfshsect_t *sct; char *str; u_int len; u_int new_len; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Sanity checks */ if (file == NULL || s == NULL || name == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", -1); if (file->secthash[ELFSH_SECTION_SYMTAB] == NULL && elfsh_get_symtab(file, NULL) == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot retreive symbol table", -1); /* Also change the section name in .shstrtab if symbol is STT_SECTION */ if (elfsh_get_symbol_type(s) == STT_SECTION) { sct = elfsh_get_section_from_sym(file, s); if (sct != NULL && elfsh_set_section_name(file, sct, name) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get section from its symbol", -1); } /* Else use the symbol string table */ if (file->secthash[ELFSH_SECTION_STRTAB] == NULL || file->secthash[ELFSH_SECTION_STRTAB]->data == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "No STRTAB available", NULL); /* Change the name */ str = file->secthash[ELFSH_SECTION_STRTAB]->data; str += s->st_name; len = strlen(str); new_len = strlen(name); /* Do not allocate new place if possible */ if (len > new_len) strncpy(str, name, new_len + 1); /* Append the name to .strtab */ else s->st_name = elfsh_insert_in_strtab(file, name); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (s->st_name)); }
/** * sect name * sym name */ int cmd_remove() { elfshsect_t *symtab; char *name; int err; char logbuf[BUFSIZ]; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Checks (needed because the command takes variable amount of params) */ if (!world.curjob->curcmd->param[0] || !world.curjob->curcmd->param[1]) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid parameters", -1); /* Lookup object name */ name = revm_lookup_string(world.curjob->curcmd->param[1]); /* Remove a section */ if (!strcmp(world.curjob->curcmd->param[0], "sect")) err = elfsh_remove_section(world.curjob->curfile, name); /* Remove a symbol after looking up symbol value */ else if (!strcmp(world.curjob->curcmd->param[0], "sym")) { symtab = elfsh_get_symtab(world.curjob->curfile, NULL); if (!symtab) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot find symbol table", -1); symtab = world.curjob->curfile->secthash[ELFSH_SECTION_SYMTAB]; err = elfsh_remove_symbol(symtab, name); } /* Remove a segment */ else if (!strcmp(world.curjob->curcmd->param[0], "phdr")) err = elfsh_remove_phdr(world.curjob->curfile, atoi(name)); /* Error */ else PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unknown object type", -1); /* Report result */ if (!world.state.revm_quiet) { snprintf(logbuf, BUFSIZ - 1, " [*] Object removing %s.\n\n", (err < 0 ? "failed" : "succesfull")); revm_output(logbuf); } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * 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); }
/** * Get symtab entry by vaddr * @param file * @param vaddr * @param off * @param mode * @return */ elfsh_Sym *elfsh_get_symbol_by_value(elfshobj_t *file, eresi_Addr vaddr, int *off, int mode) { int num; elfsh_Sym *data; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); data = elfsh_get_symtab(file, &num); if (data == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot retreive SYMTAB", NULL); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (elfsh_get_sym_by_value(data, num, vaddr, off, mode))); }
/** * Return the symbol name giving its index in the symbol string table * No special case for SECTION symbol because the section names strings * have been duplicated in the symbol table. * @param file * @param s * @return */ char *elfsh_get_symbol_name(elfshobj_t *file, elfsh_Sym *s) { elfshsect_t *sect; void *data; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Sanity checks */ if (file == NULL || s == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL parameter", NULL); /* Load symtab if needed */ if (file->secthash[ELFSH_SECTION_SYMTAB] == NULL && elfsh_get_symtab(file, NULL) == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot retreive symbol table", NULL); /* Else use the symbol string table */ sect = file->secthash[ELFSH_SECTION_STRTAB]; if (!sect || !sect->data) { sect = elfsh_get_strtab(file, 0); if (!sect) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get STRTAB", NULL); data = sect->data; } else data = sect->data; /* A last check to avoid getting killed on corrupted symbol tables */ if (!data) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, "<unreadable>"); else if ((unsigned int) s->st_name > (unsigned int) file->secthash[ELFSH_SECTION_STRTAB]->shdr->sh_size) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, "<corrupted>"); /* Return name */ PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, ((char *) data + s->st_name)); }
/** * 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 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); }
int remap_cmd() { elfshobj_t *file; elfshsect_t *cur; u_int new_base; u_int real_base = 0xffffffff; int diff; int i; int cnt; u_int count_raw = 0; u_int count_pht = 0; u_int count_sht = 0; u_int count_ent = 0; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Sanity checks */ i = sscanf(world.curjob->curcmd->param[0], "0x%X", &new_base); if (new_base == 0 || i != 1) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid new base address", -1); file = world.curjob->curfile; if (elfsh_read_obj(file) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to read object file", -1); if (elfsh_get_symtab(file, NULL) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to read symbol table", -1); /* Calculate delta */ real_base = elfsh_get_object_baseaddr(file); if (real_base == 0xffffffff) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Base address not found", -1); if (new_base & 0xfff) { revm_output(" [*] Base address adapted to be congruent pagesize \n"); new_base &= 0xfffff000; } diff = new_base - real_base; printf(" [*] Delta is %08X \n", diff); /* Update entry point */ if (file->hdr->e_entry > real_base) { file->hdr->e_entry += diff; count_ent++; } /* For all sections of the current object */ for (cur = file->sectlist; cur != NULL; cur = cur->next) { cnt = elfsh_relocate_section(cur, diff); if (cnt < 0) { printf(" [*] MODREMAP : Section %s wont be relocated\n", cur->name); continue; } count_raw += cnt; } /* Fixup SHT */ count_sht += elfsh_reloc_sht(file, diff); /* Fixup PHT */ count_pht += elfsh_reloc_pht(file, diff); /* Print msg */ printf(" [*] Total number of modified references : %u \n" "\t PHT relocation : %u \n" "\t SHT relocation : %u \n" "\t ENT relocation : %u \n" "\t RAW relocation : %u \n", count_pht + count_sht + count_ent + count_raw, count_pht , count_sht , count_ent , count_raw); printf(" [*] Remapping at base %08X -OK-\n\n", new_base); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * @brief Copy the PLT of an ET_EXEC object for the ALTPLT technique. * and the GOT of an ET_EXEC object for the ALTGOT technique. * @param file Host file. * @param mod Always inject sections with size being a multiple of mod. * @return Success (0) or Error (-1). */ int elfsh_relink_plt(elfshobj_t *file, u_int mod) { elfshsect_t *got; elfshsect_t *plt; elfshsect_t *symtab; elfshsect_t *dynsym; elfshsect_t *prolog; elfshsect_t *extplt = NULL; elfshsect_t *altgot = NULL; /* shut the nice talkative */ elfshsect_t *enew = NULL; /* compiler also know as gcc */ elfsh_Shdr hdr; elfsh_Sym *sym; elfsh_Sym newsym; char buf[BUFSIZ]; u_int off; u_int entsz; int mode; eresi_Addr addr; char *prologdata; u_int sz; char *name; u_char ostype; eresi_Addr diff; u_int extplt_size; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Get PLT */ if (file->secthash[ELFSH_SECTION_ALTPLT] != NULL) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); plt = elfsh_get_plt(file, NULL); if (NULL == plt) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "PLT section not found", -1); entsz = elfsh_get_pltentsz(file); if (entsz < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Failed to get PLT entry size", -1); /* Get GOT (recent ld call it .got.plt) */ got = elfsh_get_gotsct(file); if (NULL == got) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "GOT section not found", -1); /* Get symtabs */ if (NULL == elfsh_get_dynsymtab(file, NULL)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "DYNSYM not found", -1); if (NULL == elfsh_get_symtab(file, NULL)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "SYMTAB not found", -1); /* Some fingerprint */ ostype = elfsh_get_ostype(file); if (ostype == ELFSH_OS_ERROR) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid OS target", -1); /* Insert alternative .plt */ dynsym = file->secthash[ELFSH_SECTION_DYNSYM]; symtab = file->secthash[ELFSH_SECTION_SYMTAB]; /* FreeBSD and BeoS is incompatible with pre-interp injection */ /* Solaris needs self-mutating code for ALTPLT technique */ /* %gp offsets on ALPHA/MIPS requires data injection */ ELFSH_SELECT_INJECTION(file,NULL,mode); /* Map .alt.plt.prolog on ALPHA, or .alt.got.prolog on MIPS */ if (FILE_IS_MIPS(file) || FILE_IS_ALPHA64(file)) { if (FILE_IS_MIPS(file)) { name = ELFSH_SECTION_NAME_ALTGOTPROLOG; sz = 28; } else { name = ELFSH_SECTION_NAME_ALTPLTPROLOG; sz = 48; } prolog = elfsh_create_section(name); hdr = elfsh_create_shdr(0, SHT_PROGBITS, SHF_EXECINSTR | SHF_ALLOC, 0, 0, sz, 0, 0, 0, 0); XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, sz, -1); if (elfsh_insert_mapped_section(file, prolog, hdr, prologdata, mode, mod) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.{plt,got}.prolog insertion failed", -1); enew = elfsh_get_section_by_name(file, name, NULL, NULL, NULL); if (enew == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.{plt,got}.prolog insertion failed", -1); file->secthash[ELFSH_SECTION_ALTPLTPROLOG] = enew; } /* Map .alt.plt (or .pad.got on MIPS) On MIPS we use .pad.got in order to align .alt.got on a 0x1000 bound boundary. On ALPHA and SPARC, .alt.plt will be relocated instead of .plt */ sz = plt->shdr->sh_size; if (FILE_IS_MIPS(file)) { addr = enew->shdr->sh_addr + enew->shdr->sh_size; if ((addr - (got->shdr->sh_addr)) % 1024) sz = 1024 - ((addr - (got->shdr->sh_addr)) % 1024); XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, sz, -1); memset(prologdata, 0x00, sz); name = ELFSH_SECTION_NAME_PADGOT; } else { XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, sz, -1); memcpy(prologdata, elfsh_readmem(plt), sz); name = ELFSH_SECTION_NAME_ALTPLT; } enew = elfsh_create_section(name); hdr = elfsh_create_shdr(0, SHT_PROGBITS, SHF_EXECINSTR | SHF_ALLOC, 0, 0, sz, 0, 0, 0, 0); if (elfsh_insert_mapped_section(file, enew, hdr, prologdata, mode, mod) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.plt|.pad.got insertion failed", -1); enew = elfsh_get_section_by_name(file, name, NULL, NULL, NULL); if (enew == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.plt|.pad.got insertion failed", -1); file->secthash[ELFSH_SECTION_ALTPLT] = enew; /* Map .alt.got (all architectures except SPARC) */ /* On IA32, remap GOT with a doubled size for non-present symbol resolving */ if (FILE_IS_MIPS(file) || FILE_IS_ALPHA64(file) || FILE_IS_IA32(file)) { sz = (FILE_IS_MIPS(file) ? got->shdr->sh_size : FILE_IS_IA32(file) ? got->shdr->sh_size * 4 : plt->shdr->sh_size / elfsh_get_pltentsz(file) * sizeof(eresi_Addr)); altgot = elfsh_create_section(ELFSH_SECTION_NAME_ALTGOT); hdr = elfsh_create_shdr(0, SHT_PROGBITS, SHF_ALLOC | SHF_WRITE, 0, 0, sz, 0, 0, 0, sizeof(eresi_Addr)); XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, sz, -1); memcpy(prologdata, elfsh_readmem(got), got->shdr->sh_size); if (elfsh_insert_mapped_section(file, altgot, hdr, prologdata, ELFSH_DATA_INJECTION, mod) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.got insertion failed", -1); altgot = elfsh_get_section_by_name(file, ELFSH_SECTION_NAME_ALTGOT, NULL, NULL, NULL); if (altgot == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".alt.got insertion failed", -1); file->secthash[ELFSH_SECTION_ALTGOT] = altgot; altgot->curend = got->shdr->sh_size; memset(elfsh_readmem(altgot) + got->shdr->sh_size, 0x00, got->shdr->sh_size); altgot->shdr->sh_entsize = sizeof(eresi_Addr); } /* Insert EXTPLT in order to be able to resolve non present symbols */ if (FILE_IS_IA32(file)) { extplt_size = plt->shdr->sh_size * 2; extplt = elfsh_create_section(ELFSH_SECTION_NAME_EXTPLT); hdr = elfsh_create_shdr(0, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0, 0, extplt_size, 0, 0, 0, 0); XALLOC(__FILE__, __FUNCTION__, __LINE__, prologdata, plt->shdr->sh_size, -1); memcpy(prologdata, elfsh_readmem(plt), plt->shdr->sh_size); if (elfsh_insert_mapped_section(file, extplt, hdr, prologdata, mode, mod) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".ext.plt insertion failed", -1); extplt = elfsh_get_section_by_name(file, ELFSH_SECTION_NAME_EXTPLT, NULL, NULL, NULL); if (extplt == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, ".ext.plt insertion failed", -1); file->secthash[ELFSH_SECTION_EXTPLT] = extplt; extplt->curend = elfsh_get_first_pltentsz(file); } /* Loop on .plt and inject 'old_symnam' symbols */ for (off = 0; off < plt->shdr->sh_size; off += entsz) { /* SPARC does not have ALTGOT */ if (FILE_IS_MIPS(file) || FILE_IS_ALPHA64(file) || FILE_IS_IA32(file)) diff = (uint32_t) altgot->shdr->sh_addr - got->shdr->sh_addr; else diff = 0; /* Special case for the first plt entry */ if (off == 0 && elfsh_altplt_firstent(enew, &off, symtab, file, extplt, plt, diff) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "ALTPLT on first entry failed", -1); else if (off == 0) continue; /* Get the existing symbol name for this plt entry ... */ sym = elfsh_get_sym_by_value(elfsh_readmem(dynsym), dynsym->shdr->sh_size / sizeof(elfsh_Sym), plt->shdr->sh_addr + off, NULL, ELFSH_EXACTSYM); /* New versions of ld do not fill the vaddr of dynamic symbols, do it ourself. Do not insert old symbol in emergency cases */ if (sym == NULL) { if ((sym = elfsh_restore_dynsym(file, plt, off, dynsym)) == NULL) continue; name = elfsh_get_dynsymbol_name(file, sym); /* __gmon_start__ should not be resolved if it was not already done by gcc */ if (name && !strcmp(name, "__gmon_start__")) sym->st_value = 0x0; } /* ... and we inject the 'old' occurence symbol pointing in .alt.plt (.plt on MIPS) */ if (!FILE_IS_MIPS(file)) addr = enew->shdr->sh_addr + off; else addr = plt->shdr->sh_addr + off; #if __BYTE_ORDER == __BIG_ENDIAN if (file->hdr->e_ident[EI_DATA] == ELFDATA2LSB) #elif __BYTE_ORDER == __LITTLE_ENDIAN if (file->hdr->e_ident[EI_DATA] == ELFDATA2MSB) #else #error Unexpected __BYTE_ORDER ! #endif addr = swaplong(addr); /* Injection */ name = elfsh_get_dynsymbol_name(file, sym); newsym = elfsh_create_symbol(addr, entsz, STT_FUNC, 0, 0, 0); snprintf(buf, BUFSIZ, "old_%s", name); if (elfsh_insert_symbol(symtab, &newsym, buf) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "old_* symbol injection failed", -1); #if __DEBUG_COPYPLT__ printf("[DEBUG_COPYPLT] Symbol at .plt + %u injected" " succesfully (%s) \n", off, buf); #endif /* On ALPHA, shift the relocation offset from .got to .alt.got to avoid hooks removing when calling back the original function. */ if (FILE_IS_ALPHA64(file) && elfsh_shift_alpha_relocs(file, name, altgot, off) < 0) continue; /* Reencode the PLT entry to use the alternative GOT */ /* This condition is for compatibility with other archs where EXTPLT is not yet supported. For those we do not enter the hook */ if (FILE_IS_IA32(file)) { diff = (eresi_Addr) altgot->shdr->sh_addr - got->shdr->sh_addr; elfsh_encodeplt(file, plt, diff, off); if (file->hdr->e_type == ET_DYN) elfsh_encodeplt(file, file->secthash[ELFSH_SECTION_ALTPLT], diff, off); diff = (eresi_Addr) altgot->shdr->sh_addr - got->shdr->sh_addr + got->shdr->sh_size; elfsh_encodeplt(file, extplt, diff, off); } } /* Activate ALTGOT */ if (elfsh_redirect_pltgot(file, altgot, got, plt, enew) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "PLTGOT redirection failed", -1); /* Activate EXTPLT */ if (elfsh_extplt_mirror_sections(file) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Section mirroring failed", -1); #if __DEBUG_COPYPLT__ printf("[DEBUG_COPYPLT] Section Mirrored Successfully ! \n"); #endif /* Everything is 0k4y */ if (elfsh_sync_sorted_symtab(symtab) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "symtab synchronisation failed", -1); if (elfsh_sync_sorted_symtab(dynsym) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "dynsym synchronisation failed", -1); elfsh_sync_sectnames(file); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Load all the part of the binary. * This function should not be used by e2dbg * @param file * @return */ int elfsh_read_obj(elfshobj_t *file) { elfshsect_t *actual; int index; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (file->read) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); if (file->sht == NULL && NULL == elfsh_get_sht(file, NULL)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to grab SHT", -1); if (NULL == elfsh_get_pht(file, NULL) && file->hdr->e_type != ET_REL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to grab PHT", -1); #if __DEBUG_MAP__ puts("[DEBUG:read_obj] Loading all known typed sections\n"); #endif /* Fill multiple relocation sections */ for (index = 0; NULL != (actual = elfsh_get_reloc(file, index, NULL)); index++); /* ** Load sections placed after symtab ** Added for Solaris */ elfsh_get_comments(file); elfsh_get_dwarf(file); elfsh_get_stab(file, NULL); if (file->hdr->e_type == ET_CORE) { elfsh_get_core_notes(file); goto out; } /* ** We cannot use simply elfsh_get_anonymous_section() here ** because the object's section hash ptrs would not be filled. */ elfsh_get_symtab(file, NULL); /* Fixup stuffs in the SHT */ elfsh_fixup(file); elfsh_get_dynsymtab(file, NULL); elfsh_get_stab(file, NULL); elfsh_get_dynamic(file, NULL); elfsh_get_ctors(file, NULL); elfsh_get_dtors(file, NULL); elfsh_get_got(file, NULL); elfsh_get_interp(file); elfsh_get_versymtab(file, NULL); elfsh_get_verneedtab(file, NULL); elfsh_get_verdeftab(file, NULL); elfsh_get_hashtable(file, NULL); //elfsh_get_comments(file); elfsh_get_plt(file, NULL); /* Fill the multiple notes sections */ for (index = 0; NULL != elfsh_get_notes(file, index); index++); /* Loop on the section header table and load all unknown-typed sections */ for (actual = file->sectlist; actual; actual = actual->next) { /* Fix first section size */ if (actual->shdr->sh_size == 0 && actual->next && actual->next->shdr->sh_offset != actual->shdr->sh_offset && actual->next->shdr->sh_addr != actual->shdr->sh_addr) actual->shdr->sh_size = actual->next->shdr->sh_offset - actual->shdr->sh_offset; /* If the section data has to be loaded, load it */ /* In case of bss, only load if BSS data is inserted in the file */ if (actual->data == NULL && actual->shdr->sh_size) { if ((actual->shdr->sh_type == SHT_NOBITS && actual->shdr->sh_offset == actual->next->shdr->sh_offset) || (actual->next != NULL && actual->next->shdr->sh_offset == actual->shdr->sh_offset)) continue; #if __DEBUG_MAP__ printf("[LIBELFSH] Loading anonymous section %15s \n", elfsh_get_section_name(file, actual)); #endif elfsh_get_anonymous_section(file, actual); } } /* Fixup various symbols like dynamic ones that are NULL */ /* Non fatal error */ if (file->secthash[ELFSH_SECTION_DYNSYM]) elfsh_fixup_dynsymtab(file->secthash[ELFSH_SECTION_DYNSYM]); out: /* We close the file descriptor after file mapping so we can open more files */ if (file->fd >= 0) { #if __DEBUG_MAP__ printf("[LIBELFSH] Closing descriptor %d \n", file->fd); #endif XCLOSE(file->fd, -1); /* neutralize file descriptor */ file->fd = -1; } 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); }