diff --git a/.debugusrc.js b/.debugusrc.js index 49f986c..16c9989 100644 --- a/.debugusrc.js +++ b/.debugusrc.js @@ -20,16 +20,18 @@ var register_names = [ "r14", "r15", "rip", - "rflags", + "eflags", "cs", - "orig_rax", - "fs_base", - "gs_base", "fs", "gs", "ss", "ds", "es", + "tr", + "ldtr", + "mxcsr", + "ctrl", + "stat", ]; function dump_regs() @@ -50,6 +52,11 @@ function mem_write_reg(reg, v) mem_write(get_reg(reg), v); } +function print_rip() +{ + log_inf("rip " + get_reg("rip")); +} + function print_file() { log_inf("Debugging file \"" + get_file() + "\""); diff --git a/.debugusrc1.js b/.debugusrc1.js index 7c056ab..7c6cf25 100644 --- a/.debugusrc1.js +++ b/.debugusrc1.js @@ -3,13 +3,13 @@ log_inf("Loading user init script for program ./test"); log_err("Test error message"); -var main_offset = "0x0000000000001135"; // objdump -d ./test +var offset = "0x0000000000001145"; // objdump -d ./test // Testing... print_file(); print_pid(); print_program_load_offset(); -mk_brk_addr(main_offset); +mk_brk_addr(offset); list_brks(); log_inf("1 --------------------------------------------"); @@ -29,4 +29,4 @@ log_inf("Memory at r14 " + mem_read_reg("r14")); mem_write_reg("r14", r14_mem); log_inf("Memory at r14 " + mem_read_reg("r14")); -cont(); +// cont(); diff --git a/debugus.c b/debugus.c index d00cd8f..572552d 100644 --- a/debugus.c +++ b/debugus.c @@ -27,6 +27,7 @@ #define INIT_SCRIPT ".debugusrc.js" // Registers +// Taken from da goat https://source.winehq.org/source/dlls/dbghelp/cpu_x86_64.c typedef enum { rax, @@ -46,16 +47,18 @@ typedef enum { r14, r15, rip, - rflags, + eflags, cs, - orig_rax, - fs_base, - gs_base, fs, gs, ss, ds, es, + tr, + ldtr, + mxcsr, + ctrl, + stat, MAX_REGISTERS, } Register; @@ -67,8 +70,6 @@ typedef struct { static RegisterDescriptor reg_descriptors[MAX_REGISTERS] = { #define make_rd(r, dr) { r, dr, #r } - make_rd(orig_rax, -1), - make_rd(rip, -1), make_rd(rax, 0), make_rd(rdx, 1), make_rd(rcx, 2), @@ -85,74 +86,22 @@ static RegisterDescriptor reg_descriptors[MAX_REGISTERS] = { make_rd(r13, 13), make_rd(r14, 14), make_rd(r15, 15), - make_rd(rflags, 49), + make_rd(rip, 16), + make_rd(eflags, 49), make_rd(es, 50), make_rd(cs, 51), make_rd(ss, 52), make_rd(ds, 53), make_rd(fs, 54), make_rd(gs, 55), - make_rd(fs_base, 58), - make_rd(gs_base, 59), + make_rd(tr, 62), + make_rd(ldtr, 63), + make_rd(mxcsr, 64), + make_rd(ctrl, 65), + make_rd(stat, 66), #undef make_rd }; -uint64_t get_reg_value(pid_t pid, Register r) -{ - struct user_regs_struct rs; - ptrace(PTRACE_GETREGS, pid, NULL, &rs); - - for (int i = 0; i < sizeof(reg_descriptors)/sizeof(reg_descriptors[0]); i++) { - if (reg_descriptors[i].r == r) { - return ((uint64_t*)&rs)[i]; - } - } -} - -void set_reg_value(pid_t pid, Register r, uint64_t v) -{ - struct user_regs_struct rs; - ptrace(PTRACE_GETREGS, pid, NULL, &rs); - - for (int i = 0; i < sizeof(reg_descriptors)/sizeof(reg_descriptors[0]); i++) { - if (reg_descriptors[i].r == r) { - ((uint64_t*)&rs)[i] = v; - ptrace(PTRACE_SETREGS, pid, NULL, &rs); - return; - } - } -} - -const char *get_reg_name(Register r) -{ - for (int i = 0; i < sizeof(reg_descriptors)/sizeof(reg_descriptors[0]); i++) { - if (reg_descriptors[i].r == r) { - return reg_descriptors[i].name; - } - } -} - -Register get_reg_from_name(const char *name) -{ - for (int i = 0; i < MAX_REGISTERS; i++) { - if (strcmp(name, reg_descriptors[i].name) == 0) { - return reg_descriptors[i].r; - } - } -} - -// Memory - -uint64_t mem_read(pid_t pid, uint64_t addr) -{ - return ptrace(PTRACE_PEEKDATA, pid, addr, NULL); -} - -void mem_write(pid_t pid, uint64_t addr, uint64_t v) -{ - ptrace(PTRACE_POKEDATA, pid, addr, v); -} - // How breakpoints work? // We can enable/disable breakpoints by putting/removing an int 3 instruction // into/from the executed program. int 3 will trigger a SIGTRAP, which we can @@ -196,17 +145,111 @@ typedef struct { js_State *js; HashTable brks; uintptr_t program_load_offset; + bool running; } Dbg; +void dbg_wait(Dbg *dbg) +{ + int status, options = 0; + waitpid(dbg->pid, &status, options); +} + +// Memory + +uint64_t dbg_mem_read(Dbg *dbg, uint64_t addr) +{ + return ptrace(PTRACE_PEEKDATA, dbg->pid, addr, NULL); +} + +void dbg_mem_write(Dbg *dbg, uint64_t addr, uint64_t v) +{ + ptrace(PTRACE_POKEDATA, dbg->pid, addr, v); +} + +uint64_t dbg_get_reg_value(Dbg *dbg, Register r) +{ + struct user_regs_struct rs; + ptrace(PTRACE_GETREGS, dbg->pid, NULL, &rs); + + for (int i = 0; i < sizeof(reg_descriptors)/sizeof(reg_descriptors[0]); i++) { + if (reg_descriptors[i].r == r) { + return ((uint64_t*)&rs)[i]; + } + } +} + +void dbg_set_reg_value(Dbg *dbg, Register r, uint64_t v) +{ + struct user_regs_struct rs; + ptrace(PTRACE_GETREGS, dbg->pid, NULL, &rs); + + for (int i = 0; i < sizeof(reg_descriptors)/sizeof(reg_descriptors[0]); i++) { + if (reg_descriptors[i].r == r) { + ((uint64_t*)&rs)[i] = v; + ptrace(PTRACE_SETREGS, dbg->pid, NULL, &rs); + return; + } + } +} + +const char *get_reg_name(Register r) +{ + for (int i = 0; i < sizeof(reg_descriptors)/sizeof(reg_descriptors[0]); i++) { + if (reg_descriptors[i].r == r) { + return reg_descriptors[i].name; + } + } +} + +Register get_reg_from_name(const char *name) +{ + for (int i = 0; i < MAX_REGISTERS; i++) { + if (strcmp(name, reg_descriptors[i].name) == 0) { + return reg_descriptors[i].r; + } + } +} + +uint64_t dbg_get_rip(Dbg *dbg) +{ + return dbg_get_reg_value(dbg, rip); +} + +void dbg_set_rip(Dbg *dbg, uint64_t v) +{ + dbg_set_reg_value(dbg, rip, v); +} + +void dbg_step_brk(Dbg *dbg) +{ + uint64_t loc = dbg_get_rip(dbg) - 1; + char key[20]; + snprintf(key, sizeof(key), "0x%"PRIxPTR, (uintptr_t)loc); + Brk *brk = hashtable_get(&dbg->brks, key); + if ((brk != NULL && brk->enabled)) { + uint64_t prev_instr = loc; + dbg_set_rip(dbg, prev_instr); + brk->enabled = false; + ptrace(PTRACE_SINGLESTEP, brk->pid, NULL, NULL); + dbg_wait(dbg); + brk->enabled = true; + } else { + if (!dbg->running) { + dbg->running = true; + } else { + LOG_ERR("Breakpoint 0x%"PRIxPTR" either doesn't exist or is disabled\n", loc); + } + } +} + #define getdbg() ((Dbg*)js_currentfunctiondata(js)) void dbg_js_cont(js_State *js) { Dbg *dbg = getdbg(); + dbg_step_brk(dbg); ptrace(PTRACE_CONT, dbg->pid, NULL, NULL); - - int status, options = 0; - waitpid(dbg->pid, &status, options); + dbg_wait(dbg); js_pushundefined(js); } @@ -217,9 +260,12 @@ void dbg_js_mk_brk_addr(js_State *js) const char *addr_str = js_tostring(js, 1); uintptr_t addr; sscanf(addr_str, "0x%"SCNxPTR, &addr); + uintptr_t full_addr = dbg->program_load_offset + addr; + char addr_str2[20]; + snprintf(addr_str2, sizeof(addr_str2), "0x%"PRIxPTR, full_addr); Brk brk = { .pid = dbg->pid, .addr = dbg->program_load_offset + addr }; brk_enable(&brk); - hashtable_set(&dbg->brks, addr_str, &brk, sizeof(brk)); + hashtable_set(&dbg->brks, addr_str2, &brk, sizeof(brk)); done: js_pushundefined(js); } @@ -228,6 +274,11 @@ void dbg_js_rm_brk_addr(js_State *js) { Dbg *dbg = getdbg(); const char *addr_str = js_tostring(js, 1); + /* uintptr_t addr; */ + /* sscanf(addr_str, "0x%"SCNxPTR, &addr); */ + /* uintptr_t full_addr = dbg->program_load_offset + addr; */ + /* char addr_str2[20]; */ + /* snprintf(addr_str2, sizeof(addr_str2), "0x%"PRIxPTR, full_addr); */ Brk *brk = (Brk *)hashtable_get(&dbg->brks, addr_str); if (brk == NULL) { LOG_ERR("No breakpoint at address: %s\n", addr_str); @@ -263,8 +314,9 @@ void dbg_js_list_brks(js_State *js) for (int i = 0; i < dbg->brks.capacity; i++) { if (dbg->brks.buckets[i] != NULL) { Brk *brk = (Brk*)dbg->brks.buckets[i]->value; - LOG_INF("Breakpoint %d (%s) at 0x%"PRIxPTR"\n", - c+1, dbg->brks.buckets[i]->key, brk->addr); + LOG_INF("Breakpoint %d (%s) at 0x%"PRIxPTR" (%s)\n", + c+1, dbg->brks.buckets[i]->key, brk->addr, + brk->enabled ? "Enabled" : "Disabled"); c++; } } @@ -312,9 +364,9 @@ void dbg_js_get_reg(js_State *js) Dbg *dbg = getdbg(); const char *name = js_tostring(js, 1); Register r = get_reg_from_name(name); - uint64_t v = get_reg_value(dbg->pid, r); + uint64_t v = dbg_get_reg_value(dbg, r); char buf[20]; - snprintf(buf, sizeof(buf), "0x%016"PRIx64, v); + snprintf(buf, sizeof(buf), "0x%"PRIx64, v); js_pushstring(js, buf); } @@ -326,7 +378,7 @@ void dbg_js_set_reg(js_State *js) const char *value_str = js_tostring(js, 2); uint64_t value; sscanf(value_str, "0x%"SCNx64, &value); - set_reg_value(dbg->pid, r, value); + dbg_set_reg_value(dbg, r, value); js_pushundefined(js); } @@ -336,7 +388,7 @@ void dbg_js_mem_read(js_State *js) const char *addr_str = js_tostring(js, 1); uintptr_t addr; sscanf(addr_str, "0x%"SCNxPTR, &addr); - uint64_t v = mem_read(dbg->pid, addr); + uint64_t v = dbg_mem_read(dbg, addr); char buf[20]; snprintf(buf, sizeof(buf), "0x%"PRIx64, v); js_pushstring(js, buf); @@ -351,7 +403,7 @@ void dbg_js_mem_write(js_State *js) const char *value_str = js_tostring(js, 2); uint64_t value; sscanf(value_str, "0x%"SCNx64, &value); - mem_write(dbg->pid, addr, value); + dbg_mem_write(dbg, addr, value); js_pushundefined(js); } @@ -442,9 +494,7 @@ void dbg_deinit(Dbg *dbg) void dbg_loop(Dbg *dbg) { - int status, options = 0; - waitpid(dbg->pid, &status, options); - + dbg_wait(dbg); char *line = NULL; while ((line = linenoise("debugus # ")) != NULL) { js_dostring(dbg->js, line); diff --git a/test.c b/test.c index d637e43..b31e67e 100644 --- a/test.c +++ b/test.c @@ -1,9 +1,16 @@ #include +void dupa(void) { + printf("KSKSKKSKSKSK\n"); +} + int main(void) { - for (int i = 0; i < 20; i++) { + for (int i = 1; i <= 20; i++) { printf("i = %d\n", i); + if (i % 10 == 0) { + dupa(); + } } return 0; }