Step over breakpoints
This commit is contained in:
@@ -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() + "\"");
|
||||||
|
|||||||
@@ -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
208
debugus.c
@@ -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
9
test.c
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user