/** * @brief Get the buffered address from the real virtual address */ void *elfsh_get_raw_by_addr(elfshobj_t *current, eresi_Addr addr, void *buf, u_int size) { elfshsect_t *sect; elfsh_SAddr offset; /* This happens when the object is a ERESI variable or when we request an address in runtime that is not part of any section */ sect = elfsh_get_parent_section(current, (eresi_Addr) addr, &offset); if (!sect) return ((void *) addr); /* In debug mode, we return a pointer on the runtime data */ if (elfsh_is_runtime_mode()) { if (!elfsh_section_is_runtime(sect)) return ((void *) sect->parent->rhdr.base + sect->shdr->sh_addr + offset); else if (!sect->shdr->sh_addr) return ((void *) sect->data + offset); else return ((void *) sect->shdr->sh_addr + offset); } /* Else we return a pointer on the cache data, doing a copy if requested */ else { if (buf && size) memcpy(buf, (char *) sect->data + offset, size); return ((void *) sect->data + offset); } }
/** * @brief Nice embedded debugging trick : return a pointer on the section data. * @brief This function makes the difference between static data and runtime data. * @param sect Section to return the data buffer from. */ void *elfsh_get_raw(elfshsect_t *sect) { void *dataptr = 0; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (elfsh_is_runtime_mode()) { /* The address of the section */ dataptr = (void *) sect->shdr->sh_addr; /* For runtime injected sections, do not add the base address of the object */ if (!elfsh_section_is_runtime(sect)) dataptr += sect->parent->rhdr.base; /* For unmapped sections */ if (!dataptr) dataptr = sect->data; PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, dataptr); } if (sect) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (sect->data)); PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid parameter", NULL); }
/* Debugger stack display with symbols */ int cmd_dbgstack() { char *param; eresi_Addr size; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Preliminary checks */ if (!elfsh_is_runtime_mode()) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Command only available in e2dbg", (-1)); param = world.curjob->curcmd->param[0]; if (!param) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid argument", (-1)); param = revm_lookup_string(param); /* Dump debugger stack */ if (revm_isnbr(param)) { if (sscanf(param, UFMT, &size) != 1) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid argument", (-1)); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, e2dbg_stack_dump(size, (eresi_Addr) ¶m)); } PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid parameter", -1); }
/** * @brief Restore original rights * @param addr * @param sz * @param prot * @return */ int elfsh_mprotect_userland(elfshobj_t *file, eresi_Addr addr, uint32_t sz, int prot) { int retval; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (!elfsh_is_runtime_mode()) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); retval = mprotect((void *) (long) addr - (long) addr % getpagesize(), getpagesize(), prot); if (retval != 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Failed munprotect", -1); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, retval); }
/* Do the switch */ int revm_doswitch(int nbr) { elfshobj_t *actual; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); actual = (nbr ? revm_getfile(nbr) : hash_get(&file_hash, world.curjob->curcmd->param[0])); if (actual == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unknown requested object", (-1)); world.curjob->curfile = actual; /* Switch to static mode if current file is not mapped */ if (elfsh_is_runtime_mode() && !actual->linkmap) elfsh_set_static_mode(); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * @brief Put write capability on the zone * @param file * @param addr * @param sz * @return */ int elfsh_munprotect_userland(elfshobj_t *file, eresi_Addr addr, uint32_t sz) { elfshsect_t *sect; elfsh_Phdr *phdr; int retval; int prot; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (!elfsh_is_runtime_mode()) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); sect = elfsh_get_parent_section(file, addr, NULL); if (!sect) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot find parent section", -1); phdr = elfsh_get_parent_segment(file, sect); prot = 0; if (elfsh_segment_is_readable(phdr)) prot |= PROT_READ; if (elfsh_segment_is_writable(phdr)) prot |= PROT_WRITE; if (elfsh_segment_is_executable(phdr)) prot |= PROT_EXEC; retval = mprotect((void *) (addr - addr % getpagesize()), getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC); if (retval != 0) { perror("munprotect"); PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Failed mprotect", -1); } /* Return the original rights */ PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, prot); }
/** * Perform a raw write on the object cache data * @param file * @param foffset * @param src_buff * @param len * @return */ int elfsh_raw_write(elfshobj_t *file, u_int foffset, void *src_buff, int len) { elfshsect_t *sect; int sect_off; void *dst; int prot; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); sect = elfsh_get_parent_section_by_foffset(file, foffset, NULL); if (sect == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid virtual address", -1); sect_off = foffset - sect->shdr->sh_offset; if (sect_off + len > sect->shdr->sh_size) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Section too short", -1); dst = elfsh_get_anonymous_section(file, sect); if (dst == NULL) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); if (elfsh_is_runtime_mode()) { prot = elfsh_munprotect(file, (eresi_Addr) dst + sect_off, len); memcpy(dst + sect_off, src_buff, len); elfsh_mprotect(file, (eresi_Addr) dst + sect_off, len, prot); } else memcpy(dst + sect_off, src_buff, len); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (len)); }
/* Stack display with symbols */ int cmd_stack() { char *param; eresi_Addr size; revmobj_t *ssp; revmexpr_t *expr; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* Preliminary checks */ if (!elfsh_is_runtime_mode()) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Command only available in e2dbg", (-1)); param = world.curjob->curcmd->param[0]; if (!param) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid argument", (-1)); param = revm_lookup_string(param); expr = revm_expr_get(E2DBG_SSP_VAR); if (!expr || !expr->value) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "No saved SP", -1); ssp = expr->value; /* Dump debuggee stack */ if (revm_isnbr(param)) { if (sscanf(param, UFMT, &size) != 1) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid argument", (-1)); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, e2dbg_stack_dump(size, ssp->immed_val.ent)); } PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid parameter", -1); }
/** * Get function addr list from call search basic * @param file target file * @param addr address list */ int elfsh_addr_get_func_list(elfshobj_t *file, eresi_Addr **addr) { int ret; int index; asm_instr instr; elfsh_SAddr foffset; elfsh_Word len; char *base; asm_processor proc; eresi_Addr base_vaddr, caddr; u_char found = 0; elfshsect_t *text; eresi_Addr *vaddr; const int astep = 20; u_int apos = 0; btree_t *broot = NULL; u_int diff; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (!file || !addr) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid parameters", -1); /* Search entrypoint section, our address must be in this section */ text = elfsh_get_parent_section(file, elfsh_get_entrypoint(file->hdr), &foffset); if (!text) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot find parent section from entry point", -1); if (!elfsh_get_anonymous_section(file, text)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get an anonymous section", -1); base = elfsh_readmem(text); len = text->shdr->sh_size; /* Get the virtual address */ base_vaddr = (elfsh_is_runtime_mode() && !elfsh_section_is_runtime(text) ? file->rhdr.base + elfsh_get_section_addr(text->shdr) : elfsh_get_section_addr(text->shdr)); /* Setup asm_processor structure */ if (etrace_setup_proc(file, &proc) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Failed during proc structure setup", -1); XALLOC(__FILE__, __FUNCTION__, __LINE__, vaddr, sizeof(eresi_Addr)*astep, -1); /* Despite the fact that we choose the right architecture to init asm, Our approach is totally architecture independant as we search using global type ASM_TYPE_CALLPROC and we know that op[0].imm will contain a relative value. */ for (index = 0; index < len; index += ret) { /* Read an instruction */ if ((ret = asm_read_instr(&instr, (u_char *) (base + index), len - index, &proc))) { /* Global assembler filter */ if ((instr.type & ASM_TYPE_CALLPROC) && instr.op[0].imm != 0) { caddr = base_vaddr + index + instr.op[0].imm + instr.len; /* Found a call check its local */ if (INTERVAL(base_vaddr, caddr, base_vaddr + len)) { found = 1; diff = (u_int) caddr; /* Avoid double entrie */ if (btree_get_elem(broot, diff) != NULL) goto next; btree_insert(&broot, diff, (void *)0x1); /* Next will be the last of the current list then realloc */ if ((apos+1) % astep == 0) { XREALLOC(__FILE__, __FUNCTION__, __LINE__, vaddr, vaddr, sizeof(eresi_Addr)*(apos+1+astep), -1); /* Blank new elements */ memset(&vaddr[apos], 0x00, astep*sizeof(eresi_Addr)); } vaddr[apos++] = caddr; } } } next: if (ret <= 0) ret = 1; } /* If nothing found we free allocated buffer and return an error */ if (!found) { XFREE(__FILE__, __FUNCTION__, __LINE__, vaddr); PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "No call internal found", -3); } btree_free(broot, 0); *addr = vaddr; PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * Search a call for a given address * @param file target file * @param addr supose to be a function */ int elfsh_addr_is_called(elfshobj_t *file, eresi_Addr addr) { int ret; int index; asm_instr instr; elfsh_SAddr foffset; elfsh_Word len; char *base; asm_processor proc; eresi_Addr base_vaddr; u_char found = 0; elfshsect_t *text; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (!file) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid parameter", -1); /* Search entrypoint section, our address must be in this section */ text = elfsh_get_parent_section(file, elfsh_get_entrypoint(file->hdr), &foffset); if (!text) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot find parent section from entry point", -1); if (!elfsh_get_anonymous_section(file, text)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to get an anonymous section", -1); base = elfsh_readmem(text); len = text->shdr->sh_size; /* Get the virtual address */ base_vaddr = (elfsh_is_runtime_mode() && !elfsh_section_is_runtime(text) ? file->rhdr.base + elfsh_get_section_addr(text->shdr) : elfsh_get_section_addr(text->shdr)); /* Our address is valid ? */ if (!INTERVAL(base_vaddr, addr, (base_vaddr + len))) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Not in entrypoint section", -4); /* Setup asm_processor structure */ if (etrace_setup_proc(file, &proc) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Failed during proc structure setup", -1); /* Despite the fact that we choose the right architecture to init asm, Our approach is totally architecture independant as we search using global type ASM_TYPE_CALLPROC and we know that op[0].imm will contain a relative value. */ for (index = 0; index < len; index += ret) { /* Read an instruction */ if ((ret = asm_read_instr(&instr, (u_char *) (base + index), len - index, &proc))) { /* Global assembler filter */ if ((instr.type & ASM_TYPE_CALLPROC) && instr.op[0].imm != 0) { /* Found the correct call */ if (base_vaddr + index + instr.op[0].imm + instr.len == addr) { found = 1; break; } } } if (ret <= 0) ret = 1; } if (!found) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "No call found", -3); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/* Redirect a function on a OS independant manner */ int cmd_hijack() { elfsh_Sym *dst; eresi_Addr addr; int err; char *rev; char logbuf[BUFSIZ]; elfshredir_t *redir; listent_t *actual; int idx; int idx2; int printed; eresi_Addr hookedaddr; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* If no parameter is given, print the redirection list */ if (!world.curjob->curcmd->param[0]) { printed = 0; /* Simple printing */ for (idx2 = idx = 0; idx < world.curjob->curfile->redir_hash.size; idx++) for (actual = world.curjob->curfile->redir_hash.ent + idx; actual != NULL && actual->key != NULL; actual = actual->next) { redir = (elfshredir_t *) actual->data; if (!printed) { revm_output("\t .::. ELFsh redirection list \n\n"); printed = 1; } snprintf(logbuf, BUFSIZ, "\t [%02u] TYPE:%-6s [" AFMT "] <%s> redirected on [" AFMT "] <%s> \n", idx2, (redir->type == ELFSH_REDIR_CFLOW ? "CFLOW" : redir->type == ELFSH_REDIR_ALTPLT ? "ALTPLT" : redir->type == ELFSH_REDIR_ALTGOT ? "ALTGOT" : "UNK"), redir->addr[0], redir->name[0], redir->addr[1], redir->name[1]); revm_output(logbuf); idx2++; } /* End message */ if (!printed) revm_output("\t .::. No redirection performed on current file \n\n"); else revm_output("\n\n"); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); } /* Some sanity checks first */ if (!world.curjob->curcmd->param[1]) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Redirection destination needed", (-1)); /* Resolve destination parameter */ dst = elfsh_get_metasym_by_name(world.curjob->curfile, world.curjob->curcmd->param[1]); if (!dst && elfsh_is_runtime_mode()) { elfsh_toggle_mode(); dst = elfsh_get_metasym_by_name(world.curjob->curfile, world.curjob->curcmd->param[1]); elfsh_toggle_mode(); } /* If not found */ if (dst == NULL) { err = sscanf(world.curjob->curcmd->param[1], XFMT, (eresi_Addr *) &addr); /* If the hook function is not supplied as an address */ if (err != 1 && elfsh_dynamic_file(world.curjob->curfile)) { elfsh_setup_hooks(); /* First bootstrap ALTPLT if not done */ err = elfsh_copy_plt(world.curjob->curfile, elfsh_get_pagesize(world.curjob->curfile)); if (err < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Failed at copying PLT", (-1)); /* Request a PLT entry since we have no symbol yet */ dst = elfsh_request_pltent(world.curjob->curfile, world.curjob->curcmd->param[1]); if (dst) addr = dst->st_value; else PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "PLT entry request failed", (-1)); } /* Insert a symbol on the requested address to avoid this */ else PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Need a symbol to redirect", -1); rev = revm_reverse(world.curjob->curfile, addr); } /* The first resolution worked, we take the address */ else { addr = dst->st_value; rev = NULL; } #if __DEBUG_HIJACK__ printf("[cmd_hijack] Resolved %s as %08X \n", world.curjob->curcmd->param[1], addr); #endif /* Hijack function */ err = elfsh_hijack_function_by_name(world.curjob->curfile, ELFSH_HIJACK_TYPE_FLOW, world.curjob->curcmd->param[0], addr, &hookedaddr); /* Last checks */ if (err < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Function redirection failed", (-1)); /* Add it to redirection hash table */ redir = revm_create_REDIR((u_char) err, world.curjob->curcmd->param[0], world.curjob->curcmd->param[1], hookedaddr, addr); hash_add(&world.curjob->curfile->redir_hash, world.curjob->curcmd->param[0], (void *) redir); /* Print final information */ if (!world.state.revm_quiet) { snprintf(logbuf, BUFSIZ - 1, "\n [*] Function %s redirected to addr " XFMT " <%s> \n\n", world.curjob->curcmd->param[0], (eresi_Addr) addr, (rev == NULL ? world.curjob->curcmd->param[1] : rev)); revm_output(logbuf); } if (rev != NULL) XFREE(__FILE__, __FUNCTION__, __LINE__,rev); /* Everything is ok */ PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * List all the loaded objects */ int cmd_dolist() { elfshobj_t *actual; int index; char *time; char *nl; char c; char c2; char logbuf[BUFSIZ]; char optbuf[BUFSIZ]; char **keys; int keynbr; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); index = 1; /* Private descriptors */ if (hash_size(&world.curjob->loaded)) { revm_output(" .::. Static Working files .::. \n"); keys = hash_get_keys(&world.curjob->loaded, &keynbr); for (index = 0; index < keynbr; index++) { actual = hash_get(&world.curjob->loaded, keys[index]); time = ctime(&actual->loadtime); nl = strchr(time, '\n'); if (nl) *nl = 0x00; c = (world.curjob->curfile == actual ? '*' : ' '); c2 = ((actual->linkmap || actual->rhdr.base) ? 'M' : ' '); if (elfsh_is_runtime_mode()) snprintf(optbuf, BUFSIZ, "(" XFMT ")", actual->rhdr.base); else snprintf(optbuf, BUFSIZ, "%s", ""); snprintf(logbuf, BUFSIZ - 1, " %s %c%c %s ID: %10u %s %-31s ", time, c, c2, optbuf, actual->id, elfsh_get_objtype(actual->hdr) == ET_REL ? "ET_REL " : elfsh_get_objtype(actual->hdr) == ET_DYN ? "ET_DYN " : elfsh_get_objtype(actual->hdr) == ET_EXEC ? "ET_EXEC" : elfsh_get_objtype(actual->hdr) == ET_CORE ? "ET_CORE" : "UNKNOWN", actual->name); revm_output(logbuf); revm_dolist_dep(actual); revm_output("\n"); /* printf("-> Hashes for object : PAR[%u] ROOT[%u] CHILD[%u] \n", hash_size(&actual->parent_hash), hash_size(&actual->root_hash), hash_size(&actual->child_hash)); */ } } /* Shared descriptors */ if (hash_size(&world.shared_hash)) { revm_output("\n .::. Shared Working files .::. \n"); keys = hash_get_keys(&world.shared_hash, &keynbr); for (index = 0; index < keynbr; index++) { actual = hash_get(&world.shared_hash, keys[index]); time = ctime(&actual->loadtime); nl = strchr(time, '\n'); if (nl) *nl = 0x00; c = (world.curjob->curfile == actual ? '*' : ' '); c2 = (actual->linkmap ? 'L' : ' '); if (elfsh_is_runtime_mode()) snprintf(optbuf, BUFSIZ, "(" XFMT ")", actual->rhdr.base); else snprintf(optbuf, BUFSIZ, "%s", ""); snprintf(logbuf, BUFSIZ - 1, " [%02u] %s %c%c %s ID: %02u %-31s \n", index + 1, time, c, c2, optbuf, actual->id, actual->name); revm_output(logbuf); } } if (!hash_size(&world.curjob->loaded) && !hash_size(&world.shared_hash)) revm_output(" [*] No loaded file\n"); revm_output("\n"); revm_modlist(); revm_output("\n"); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * @brief Display a PHT * @param phdr * @param num * @param base */ void revm_pht_print(elfsh_Phdr *phdr, uint16_t num, eresi_Addr base) { elfsh_Shdr *shdr; int shtnum; int index; int index2; char *type; u_int typenum; elfshsect_t *list; regex_t *tmp; char buff[512]; char warnmsg[256]; char logbuf[BUFSIZ]; int check; eresi_Addr addr; eresi_Addr addr_end; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); FIRSTREGX(tmp); /* Primary view (2 modes, depending on the quiet flag) */ for (index = 0; index < num; index++) { typenum = elfsh_get_segment_type(phdr + index); type = (char *) (typenum >= ELFSH_SEGTYPE_MAX ? revm_display_pdesc(typenum) : elfsh_seg_type[typenum].desc); addr = phdr[index].p_vaddr; addr_end = phdr[index].p_vaddr + phdr[index].p_memsz; if (elfsh_is_runtime_mode()) { addr_end += base; addr += base; } /* We check if we have a correct alignment */ check = (addr - phdr[index].p_offset) & (phdr[index].p_align - 1); if (check != 0) snprintf(warnmsg, 255, "Wrong alignment (%d)", check); if (!world.state.revm_quiet) snprintf(buff, sizeof(buff), " %s %s -> %s %c%c%c %s%s%s " "%s%s%s %s%s%s %s%s%s => %s %s\n", revm_colornumber("[%02u]", index), revm_coloraddress(XFMT, addr), revm_coloraddress(XFMT, addr_end), (elfsh_segment_is_readable(&phdr[index]) ? 'r' : '-'), (elfsh_segment_is_writable(&phdr[index]) ? 'w' : '-'), (elfsh_segment_is_executable(&phdr[index]) ? 'x' : '-'), revm_colorfieldstr("memsz("), revm_colornumber(UFMT, phdr[index].p_memsz), revm_colorfieldstr(")"), revm_colorfieldstr("foffset("), revm_colornumber(UFMT, phdr[index].p_offset), revm_colorfieldstr(")"), revm_colorfieldstr("filesz("), revm_colornumber(UFMT, phdr[index].p_filesz), revm_colorfieldstr(")"), revm_colorfieldstr("align("), revm_colornumber(UFMT, phdr[index].p_align), revm_colorfieldstr(")"), revm_colortypestr(type), check != 0 ? revm_colorwarn(warnmsg) : "" ); else snprintf(buff, sizeof(buff), " %s %s -> %s %c%c%c %s%s%s " "%s%s%s %s%s%s\n", revm_colornumber("[%02u]", index), revm_coloraddress(XFMT, addr), revm_coloraddress(XFMT, addr_end), (elfsh_segment_is_readable(&phdr[index]) ? 'r' : '-'), (elfsh_segment_is_writable(&phdr[index]) ? 'w' : '-'), (elfsh_segment_is_executable(&phdr[index]) ? 'x' : '-'), revm_colorfieldstr("memsz("), revm_colornumber(UFMT, phdr[index].p_memsz), revm_colorfieldstr(")"), revm_colorfieldstr("foffset("), revm_colornumber(UFMT, phdr[index].p_offset), revm_colorfieldstr(")"), revm_colorfieldstr("filesz("), revm_colornumber(UFMT, phdr[index].p_filesz), revm_colorfieldstr(")")); if (!tmp || (tmp && !regexec(tmp, buff, 0, 0, 0))) revm_output(buff); revm_endline(); } snprintf(logbuf, BUFSIZ - 1, "\n [SHT correlation]" "\n [Object %s]\n\n", world.curjob->curfile->name); revm_output(logbuf); /* Retreive the sht */ if ((shdr = elfsh_get_sht(world.curjob->curfile, &shtnum)) == 0) PROFILER_OUT(__FILE__, __FUNCTION__, __LINE__); snprintf(logbuf, BUFSIZ - 1, " [*] SHT %s \n", (world.curjob->curfile->shtrb ? "has been rebuilt \n" : "is not stripped \n")); revm_output(logbuf); /* Alternate View */ for (index = 0; index < num; index++, index2 = 0) { typenum = elfsh_get_segment_type(phdr + index); type = (char *) (typenum >= ELFSH_SEGTYPE_MAX ? revm_display_pname(typenum) : elfsh_seg_type[typenum].name); snprintf(logbuf, BUFSIZ - 1, " %s %s \t", revm_colornumber("[%02u]", index), revm_colortypestr_fmt("%-10s", type)); revm_output(logbuf); revm_endline(); /* In SHT */ for (index2 = 0, list = world.curjob->curfile->sectlist; list; list = list->next) if (elfsh_segment_is_parent(list, phdr + index)) { index2++; snprintf(logbuf, BUFSIZ - 1, "%s%s ", (list->shdr->sh_offset + list->shdr->sh_size > phdr[index].p_offset + phdr[index].p_filesz ? "|" : ""), revm_colorstr(elfsh_get_section_name(world.curjob->curfile, list))); revm_output(logbuf); revm_endline(); } /* In RSHT */ for (index2 = 0, list = world.curjob->curfile->rsectlist; list; list = list->next) if (elfsh_segment_is_parent(list, phdr + index)) { index2++; snprintf(logbuf, BUFSIZ - 1, "%s%s ", (list->shdr->sh_addr + list->shdr->sh_size > phdr[index].p_vaddr + phdr[index].p_memsz ? "|" : ""), revm_colorstr(elfsh_get_section_name(world.curjob->curfile, list))); revm_output(logbuf); revm_endline(); } revm_output("\n"); } PROFILER_OUT(__FILE__, __FUNCTION__, __LINE__); }
/** * Resolve symbol in one file or all (mapped) if we are in e2dbg * Runtime compatible. * @param file * @param addr * @param roffset * @return */ char *revm_resolve(elfshobj_t *file, eresi_Addr addr, elfsh_SAddr *roffset) { int index; elfshobj_t *actual; char *name = NULL; char *dname = NULL; elfsh_SAddr offset = 0; elfsh_SAddr doffset = 0; char *bestname = NULL; elfsh_SAddr bestoffset; elfshobj_t *bestfile; char buf[BUFSIZ]; char *str; char **keys; int keynbr; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (!file) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid NULL argument", NULL); actual = file; name = elfsh_reverse_symbol(actual, addr, &offset); dname = elfsh_reverse_dynsymbol(actual, addr, &doffset); #if __DEBUG_RESOLVE__ printf("[elfsh:resolve] First found file : %s name = %s:%d / dname = %s:%d ("XFMT") \n", actual->name, name, offset, dname, doffset, addr); #endif if (!name || (dname && !strcmp(name, ELFSH_SECTION_NAME_PLT)) || (offset < 0) || (dname && doffset < offset && doffset >= 0)) { name = dname; offset = doffset; } else if (name && dname && doffset == offset) name = dname; bestname = name; bestoffset = offset; bestfile = actual; /* Find the best symbol by searching in all the objects of the process */ if (e2dbg_presence_get()) { keys = hash_get_keys(&world.curjob->loaded, &keynbr); for (index = 0; index < keynbr; index++) { actual = hash_get(&world.curjob->loaded, keys[index]); if (!actual->linkmap) continue; name = elfsh_reverse_symbol(actual, addr, &offset); dname = elfsh_reverse_dynsymbol(actual, addr, &doffset); if (!name || (offset < 0) || (dname && doffset < offset && doffset >= 0)) { name = dname; offset = doffset; } if (!bestname || (bestoffset < 0) || (name && (offset < bestoffset) && offset >= 0)) { bestname = name; bestoffset = offset; bestfile = actual; #if __DEBUG_RESOLVE__ fprintf(stderr, "[elfsh:resolve] Changed best : file %s name %s %d\n", actual->name, name, offset); #endif } } } #if __DEBUG_RESOLVE__ printf("[elfsh:resolve] BEST name %s %d\n", bestname, bestoffset); #endif if (roffset) *roffset = bestoffset; if (bestname == NULL) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Unable to resolve best name", (NULL)); if (elfsh_is_runtime_mode()) { str = revm_basename(bestfile->name); snprintf(buf, BUFSIZ, "%s@%s", bestname, (str ? str : "CORRUPTED")); } else snprintf(buf, BUFSIZ, "%s", bestname); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, strdup(buf)); }
/** * 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); }
/* Breakpoint command */ int cmd_bp() { char *str; int ret; eresi_Addr addr; char logbuf[BUFSIZ]; int idx; int index; elfsh_SAddr off = 0; char *name; elfshbp_t *cur; char **keys; int keynbr; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* build argc */ for (idx = 0; world.curjob->curcmd->param[idx] != NULL; idx++); str = revm_lookup_string(world.curjob->curcmd->param[0]); /* Select subcommand */ switch (idx) { /* List breakpoints */ case 0: e2dbg_output(" .:: Breakpoints ::.\n\n"); keys = hash_get_keys(&e2dbgworld.bp, &keynbr); for (index = 0; index < keynbr; index++) { cur = hash_get(&e2dbgworld.bp, keys[index]); name = revm_resolve(world.curjob->curfile, (eresi_Addr) cur->addr, &off); if (off) snprintf(logbuf, BUFSIZ, " %c [%02u] " XFMT " <%s + " UFMT ">\n", (e2dbg_is_watchpoint(cur) ? 'W' : 'B'), cur->id, cur->addr, name, off); else snprintf(logbuf, BUFSIZ, " %c [%02u] " XFMT " <%s>\n", (e2dbg_is_watchpoint(cur) ? 'W' : 'B'), cur->id, cur->addr, name); e2dbg_output(logbuf); } hash_free_keys(keys); if (!index) e2dbg_output(" [*] No breakpoints\n"); e2dbg_output("\n"); break; /* Supply a new breakpoint */ case 1: if (!elfsh_is_runtime_mode()) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Not in dynamic or debugger mode", -1); if (!str || !(*str)) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid argument", -1); /* Break on a supplied virtual address */ if (IS_VADDR(str)) { if (sscanf(str + 2, AFMT, &addr) != 1) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid virtual address requested", (-1)); } /* Resolve first a function name */ else { addr = e2dbg_breakpoint_find_addr(str); if (addr == 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Requested symbol address unknown", -1); } /* Add the breakpoint */ ret = e2dbg_breakpoint_add(addr); if (ret < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Breakpoint insertion failed\n", (-1)); if (ret >= 0) { name = revm_resolve(world.curjob->curfile, addr, &off); if (!off) snprintf(logbuf, BUFSIZ - 1, " [*] Breakpoint added at <%s> (" XFMT ")\n\n", name, addr); else snprintf(logbuf, BUFSIZ - 1, " [*] Breakpoint added at <%s + " UFMT "> (" XFMT ")\n\n", name, off, addr); e2dbg_output(logbuf); } break; /* Wrong command syntax */ default: PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Wrong arg number", (-1)); } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (ret)); }