/** * Signal handler for SIGTRAP * @param signum * @param info * @param pcontext * @return */ void e2dbg_sigtrap_handler(int signum, siginfo_t *info, void *pcontext) { char *argv[2]; //ucontext_t *context; e2dbgparams_t params; CLRSIG; e2dbg_presence_set(); #if (__DEBUG_THREADS__ || __DEBUG_E2DBG__ || __DEBUG_MUTEX__) if (!e2dbg_presence_get()) e2dbg_output(" [*] Debuggee in SIGTRAP handler\n"); else e2dbg_output(" [*] Debugger in SIGTRAP handler\n"); #endif //context = (ucontext_t *) pcontext; argv[0] = E2DBG_ARGV0; argv[1] = NULL; e2dbg_output(" [*] SIGTRAP : Entering E2dbg.\n"); params.ac = 1; params.av = argv; e2dbg_entry(¶ms); e2dbg_presence_reset(); SETSIG; }
/* Symbol matching on the stack content. Always useful */ int e2dbg_stack_dump(uint32_t size, eresi_Addr start) { long *i; char logbuf[BUFSIZ]; char *name; elfsh_SAddr off; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); e2dbg_output(" .:: Stack ::.\n"); /* Just a simple loop that dump resolved stack content */ for (i = (long *) start; i < (long *) start + size; i++) { if ((eresi_Addr) i >= E2DBG_KERNELBASE) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot dump anymore : end of stack", -1); name = revm_resolve(world.curjob->curfile, *i, &off); if (!name) name = "?"; if (off) snprintf(logbuf, BUFSIZ - 1, " " XFMT " " XFMT " <%s + " DFMT "> \n", (eresi_Addr) i, (eresi_Addr) *i, name, off); else snprintf(logbuf, BUFSIZ - 1, " " XFMT " " XFMT " <%s> \n", (eresi_Addr) i, (eresi_Addr) *i, name); e2dbg_output(logbuf); } e2dbg_output("\n"); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/* Watchpoint */ int cmd_watch() { int idx; revmexpr_t *addr; eresi_Addr val; char buff[BUFSIZ]; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); /* List watchpoints */ if (!world.curjob->curcmd->param[0]) { e2dbg_output(" .:: Watchpoints ::.\n\n"); for (idx = 0; e2dbgworld.tracedata[idx]; idx++) { snprintf(buff, BUFSIZ, " [%u] %-40s ("XFMT")\n", idx, e2dbgworld.tracedstr[idx], e2dbgworld.tracedata[idx]); e2dbg_output(buff); } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); } /* Put a new watchpoint */ for (idx = 0; world.curjob->curcmd->param[idx]; idx++) { addr = revm_compute(world.curjob->curcmd->param[idx]); if (!addr || !addr->type || !addr->value) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid parameter", -1); if (addr->type->type != ASPECT_TYPE_LONG && addr->type->type != ASPECT_TYPE_CADDR && addr->type->type != ASPECT_TYPE_DADDR) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Can watch only an address", -1); if (e2dbgworld.tdatanbr >= E2DBG_STEPCMD_MAX) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Too many watch: cannot trace more", -1); val = (addr->value->immed ? addr->value->immed_val.ent : addr->value->get_obj(addr->value->parent)); e2dbgworld.tracedata[e2dbgworld.tdatanbr] = val; e2dbgworld.tracedstr[e2dbgworld.tdatanbr] = strdup(world.curjob->curcmd->param[idx]); snprintf(buff, BUFSIZ, " [%u] Added watchpoint on address "XFMT" - (from %s)\n", e2dbgworld.tdatanbr, e2dbgworld.tracedata[e2dbgworld.tdatanbr], e2dbgworld.tracedstr[e2dbgworld.tdatanbr]); e2dbg_output(buff); e2dbgworld.tdatanbr++; } e2dbg_output("\n"); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/* Print the registers state just before entering the breakpoint */ int cmd_dumpregs() { PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (!e2dbgworld.curthread) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "No current thread available", (-1)); if (!e2dbgworld.curthread->context) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "No context available", (-1)); e2dbg_output(" .:: Registers ::. \n\n"); e2dbg_setregs(); e2dbg_printregs(); e2dbg_output("\n"); PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (0)); }
/** Reinstall a breakpoint */ void e2dbg_breakpoint_reinstall() { elfshbp_t *bp; char buf[32]; int ret; /* Test if we need to reinstall a breakpoint */ snprintf(buf, sizeof(buf), XFMT, e2dbgworld.stoppedthread->past); bp = hash_get(&e2dbgworld.bp, buf); /* Call the architecture dependant hook for putting back the breakpoint */ if (bp) { ret = e2dbg_setbreak(bp->obj, bp); if (ret < 0) { e2dbg_output(" [E] Breakpoint reinsertion failed"); return; } //#if __DEBUG_BP__ fprintf(stderr, " [D] Breakpoint reinserted at " AFMT " ! \n", bp->addr); //#endif e2dbgworld.stoppedthread->past = 0; } else fprintf(stderr, " [D] Breakpoint was deleted from " AFMT " : not reinstalling ! \n", e2dbgworld.stoppedthread->past); }
/** * Signal handler for SIGSTOP * @param signum * @param info * @param pcontext * @return */ void e2dbg_sigstop_handler(int signum, siginfo_t *info, void *pcontext) { char *argv[2]; e2dbgparams_t params; e2dbgthread_t *curthread; char key[15]; CLRSIG; e2dbg_presence_set(); #if __DEBUG_THREADS__ printf("\n [*] SIGSTOP handler for thread %u \n", (unsigned int) e2dbg_self()); #endif /* Get the current thread */ snprintf(key, sizeof(key), "%u", (unsigned int) e2dbg_self()); curthread = hash_get(&e2dbgworld.threads, key); curthread->context = (ucontext_t *) pcontext; /* Set all registers as variables and get PC */ //e2dbgworld.context = (ucontext_t *) pcontext; e2dbg_user_hooks_install(); e2dbg_getregs(); argv[0] = E2DBG_ARGV0; argv[1] = NULL; e2dbg_output(" [*] Interrupted, entering E2dbg ...\n"); params.ac = 1; params.av = argv; e2dbg_entry(¶ms); e2dbg_presence_reset(); SETSIG; }
/* Find a breakpoint by various ways */ elfshbp_t *e2dbg_breakpoint_lookup(char *name) { eresi_Addr addr; elfshbp_t *bp; uint16_t bpid; char straddr[32]; char logbuf[BUFSIZ]; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); bp = NULL; /* Lookup by vaddr */ if (IS_VADDR(name)) { if (sscanf(name + 2, AFMT, &addr) != 1) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid virtual address requested", NULL); } /* Try to lookup by ID */ else if (revm_isnbr(name)) { bpid = atoi(name); bp = e2dbg_breakpoint_from_id(bpid); if (!bp) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Invalid breakpoint ID", NULL); } /* Resolve symbol */ /* Here we fix symbols on the disk only ! This avoid a mprotect */ else { addr = e2dbg_breakpoint_find_addr(name); if (!addr) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Requested symbol address unknown", NULL); } /* Get the breakpoint */ if (!bp) { snprintf(straddr, sizeof(straddr), XFMT, addr); bp = hash_get(&e2dbgworld.bp, straddr); if (!bp) { snprintf(logbuf, BUFSIZ, "\n [!] No breakpoint set at addr " AFMT " \n\n", addr); e2dbg_output(logbuf); PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "No breakpoint at this address", NULL); } } PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, bp); }
void e2dbg_watch_check_ia32_sysv(u_int regidx, char *regstr) { char buff[BUFSIZ]; u_int idx; for (idx = 0; idx < E2DBG_STEPCMD_MAX && e2dbgworld.tracedata[idx]; idx++) if (e2dbgworld.curthread->context->uc_mcontext.gregs[regidx] == e2dbgworld.tracedata[idx]) { snprintf(buff, BUFSIZ, " [*] TRACED %s ("XFMT") found in register %s \n", e2dbgworld.tracedstr[idx], e2dbgworld.tracedata[idx], regstr); e2dbg_output(buff); /* Disable stepping and tracing */ if (e2dbgworld.curthread->trace) e2dbg_step(); e2dbgworld.curthread->trace = 0; } }
/** * Load linkmap * @param name * @return */ int e2dbg_linkmap_load(char *name) { static int done = 0; elfshsect_t *got; eresi_Addr *linkmap_entry; void *data; #if defined(sun) Link_map *actual; #else elfshlinkmap_t *actual; #endif char *gotname; char *ename; elfsh_Ehdr *hdr; u_int elftypenum; elfsh_Sym *endsym; char buff[64]; PROFILER_IN(__FILE__, __FUNCTION__, __LINE__); if (done) PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg] Starting Loading LINKMAP !! \n"); #endif e2dbg_user_hooks_install(); revm_config(E2DBG_CONFIG); /* Load debugged file */ if (name) { /* No need to fill ET_EXEC base addr */ if (!revm_is_loaded(name) && revm_file_load(name, 0, NULL) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot load file", -1); #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] file %s loaded\n", name); #endif world.curjob->curfile->linkmap = E2DBG_DYNAMIC_LINKMAP; world.curjob->curfile->iotype = ELFSH_IOTYPE_EMBEDDED; world.curjob->curfile->running = 0; } #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] Before switch\n"); #endif /* Switch to obj 1 */ if (revm_doswitch(1) < 0) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot switch on object 1", -1); #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] After switch \n"); #endif /* Base address for PIE binaries have to be imported */ if (world.curjob->curfile->hdr->e_type == ET_DYN && !world.curjob->curfile->rhdr.base) { #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] Inside ET_DYN condition\n"); #endif endsym = elfsh_get_symbol_by_name(world.curjob->curfile, "_end"); fprintf(stderr, "endsym = " AFMT " \n", (eresi_Addr) endsym); sleep(1); #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] Filling PIE base" " (_end ondisk = " AFMT " / _end in memory = " AFMT ") ! \n", endsym->st_value, e2dbgworld.syms.piebase); #endif world.curjob->curfile->rhdr.base = e2dbgworld.syms.piebase - endsym->st_value; } /* Get ALTGOT or GOT if we used LD_PRELOAD */ if (!e2dbgworld.preloaded) { gotname = ELFSH_SECTION_NAME_ALTGOT; got = elfsh_get_section_by_name(world.curjob->curfile, gotname, NULL, NULL, NULL); } else got = elfsh_get_gotsct(world.curjob->curfile); #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] %s section at " XFMT "\n", got->name, got->shdr->sh_addr); fprintf(stderr, "[e2dbg_linkmap_load] BASE = %08x\n", world.curjob->curfile->rhdr.base); #endif /* Fix first file linkmap entry */ if (world.curjob->curfile->linkmap == E2DBG_DYNAMIC_LINKMAP) { /* Fix first file linkmap entry */ hdr = elfsh_get_hdr(world.curjob->curfile); if (!hdr) PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, "Cannot get ELF header", -1); elftypenum = elfsh_get_objtype(hdr); //fprintf(stderr, "[e2dbg_linkmap_load] after ELF header \n"); /* Get ALTGOT entry */ data = elfsh_readmem(got); //fprintf(stderr, "[e2dbg_linkmap_load] after get_raw (data = %08X) \n", data); linkmap_entry = elfsh_get_got_entry_by_index(data, 1); //fprintf(stderr, "[e2dbg_linkmap_load] after entry_by_index (linkmap_entry = %08x)\n", // linkmap_entry); #if defined(__FreeBSD__) || defined(__NetBSD__) world.curjob->curfile->linkmap = (elfshlinkmap_t *) &((Obj_Entry *) elfsh_get_got_val(linkmap_entry))->linkmap; #elif defined(sun) world.curjob->curfile->linkmap = e2dbgworld.syms.map; #else world.curjob->curfile->linkmap = (elfshlinkmap_t *) elfsh_get_got_val(linkmap_entry); #endif } #if __DEBUG_LINKMAP__ else fprintf(stderr, "[e2dbg_linkmap_load] Linkmap was -NOT- dynamic\n"); fprintf(stderr, "[e2dbg_linkmap_load] LINKMAP Found at " XFMT "\n", world.curjob->curfile->linkmap); #endif revm_doswitch(1); /* now load all linkmap's files */ for (actual = elfsh_linkmap_get_lprev(world.curjob->curfile->linkmap); actual != NULL; actual = elfsh_linkmap_get_lprev(actual)) { #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] Running on LINKMAP PREV " XFMT "\n", actual); #endif ename = elfsh_linkmap_get_lname(actual); if (ename && *ename && !revm_is_loaded(ename)) { if (revm_file_load(ename, elfsh_linkmap_get_laddr(actual), world.curjob->curfile->linkmap) < 0) e2dbg_output(" [EE] Loading failed"); world.curjob->curfile->iotype = ELFSH_IOTYPE_EMBEDDED; } } #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] Running on LINKMAP NEXT\n"); #endif for (actual = elfsh_linkmap_get_lnext(world.curjob->curfile->linkmap); actual != NULL; actual = elfsh_linkmap_get_lnext(actual)) { ename = elfsh_linkmap_get_lname(actual); #if __DEBUG_LINKMAP__ fprintf(stderr, "[e2dbg_linkmap_load] Running on LINKMAP NEXT " XFMT " (%s baseaddr %08X) \n", actual, ename, actual->laddr); #endif if (ename && *ename && !revm_is_loaded(ename)) { if (revm_file_load(ename, elfsh_linkmap_get_laddr(actual), world.curjob->curfile->linkmap) < 0) e2dbg_output(" [EE] Loading failed"); world.curjob->curfile->iotype = ELFSH_IOTYPE_EMBEDDED; } } /* Everything was OK */ e2dbg_output("\n"); //elfsh_set_runtime_mode(); revm_doswitch(1); snprintf(buff, sizeof(buff), " [*] Target PID = %u \n", getpid()); e2dbg_output(buff); done = 1; PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0); }
/** * SIGTRAP signal handler (The breakpoint routine). Save registers and callback. Multi-thread safe. * @param signum Received signal number. * @param info Signal info structure from breakpoint. * @param pcontext Context data pointer containing register values and more. * @return */ void e2dbg_generic_breakpoint(int signum, siginfo_t *info, void *pcontext) { ucontext_t *context; char key[15]; pthread_t stopped; /* Do not allow processing of 2 breakpoint at the same time */ /* We update the current thread information */ e2dbg_presence_set(); revm_proc_init(); if (!e2dbgworld.curbp || e2dbgworld.curbp->tid != e2dbg_self()) { e2dbg_mutex_lock(&e2dbgworld.dbgbp); #if (__DEBUG_THREADS__ || __DEBUG_E2DBG__ || __DEBUG_MUTEX__ || __DEBUG_BP__) //e2dbg_output("-------------- ON-BREAK REGISTERS ----------------------->\n"); //cmd_dumpregs(); //e2dbg_output("<------------------------------------------------------\n"); e2dbg_output("------------------------------------->\n"); e2dbg_output(" [*] BP MUTEX LOCKED [e2dbg_generic_breakpoint] \n"); //e2dbg_threads_print(); #endif } /* Get the current thread */ stopped = (pthread_t) e2dbg_self(); snprintf(key, sizeof(key), "%u", (unsigned int) stopped); e2dbgworld.curthread = hash_get(&e2dbgworld.threads, key); e2dbgworld.stoppedthread = e2dbgworld.curthread; #if (__DEBUG_THREADS__ || __DEBUG_E2DBG__ || __DEBUG_MUTEX__ || __DEBUG_BP__) fprintf(stderr, "\n [*] Thread entering generic breakpoint (ID %u) \n", (unsigned int) e2dbgworld.stoppedthread->tid); fflush(stdout); #endif e2dbgworld.stoppedthread->state = E2DBG_THREAD_BREAKING; context = (ucontext_t *) pcontext; e2dbgworld.stoppedthread->context = context; /* We first get contexts for all other threads (except debugger) using SIGUSR2 */ /* Then we stop all threads */ /* We do this only at the first state (count = 0) of the breakpoint */ if (!e2dbgworld.stoppedthread->count) { if (e2dbg_thread_stopall(SIGUSR2)) usleep(100000); } #if (__DEBUG_THREADS__ || __DEBUG_E2DBG__ || __DEBUG_MUTEX__ || __DEBUG_BP__) else fprintf(stderr, " NOT COLLECTING THREADS CONTEXTS (stopped thread %u state count = %u) \n", (u_int) e2dbgworld.stoppedthread->tid, e2dbgworld.stoppedthread->count); #endif /* Call the real breakpoint code */ e2dbg_breakpoint_process(); /* Continue all threads */ if (e2dbgworld.stoppedthread->count == E2DBG_BREAK_FINISHED || e2dbgworld.curthread->step || e2dbgworld.curthread->was_step) { e2dbg_thread_contall(); e2dbgworld.curthread->was_step = 0; e2dbgworld.stoppedthread->count = E2DBG_BREAK_NONE; e2dbgworld.curbp = NULL; fprintf(stderr, " [D] Thread ID %lu now has Count = 0 (NONE) \n", e2dbgworld.curthread->tid); /* Allow another breakpoint to be processed */ if (e2dbg_mutex_unlock(&e2dbgworld.dbgbp) != 0) e2dbg_output(" [*] Debuggee Cannot unlock breakpoint mutex ! \n"); #if (__DEBUG_THREADS__ || __DEBUG_E2DBG__ || __DEBUG_MUTEX__ || __DEBUG_BP__) else { e2dbg_output(" [*] BP MUTEX UNLOCKED [e2dbg_generic_breakpoint] \n"); e2dbg_output("<-------------------------------------\n"); } #endif } #if (__DEBUG_THREADS__ || __DEBUG_E2DBG__ || __DEBUG_MUTEX__ || __DEBUG_BP__) else fprintf(stderr, " [D] No SIGCONT as thread (%u) is stopped with state count = %u \n", (u_int) e2dbgworld.stoppedthread->tid, e2dbgworld.stoppedthread->count); #endif e2dbgworld.stoppedthread->state = E2DBG_THREAD_RUNNING; e2dbg_presence_reset(); SETSIG; #if __DEBUG_BP__ fprintf(stderr, " [D] Returning from generic signal handler\n"); #endif }
/* 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)); }