static int r_debug_gdb_reg_write(RDebug *dbg, int type, const ut8 *buf, int size) { if (!reg_buf) { // we cannot write registers before we once read them return -1; } int buflen = 0; int bits = dbg->anal->bits; free(r_reg_get_bytes(dbg->reg, type, &buflen)); // some implementations of the gdb protocol are acting weird. // so winedbg is not able to write registers through the <G> packet // and also it does not return the whole gdb register profile after // calling <g> // so this workaround resizes the small register profile buffer // to the whole set and fills the rest with 0 if (buf_size < buflen) { ut8* new_buf = realloc (reg_buf, buflen * sizeof (ut8)); if (!new_buf) { return -1; } reg_buf = new_buf; memset (new_buf + buf_size, 0, buflen - buf_size); } RRegItem* current = NULL; for (;;) { current = r_reg_next_diff (dbg->reg, type, reg_buf, buflen, current, bits); if (!current) break; ut64 val = r_reg_get_value (dbg->reg, current); int bytes = bits / 8; gdbr_write_reg (desc, current->name, (char*)&val, bytes); } return true; }
static int r_debug_gdb_reg_read(RDebug *dbg, int type, ut8 *buf, int size) { gdbr_read_registers(desc); // read the len of the current area int buflen = 0; free (r_reg_get_bytes (dbg->reg, type, &buflen)); memcpy (buf, desc->data, desc->data_len); if (!reg_buf) { reg_buf = calloc (buflen, sizeof (char)); if (!reg_buf) { return -1; } } else { if (buf_size < desc->data_len) { ut8* new_buf = realloc (reg_buf, desc->data_len * sizeof (ut8)); if (!new_buf) { return -1; } reg_buf = new_buf; buflen = desc->data_len; buf_size = desc->data_len; } } buflen = R_MIN (desc->data_len, buflen); memcpy (reg_buf, desc->data, buflen); return desc->data_len; }
static int __reg_read (RDebug *dbg, int type, ut8 *buf, int size) { int sz; /* do nothing */ ut8 *bytes = r_reg_get_bytes (dbg->reg, type, &sz); memcpy (buf, bytes, R_MIN (size, sz)); free (bytes); return size; }
/* * Save 4096 bytes from %esp * TODO: Add support for reverse stack architectures * Also known as r_debug_inject() */ R_API ut64 r_debug_execute(RDebug *dbg, const ut8 *buf, int len, int restore) { int orig_sz; ut8 stackbackup[4096]; ut8 *backup, *orig = NULL; RRegItem *ri, *risp, *ripc; ut64 rsp, rpc, ra0 = 0LL; if (r_debug_is_dead (dbg)) return R_FALSE; ripc = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_PC], R_REG_TYPE_GPR); risp = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_SP], R_REG_TYPE_GPR); if (ripc) { r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE); orig = r_reg_get_bytes (dbg->reg, -1, &orig_sz); if (orig == NULL) { eprintf ("Cannot get register arena bytes\n"); return 0LL; } rpc = r_reg_get_value (dbg->reg, ripc); rsp = r_reg_get_value (dbg->reg, risp); backup = malloc (len); if (backup == NULL) { free (orig); return 0LL; } dbg->iob.read_at (dbg->iob.io, rpc, backup, len); dbg->iob.read_at (dbg->iob.io, rsp, stackbackup, len); r_bp_add_sw (dbg->bp, rpc+len, dbg->bpsize, R_BP_PROT_EXEC); /* execute code here */ dbg->iob.write_at (dbg->iob.io, rpc, buf, len); //r_bp_add_sw (dbg->bp, rpc+len, 4, R_BP_PROT_EXEC); r_debug_continue (dbg); //r_bp_del (dbg->bp, rpc+len); /* TODO: check if stopped in breakpoint or not */ r_bp_del (dbg->bp, rpc+len); dbg->iob.write_at (dbg->iob.io, rpc, backup, len); if (restore) { dbg->iob.write_at (dbg->iob.io, rsp, stackbackup, len); } r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE); ri = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_A0], R_REG_TYPE_GPR); ra0 = r_reg_get_value (dbg->reg, ri); if (restore) { r_reg_set_bytes (dbg->reg, -1, orig, orig_sz); } else { r_reg_set_value (dbg->reg, ripc, rpc); } r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_TRUE); free (backup); free (orig); eprintf ("ra0=0x%08"PFMT64x"\n", ra0); } else eprintf ("r_debug_execute: Cannot get program counter\n"); return (ra0); }
static int r_debug_windbg_reg_write(RDebug *dbg, int type, const ut8 *buf, int size) { if (!dbg->reg) { return false; } int arena_size; ut8 *arena = r_reg_get_bytes (dbg->reg, R_REG_TYPE_ALL, &arena_size); if (!arena) { eprintf ("Could not retrieve the register arena!\n"); return false; } int ret = windbg_write_reg (wctx, arena, arena_size); free (arena); return ret; }
R_API int r_debug_reg_sync(RDebug *dbg, int type, int write) { int i, size; if (!dbg || !dbg->reg || !dbg->h) return R_FALSE; // Theres no point in syncing a dead target if (r_debug_is_dead (dbg)) return R_FALSE; // Check if the functions needed are available if (write && !dbg->h->reg_write) return R_FALSE; if (!write && !dbg->h->reg_read) return R_FALSE; // Sync all the types sequentially if asked i = (type == R_REG_TYPE_ALL) ? R_REG_TYPE_GPR : type; do { if (write) { ut8 *buf = r_reg_get_bytes (dbg->reg, i, &size); if (!buf || !dbg->h->reg_write (dbg, i, buf, size)) { if (i==0) eprintf ("r_debug_reg: error writing registers %d to %d\n", i, dbg->pid); return R_FALSE; } } else { //int bufsize = R_MAX (1024, dbg->reg->size*2); // i know. its hacky int bufsize = dbg->reg->size; ut8 *buf = malloc (bufsize); if (!buf) return R_FALSE; //we have already checked dbg->h and dbg->h->reg_read above size = dbg->h->reg_read (dbg, i, buf, bufsize); // we need to check against zero because reg_read can return R_FALSE if (!size) { eprintf ("r_debug_reg: error reading registers\n"); free (buf); return R_FALSE; } else r_reg_set_bytes (dbg->reg, i, buf, R_MIN(size, bufsize)); free (buf); } // DO NOT BREAK R_REG_TYPE_ALL PLEASE // break; // Continue the syncronization or just stop if it was asked only for a single type of regs } while ((type==R_REG_TYPE_ALL) && (i++ < R_REG_TYPE_LAST)); return R_TRUE; }
static int r_debug_gdb_reg_read(RDebug *dbg, int type, ut8 *buf, int size) { int copy_size; int buflen = 0; check_connection (dbg); gdbr_read_registers (desc); if (!desc) { return -1; } // read the len of the current area free (r_reg_get_bytes (dbg->reg, type, &buflen)); if (size < desc->data_len) { eprintf ("r_debug_gdb_reg_read: small buffer %d vs %d\n", (int)size, (int)desc->data_len); // return -1; } copy_size = R_MIN (desc->data_len, size); buflen = R_MAX (desc->data_len, buflen); if (reg_buf) { // if (buf_size < copy_size) { //desc->data_len) { if (buflen > buf_size) { //copy_size) { ut8* new_buf = realloc (reg_buf, buflen); if (!new_buf) { return -1; } reg_buf = new_buf; buf_size = buflen; } } else { reg_buf = calloc (buflen, 1); if (!reg_buf) { return -1; } buf_size = buflen; } memset ((void*)(volatile void*)buf, 0, size); memcpy ((void*)(volatile void*)buf, desc->data, R_MIN (copy_size, size)); memset ((void*)(volatile void*)reg_buf, 0, buflen); memcpy ((void*)(volatile void*)reg_buf, desc->data, copy_size); #if 0 int i; //for(i=0;i<168;i++) { for(i=0;i<copy_size;i++) { if (!(i%16)) printf ("\n0x%08x ", i); printf ("%02x ", buf[i]); //(ut8)desc->data[i]); } printf("\n"); #endif return desc->data_len; }
R_API int r_debug_reg_sync(RDebug *dbg, int type, int write) { int i, size; if (!dbg || !dbg->reg || !dbg->h) return R_FALSE; // Theres no point in syncing a dead target if (r_debug_is_dead(dbg)) return R_FALSE; // Check if the functions needed are available if (write && !dbg->h->reg_write) return R_FALSE; if (!write && !dbg->h->reg_read) return R_FALSE; // Sync all the types sequentially if asked i = (type == R_REG_TYPE_ALL) ? R_REG_TYPE_GPR : type; do { if (write) { ut8 *buf = r_reg_get_bytes (dbg->reg, i, &size); if (!buf || !dbg->h->reg_write (dbg, i, buf, size)) { eprintf ("r_debug_reg: error writing registers\n"); return R_FALSE; } } else { // TODO : Get an exact size of the profile ut8 buf[2048]; size = dbg->h->reg_read (dbg, i, buf, sizeof (buf)); if (!size) { eprintf ("r_debug_reg: error reading registers\n"); return R_FALSE; } r_reg_set_bytes (dbg->reg, i, buf, size); } // Continue the syncronization or just stop if it was asked only for a single type of regs } while(i++ < R_REG_TYPE_LAST && type != R_REG_TYPE_ALL); return R_TRUE; }
R_API int r_debug_reg_sync(RDebug *dbg, int type, int write) { ut8 buf[4096]; // XXX hacky! int next, size, ret = R_FALSE; if (!dbg || !dbg->reg || dbg->pid == -1) return R_FALSE; if (type == -1) { type = R_REG_TYPE_GPR; next = R_REG_TYPE_DRX; } else next = 0; repeat: if (write) { if (dbg && dbg->h && dbg->h->reg_write) { ut8 *buf = r_reg_get_bytes (dbg->reg, type, &size); if (!dbg->h->reg_write (dbg, type, buf, sizeof (buf))) eprintf ("r_debug_reg: error writing registers\n"); else ret = R_TRUE; } //else eprintf ("r_debug_reg: cannot set registers\n"); } else { /* read registers from debugger backend to dbg->regs */ if (dbg && dbg->h && dbg->h->reg_read) { size = dbg->h->reg_read (dbg, type, buf, sizeof (buf)); if (size == 0) { eprintf ("r_debug_reg: error reading registers pid=%d\n", dbg->pid); } else { ret = r_reg_set_bytes (dbg->reg, type, buf, size); } } //else eprintf ("r_debug_reg: cannot read registers\n"); } if (next) { type = next; switch (next) { case R_REG_TYPE_FPU: next = R_REG_TYPE_DRX; break; case R_REG_TYPE_DRX: next = 0; break; default: next = 0; break; } goto repeat; } return ret; }
static int r_debug_wind_reg_write(RDebug *dbg, int type, const ut8 *buf, int size) { (void)buf; (void)size; ut8 *arena; int arena_size; int ret; if (!dbg->reg) return R_FALSE; arena = r_reg_get_bytes (dbg->reg, R_REG_TYPE_ALL, &arena_size); if (!arena) { eprintf ("Could not retrieve the register arena!\n"); return R_FALSE; } ret = wind_write_reg(wctx, arena, arena_size); free (arena); return ret; }
static int r_debug_qnx_reg_read (RDebug *dbg, int type, ut8 *buf, int size) { int copy_size; int buflen = 0; if (!desc) { return -1; } int len = qnxr_read_registers (desc); if (len <= 0) return -1; // read the len of the current area free (r_reg_get_bytes (dbg->reg, type, &buflen)); if (size < len) { eprintf ("r_debug_qnx_reg_read: small buffer %d vs %d\n", (int)size, (int)len); } copy_size = R_MIN (len, size); buflen = R_MAX (len, buflen); if (reg_buf) { if (buf_size < copy_size) { ut8 *new_buf = realloc (reg_buf, copy_size); if (!new_buf) return -1; reg_buf = new_buf; buflen = copy_size; buf_size = len; } } else { reg_buf = calloc (buflen, 1); if (!reg_buf) return -1; buf_size = buflen; } memset ((void *)(volatile void *) buf, 0, size); memcpy ((void *)(volatile void *) buf, desc->recv.data, copy_size); memset ((void *)(volatile void *) reg_buf, 0, buflen); memcpy ((void *)(volatile void *) reg_buf, desc->recv.data, copy_size); return len; }
R_API int r_debug_reg_sync(RDebug *dbg, int type, int write) { int i, n, size; if (!dbg || !dbg->reg || !dbg->h) { return false; } // Theres no point in syncing a dead target if (r_debug_is_dead (dbg)) { return false; } // Check if the functions needed are available if (write && !dbg->h->reg_write) { return false; } if (!write && !dbg->h->reg_read) { return false; } // Sync all the types sequentially if asked i = (type == R_REG_TYPE_ALL)? R_REG_TYPE_GPR: type; // Check to get the correct arena when using @ into reg profile (arena!=type) // if request type is positive and the request regset dont have regs if (i >= R_REG_TYPE_GPR && dbg->reg->regset[i].regs && !dbg->reg->regset[i].regs->length) { // seek into the other arena for redirections. for (n = R_REG_TYPE_GPR; n < R_REG_TYPE_LAST; n++) { // get regset mask int mask = dbg->reg->regset[n].maskregstype; // convert request arena to mask value int v = ((int)1 << i); // skip checks on same request arena and check if this arena have inside the request arena type if (n != i && (mask & v)) { //eprintf(" req = %i arena = %i mask = %x search = %x \n", i, n, mask, v); //eprintf(" request arena %i found at arena %i\n", i, n ); // if this arena have the request arena type, force to use this arena. i = n; break; } } } do { if (write) { ut8 *buf = r_reg_get_bytes (dbg->reg, i, &size); if (!buf || !dbg->h->reg_write (dbg, i, buf, size)) { if (!i) { eprintf ("r_debug_reg: error writing " "registers %d to %d\n", i, dbg->tid); } free (buf); return false; } free (buf); } else { // int bufsize = R_MAX (1024, dbg->reg->size*2); // i know. its hacky int bufsize = dbg->reg->size; //int bufsize = dbg->reg->regset[i].arena->size; if (bufsize > 0) { ut8 *buf = calloc (1 + 1, bufsize); if (!buf) { return false; } //we have already checked dbg->h and dbg->h->reg_read above size = dbg->h->reg_read (dbg, i, buf, bufsize); // we need to check against zero because reg_read can return false if (size > 0) { r_reg_set_bytes (dbg->reg, i, buf, size); //R_MIN (size, bufsize)); // free (buf); // return true; } free (buf); } } // DO NOT BREAK R_REG_TYPE_ALL PLEASE // break; // Continue the syncronization or just stop if it was asked only for a single type of regs i++; } while ((type == R_REG_TYPE_ALL) && (i < R_REG_TYPE_LAST)); return true; }