Step over breakpoints

This commit is contained in:
kamkow1
2025-03-10 00:17:31 +01:00
parent 87cb958478
commit c39b54d0d7
4 changed files with 151 additions and 87 deletions

View File

@@ -20,16 +20,18 @@ var register_names = [
"r14", "r14",
"r15", "r15",
"rip", "rip",
"rflags", "eflags",
"cs", "cs",
"orig_rax",
"fs_base",
"gs_base",
"fs", "fs",
"gs", "gs",
"ss", "ss",
"ds", "ds",
"es", "es",
"tr",
"ldtr",
"mxcsr",
"ctrl",
"stat",
]; ];
function dump_regs() function dump_regs()
@@ -50,6 +52,11 @@ function mem_write_reg(reg, v)
mem_write(get_reg(reg), v); mem_write(get_reg(reg), v);
} }
function print_rip()
{
log_inf("rip " + get_reg("rip"));
}
function print_file() function print_file()
{ {
log_inf("Debugging file \"" + get_file() + "\""); log_inf("Debugging file \"" + get_file() + "\"");

View File

@@ -3,13 +3,13 @@
log_inf("Loading user init script for program ./test"); log_inf("Loading user init script for program ./test");
log_err("Test error message"); log_err("Test error message");
var main_offset = "0x0000000000001135"; // objdump -d ./test var offset = "0x0000000000001145"; // objdump -d ./test
// Testing... // Testing...
print_file(); print_file();
print_pid(); print_pid();
print_program_load_offset(); print_program_load_offset();
mk_brk_addr(main_offset); mk_brk_addr(offset);
list_brks(); list_brks();
log_inf("1 --------------------------------------------"); log_inf("1 --------------------------------------------");
@@ -29,4 +29,4 @@ log_inf("Memory at r14 " + mem_read_reg("r14"));
mem_write_reg("r14", r14_mem); mem_write_reg("r14", r14_mem);
log_inf("Memory at r14 " + mem_read_reg("r14")); log_inf("Memory at r14 " + mem_read_reg("r14"));
cont(); // cont();

208
debugus.c
View File

@@ -27,6 +27,7 @@
#define INIT_SCRIPT ".debugusrc.js" #define INIT_SCRIPT ".debugusrc.js"
// Registers // Registers
// Taken from da goat https://source.winehq.org/source/dlls/dbghelp/cpu_x86_64.c
typedef enum { typedef enum {
rax, rax,
@@ -46,16 +47,18 @@ typedef enum {
r14, r14,
r15, r15,
rip, rip,
rflags, eflags,
cs, cs,
orig_rax,
fs_base,
gs_base,
fs, fs,
gs, gs,
ss, ss,
ds, ds,
es, es,
tr,
ldtr,
mxcsr,
ctrl,
stat,
MAX_REGISTERS, MAX_REGISTERS,
} Register; } Register;
@@ -67,8 +70,6 @@ typedef struct {
static RegisterDescriptor reg_descriptors[MAX_REGISTERS] = { static RegisterDescriptor reg_descriptors[MAX_REGISTERS] = {
#define make_rd(r, dr) { r, dr, #r } #define make_rd(r, dr) { r, dr, #r }
make_rd(orig_rax, -1),
make_rd(rip, -1),
make_rd(rax, 0), make_rd(rax, 0),
make_rd(rdx, 1), make_rd(rdx, 1),
make_rd(rcx, 2), make_rd(rcx, 2),
@@ -85,74 +86,22 @@ static RegisterDescriptor reg_descriptors[MAX_REGISTERS] = {
make_rd(r13, 13), make_rd(r13, 13),
make_rd(r14, 14), make_rd(r14, 14),
make_rd(r15, 15), make_rd(r15, 15),
make_rd(rflags, 49), make_rd(rip, 16),
make_rd(eflags, 49),
make_rd(es, 50), make_rd(es, 50),
make_rd(cs, 51), make_rd(cs, 51),
make_rd(ss, 52), make_rd(ss, 52),
make_rd(ds, 53), make_rd(ds, 53),
make_rd(fs, 54), make_rd(fs, 54),
make_rd(gs, 55), make_rd(gs, 55),
make_rd(fs_base, 58), make_rd(tr, 62),
make_rd(gs_base, 59), make_rd(ldtr, 63),
make_rd(mxcsr, 64),
make_rd(ctrl, 65),
make_rd(stat, 66),
#undef make_rd #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? // How breakpoints work?
// We can enable/disable breakpoints by putting/removing an int 3 instruction // 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 // into/from the executed program. int 3 will trigger a SIGTRAP, which we can
@@ -196,17 +145,111 @@ typedef struct {
js_State *js; js_State *js;
HashTable brks; HashTable brks;
uintptr_t program_load_offset; uintptr_t program_load_offset;
bool running;
} Dbg; } 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)) #define getdbg() ((Dbg*)js_currentfunctiondata(js))
void dbg_js_cont(js_State *js) void dbg_js_cont(js_State *js)
{ {
Dbg *dbg = getdbg(); Dbg *dbg = getdbg();
dbg_step_brk(dbg);
ptrace(PTRACE_CONT, dbg->pid, NULL, NULL); ptrace(PTRACE_CONT, dbg->pid, NULL, NULL);
dbg_wait(dbg);
int status, options = 0;
waitpid(dbg->pid, &status, options);
js_pushundefined(js); js_pushundefined(js);
} }
@@ -217,9 +260,12 @@ void dbg_js_mk_brk_addr(js_State *js)
const char *addr_str = js_tostring(js, 1); const char *addr_str = js_tostring(js, 1);
uintptr_t addr; uintptr_t addr;
sscanf(addr_str, "0x%"SCNxPTR, &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 brk = { .pid = dbg->pid, .addr = dbg->program_load_offset + addr };
brk_enable(&brk); brk_enable(&brk);
hashtable_set(&dbg->brks, addr_str, &brk, sizeof(brk)); hashtable_set(&dbg->brks, addr_str2, &brk, sizeof(brk));
done: done:
js_pushundefined(js); js_pushundefined(js);
} }
@@ -228,6 +274,11 @@ void dbg_js_rm_brk_addr(js_State *js)
{ {
Dbg *dbg = getdbg(); Dbg *dbg = getdbg();
const char *addr_str = js_tostring(js, 1); 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); Brk *brk = (Brk *)hashtable_get(&dbg->brks, addr_str);
if (brk == NULL) { if (brk == NULL) {
LOG_ERR("No breakpoint at address: %s\n", addr_str); 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++) { for (int i = 0; i < dbg->brks.capacity; i++) {
if (dbg->brks.buckets[i] != NULL) { if (dbg->brks.buckets[i] != NULL) {
Brk *brk = (Brk*)dbg->brks.buckets[i]->value; Brk *brk = (Brk*)dbg->brks.buckets[i]->value;
LOG_INF("Breakpoint %d (%s) at 0x%"PRIxPTR"\n", LOG_INF("Breakpoint %d (%s) at 0x%"PRIxPTR" (%s)\n",
c+1, dbg->brks.buckets[i]->key, brk->addr); c+1, dbg->brks.buckets[i]->key, brk->addr,
brk->enabled ? "Enabled" : "Disabled");
c++; c++;
} }
} }
@@ -312,9 +364,9 @@ void dbg_js_get_reg(js_State *js)
Dbg *dbg = getdbg(); Dbg *dbg = getdbg();
const char *name = js_tostring(js, 1); const char *name = js_tostring(js, 1);
Register r = get_reg_from_name(name); 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]; char buf[20];
snprintf(buf, sizeof(buf), "0x%016"PRIx64, v); snprintf(buf, sizeof(buf), "0x%"PRIx64, v);
js_pushstring(js, buf); js_pushstring(js, buf);
} }
@@ -326,7 +378,7 @@ void dbg_js_set_reg(js_State *js)
const char *value_str = js_tostring(js, 2); const char *value_str = js_tostring(js, 2);
uint64_t value; uint64_t value;
sscanf(value_str, "0x%"SCNx64, &value); sscanf(value_str, "0x%"SCNx64, &value);
set_reg_value(dbg->pid, r, value); dbg_set_reg_value(dbg, r, value);
js_pushundefined(js); js_pushundefined(js);
} }
@@ -336,7 +388,7 @@ void dbg_js_mem_read(js_State *js)
const char *addr_str = js_tostring(js, 1); const char *addr_str = js_tostring(js, 1);
uintptr_t addr; uintptr_t addr;
sscanf(addr_str, "0x%"SCNxPTR, &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]; char buf[20];
snprintf(buf, sizeof(buf), "0x%"PRIx64, v); snprintf(buf, sizeof(buf), "0x%"PRIx64, v);
js_pushstring(js, buf); js_pushstring(js, buf);
@@ -351,7 +403,7 @@ void dbg_js_mem_write(js_State *js)
const char *value_str = js_tostring(js, 2); const char *value_str = js_tostring(js, 2);
uint64_t value; uint64_t value;
sscanf(value_str, "0x%"SCNx64, &value); sscanf(value_str, "0x%"SCNx64, &value);
mem_write(dbg->pid, addr, value); dbg_mem_write(dbg, addr, value);
js_pushundefined(js); js_pushundefined(js);
} }
@@ -442,9 +494,7 @@ void dbg_deinit(Dbg *dbg)
void dbg_loop(Dbg *dbg) void dbg_loop(Dbg *dbg)
{ {
int status, options = 0; dbg_wait(dbg);
waitpid(dbg->pid, &status, options);
char *line = NULL; char *line = NULL;
while ((line = linenoise("debugus # ")) != NULL) { while ((line = linenoise("debugus # ")) != NULL) {
js_dostring(dbg->js, line); js_dostring(dbg->js, line);

9
test.c
View File

@@ -1,9 +1,16 @@
#include <stdio.h> #include <stdio.h>
void dupa(void) {
printf("KSKSKKSKSKSK\n");
}
int main(void) int main(void)
{ {
for (int i = 0; i < 20; i++) { for (int i = 1; i <= 20; i++) {
printf("i = %d\n", i); printf("i = %d\n", i);
if (i % 10 == 0) {
dupa();
}
} }
return 0; return 0;
} }