/* debugbochs - LGPL - Copyright 2016 - SkUaTeR */ #include #include #include static bool bCapturaRegs = true; static bool bStep = false; static bool bBreak = false; static bool bAjusta = true; static char *saveRegs; static ut64 ripStop = 0LL; typedef struct { libbochs_t desc; } RIOBochs; static libbochs_t *desc = NULL; static int r_debug_bochs_breakpoint (RBreakpointItem *bp, int set, void *user) { char cmd[64]; char num[4]; char addr[19]; char bufcmd[100]; ut64 a; int n,i,lenRec; //eprintf ("bochs_breakpoint\n"); if (!bp) return false; if (set) { //eprintf("[set] bochs_breakpoint %016"PFMT64x"\n",bp->addr); sprintf (cmd, "lb 0x%x", (ut32)bp->addr); bochs_send_cmd (desc, cmd, true); bCapturaRegs = true; } else { //eprintf("[unset] bochs_breakpoint %016"PFMT64x"\n",bp->addr); /* Num Type Disp Enb Address 1 lbreakpoint keep y 0x0000000000007c00 2 lbreakpoint keep y 0x0000000000007c00 */ bochs_send_cmd (desc,"blist",true); lenRec = strlen (desc->data); a = -1; n = 0; if (!strncmp (desc->data, "Num Type", 8)) { i = 37; do { if (desc->data[i + 24] == 'y') { strncpy(num, &desc->data[i], 3); num[3] = 0; strncpy(addr, &desc->data[i + 28], 18); addr[18] = 0; n = r_num_get (NULL,num); a = r_num_get (NULL,addr); //eprintf("parseado %x %016"PFMT64x"\n",n,a); if (a == bp->addr) break; } i += 48; } while (desc->data[i] != '<' && iaddr) { snprintf (bufcmd, sizeof (bufcmd), "d %i", n); //eprintf("[unset] Break point localizado indice = %x (%x) %s \n",n,(DWORD)a,bufcmd); bochs_send_cmd (desc, bufcmd, true); } } return true; } static int r_debug_bochs_reg_read(RDebug *dbg, int type, ut8 *buf, int size) { char strReg[19]; char regname[4]; char strBase[19]; char strLimit[19]; int i = 0, pos = 0, lenRec = 0; ut64 val = 0, valRIP = 0; //, posRIP = 0; //eprintf ("bochs_reg_read\n"); if (bCapturaRegs == true) { bochs_send_cmd (desc, "regs", true); //r14: 00000000_00000000 r15: 00000000_00000000 //rip: 00000000_0000e07b //eflags 0x00000046: id vip vif ac vm rf nt IOPL=0 of df if tf sf ZF af PF cf //return -1; pos = 0x78; lenRec = strlen (desc->data); while (desc->data[i] != 0 && i < lenRec -4 ) { if ( (desc->data[i] == (ut8)'r' && desc->data[i + 3] == (ut8)':')) { strncpy (regname, &desc->data[i], 3); regname[3] = 0; strncpy (&strReg[2], &desc->data[i + 5], 8); strncpy (&strReg[10], &desc->data[i + 14], 8); strReg[0]='0'; strReg[1]='x'; strReg[18] = 0; i += 22; val = r_num_get (NULL, strReg); // eprintf("parseado %s = %s valx64 = %016"PFMT64x"\n", regname, strReg,val); memcpy (&buf[pos], &val, 8); // guardamos la posicion del rip y su valor para ajustarlo al obtener el CS if (!strncmp (regname, "rip", 3)) { // UNUSED posRIP = pos; valRIP = val; } pos+= 8; } else i++; } bochs_send_cmd (desc, "info cpu", true); if (strstr (desc->data,"PC_32")) { bAjusta = true; //eprintf("[modo PC_32]\n"); } else if (strstr (desc->data,"PC_80")) { bAjusta = false; //eprintf("[modo PC_80]\n"); } else if (strstr (desc->data,"PC_64")) { bAjusta = false; //eprintf("[modo PC_64]\n"); } else eprintf ("[unknown mode]\n%s\n",desc->data); /* es:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7 Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed cs:0xf000, dh=0xff0093ff, dl=0x0000ffff, valid=7 Data segment, base=0xffff0000, limit=0x0000ffff, Read/Write, Accessed ss:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7 Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed ds:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7 Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7 Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7 Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1 tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1 gdtr:base=0x0000000000000000, limit=0xffff idtr:base=0x0000000000000000, limit=0xffff */ bochs_send_cmd (desc, "sreg", true); pos = 0x38; char * s [] = { "es:0x", "cs:0x","ss:0x","ds:0x","fs:0x","gs:0x",0}; const char *x; int n; for (n = 0; s[n] != 0; n++) { if ((x = strstr (desc->data,s[n]))) { strncpy (&strReg[0], x+3, 7); strReg[6] = 0; val = r_num_get (NULL, strReg); strncpy (regname, s[n], 2); regname[2] = 0; if ((x = strstr (x, "base="))) { strncpy (strBase, x + 5, 10); strBase[10] = 0; if ((x = strstr (x, "limit="))) { strncpy (strLimit, x + 6, 10); strLimit[10] = 0; } } //eprintf("%s localizado %s %04x base = %s limit = %s\n",regname,strReg,(WORD)val,strBase,strLimit); memcpy (&buf[pos], &val, 2); pos += 2; if (bAjusta) { if (!strncmp (regname,"cs",2)) { valRIP += (val*0x10); // desplazamos CS y lo aƱadimos a RIP //eprintf("%016"PFMT64x"\n",valRIP); } } } } // Cheat para evitar traducciones de direcciones if (ripStop != 0) { memcpy (&buf[0], &ripStop, 8); } else { memcpy (&buf[0], &valRIP, 8); // guardamos el valor cs:ip en el registro virtual "vip" } //eprintf("guardando regs procesados%x\n",size); memcpy (saveRegs,buf,size); bCapturaRegs = false; //eprintf("bochs_reg_read\n"); } else { memcpy (buf, saveRegs, size); //eprintf("[cache] bochs_reg_read\n"); } return size; } static int r_debug_bochs_reg_write(RDebug *dbg, int type, const ut8 *buf, int size) { //eprintf("bochs_reg_write\n"); return -1; } void map_free(RDebugMap *map) { free (map->name); free (map); } static RList *r_debug_bochs_map_get(RDebug* dbg) { //TODO //eprintf("bochs_map_getdebug:\n"); RDebugMap *mr; RList *list = r_list_newf ((RListFree)map_free); if (!list) return NULL; mr = R_NEW0 (RDebugMap); if (!mr) { r_list_free (list); return NULL; } mr->name = strdup ("fake"); mr->addr = 0; mr->addr_end = UT32_MAX; mr->size = UT32_MAX; mr->perm = 0; mr->user = 0; r_list_append (list, mr); return list; } static int r_debug_bochs_step(RDebug *dbg) { //eprintf ("bochs_step\n"); bochs_send_cmd (desc,"s",true); bCapturaRegs = true; bStep = true; return true; } static int r_debug_bochs_continue(RDebug *dbg, int pid, int tid, int sig) { //eprintf ("bochs_continue:\n"); bochs_send_cmd (desc, "c", false); bCapturaRegs = true; bBreak = false; return true; } static void bochs_debug_break(void *u) { eprintf("bochs_debug_break: Sending break...\n"); bochs_cmd_stop (desc); bBreak = true; } static int r_debug_bochs_wait(RDebug *dbg, int pid) { char strIP[19]; int i = 0; const char *x; char *ini = 0, *fin = 0; //eprintf ("bochs_wait:\n"); if (bStep) { bStep = false; } else { r_cons_break (bochs_debug_break, dbg); i = 500; do { bochs_wait (desc); if (bBreak) { if (desc->data[0]) { eprintf ("ctrl+c %s\n", desc->data); bBreak = false; break; } i--; if (!i) { bBreak = false; eprintf ("empty ctrl+c.\n"); break; } } else if (desc->data[0]) { //eprintf("stop on breakpoint%s\n",desc->data); break; } } while(1); } //eprintf ("bochs_wait: loop done\n"); i = 0; // Next at t=394241428 // (0) [0x000000337635] 0020:0000000000337635 (unk. ctxt): add eax, esi ; 03c6 ripStop = 0; if ((x = strstr (desc->data, "Next at"))) { if ((ini = strstr (x, "[0x"))) { if ((fin = strstr (ini,"]"))) { int len = fin - ini - 1; strncpy (strIP, ini+1, len); strIP[len] = 0; //eprintf(" parada EIP = %s\n",strIP); ripStop = r_num_get (NULL, strIP); } } } desc->data[0] = 0; return true; } static int r_debug_bochs_stop(RDebug *dbg) { //eprintf("bochs_stop:\n"); //RIOBdescbg *o = dbg->iob.io->desc->data; //BfvmCPU *c = o->bfvm; //c->breaked = true; return true; } static int r_debug_bochs_attach(RDebug *dbg, int pid) { RIODesc *d = dbg->iob.io->desc; //eprintf ("bochs_attach:\n"); dbg->swstep = false; if (d && d->plugin && d->plugin->name && d->data) { if (!strcmp ("bochs", d->plugin->name)) { RIOBochs *g = d->data; //int arch = r_sys_arch_id (dbg->arch); // int bits = dbg->anal->bits; if (( desc = &g->desc )) { eprintf("bochs attach: ok\n"); saveRegs = malloc(1024); bCapturaRegs = true; bStep = false; bBreak = false; } } } return true; } static int r_debug_bochs_detach(RDebug *dbg, int pid) { //eprintf ("bochs_detach:\n"); free (saveRegs); return true; } static const char *r_debug_bochs_reg_profile(RDebug *dbg) { int bits = dbg->anal->bits; if (bits == 16 || bits == 32 || bits == 64) { return strdup ( "=PC csip\n" "=SP rsp\n" "=BP rbp\n" "=A0 rax\n" "=A1 rbx\n" "=A2 rcx\n" "=A3 rdi\n" "seg es 2 0x038 0 \n" "seg cs 2 0x03A 0 \n" "seg ss 2 0x03C 0 \n" "seg ds 2 0x03E 0 \n" "seg fs 2 0x040 0 \n" "seg gs 2 0x042 0 \n" "gpr rax 8 0x078 0 \n" "gpr eax 4 0x078 0 \n" "gpr ax 2 0x078 0 \n" "gpr al 1 0x078 0 \n" "gpr rcx 8 0x080 0 \n" "gpr ecx 4 0x080 0 \n" "gpr cx 2 0x080 0 \n" "gpr cl 1 0x078 0 \n" "gpr rdx 8 0x088 0 \n" "gpr edx 4 0x088 0 \n" "gpr dx 2 0x088 0 \n" "gpr dl 1 0x088 0 \n" "gpr rbx 8 0x090 0 \n" "gpr ebx 4 0x090 0 \n" "gpr bx 2 0x090 0 \n" "gpr bl 1 0x090 0 \n" "gpr rsp 8 0x098 0 \n" "gpr esp 4 0x098 0 \n" "gpr sp 2 0x098 0 \n" "gpr spl 1 0x098 0 \n" "gpr rbp 8 0x0A0 0 \n" "gpr ebp 4 0x0A0 0 \n" "gpr bp 2 0x0A0 0 \n" "gpr bpl 1 0x0A0 0 \n" "gpr rsi 8 0x0A8 0 \n" "gpr esi 4 0x0A8 0 \n" "gpr si 2 0x0A8 0 \n" "gpr sil 1 0x0A8 0 \n" "gpr rdi 8 0x0B0 0 \n" "gpr edi 4 0x0B0 0 \n" "gpr di 2 0x0B0 0 \n" "gpr dil 1 0x0B0 0 \n" "gpr r8 8 0x0B8 0 \n" "gpr r8d 4 0x0B8 0 \n" "gpr r8w 2 0x0B8 0 \n" "gpr r8b 1 0x0B8 0 \n" "gpr r9 8 0x0C0 0 \n" "gpr r9d 4 0x0C0 0 \n" "gpr r9w 2 0x0C0 0 \n" "gpr r9b 1 0x0C0 0 \n" "gpr r10 8 0x0C8 0 \n" "gpr r10d 4 0x0C8 0 \n" "gpr r10w 2 0x0C8 0 \n" "gpr r10b 1 0x0C8 0 \n" "gpr r11 8 0x0D0 0 \n" "gpr r11d 4 0x0D0 0 \n" "gpr r11w 2 0x0D0 0 \n" "gpr r11b 1 0x0D0 0 \n" "gpr r12 8 0x0D8 0 \n" "gpr r12d 4 0x0D8 0 \n" "gpr r12w 2 0x0D8 0 \n" "gpr r12b 1 0x0D8 0 \n" "gpr r13 8 0x0E0 0 \n" "gpr r13d 4 0x0E0 0 \n" "gpr r13w 2 0x0E0 0 \n" "gpr r13b 1 0x0E0 0 \n" "gpr r14 8 0x0E8 0 \n" "gpr r14d 4 0x0E8 0 \n" "gpr r14w 2 0x0E8 0 \n" "gpr r14b 1 0x0E8 0 \n" "gpr r15 8 0x0F0 0 \n" "gpr r15d 4 0x0F0 0 \n" "gpr r15w 2 0x0F0 0 \n" "gpr r15b 1 0x0F0 0 \n" "gpr rip 8 0x0F8 0 \n" "gpr eip 4 0x0F8 0 \n" "gpr csip 8 0x000 0 \n" /* "gpr mxcsr 4 0x034 0 \n" "seg cs 2 0x038 0 \n" "seg ds 2 0x03A 0 \n" "seg es 2 0x03C 0 \n" "seg fs 2 0x03E 0 \n" "seg gs 2 0x040 0 \n" "seg ss 2 0x042 0 \n" "gpr eflags 4 0x044 0 \n" "drx dr0 8 0x048 0 \n" "drx dr1 8 0x050 0 \n" "drx dr2 8 0x058 0 \n" "drx dr3 8 0x060 0 \n" "drx dr6 8 0x068 0 \n" "drx dr7 8 0x070 0 \n" "gpr rax 8 0x078 0 \n" "gpr eax 4 0x078 0 \n" "gpr ax 2 0x078 0 \n" "gpr al 1 0x078 0 \n" "gpr rcx 8 0x080 0 \n" "gpr ecx 4 0x080 0 \n" "gpr cx 2 0x080 0 \n" "gpr cl 1 0x078 0 \n" "gpr rdx 8 0x088 0 \n" "gpr edx 4 0x088 0 \n" "gpr dx 2 0x088 0 \n" "gpr dl 1 0x088 0 \n" "gpr rbx 8 0x090 0 \n" "gpr ebx 4 0x090 0 \n" "gpr bx 2 0x090 0 \n" "gpr bl 1 0x090 0 \n" "gpr rsp 8 0x098 0 \n" "gpr esp 4 0x098 0 \n" "gpr sp 2 0x098 0 \n" "gpr spl 1 0x098 0 \n" "gpr rbp 8 0x0A0 0 \n" "gpr ebp 4 0x0A0 0 \n" "gpr bp 2 0x0A0 0 \n" "gpr bpl 1 0x0A0 0 \n" "gpr rsi 8 0x0A8 0 \n" "gpr esi 4 0x0A8 0 \n" "gpr si 2 0x0A8 0 \n" "gpr sil 1 0x0A8 0 \n" "gpr rdi 8 0x0B0 0 \n" "gpr edi 4 0x0B0 0 \n" "gpr di 2 0x0B0 0 \n" "gpr dil 1 0x0B0 0 \n" "gpr r8 8 0x0B8 0 \n" "gpr r8d 4 0x0B8 0 \n" "gpr r8w 2 0x0B8 0 \n" "gpr r8b 1 0x0B8 0 \n" "gpr r9 8 0x0C0 0 \n" "gpr r9d 4 0x0C0 0 \n" "gpr r9w 2 0x0C0 0 \n" "gpr r9b 1 0x0C0 0 \n" "gpr r10 8 0x0C8 0 \n" "gpr r10d 4 0x0C8 0 \n" "gpr r10w 2 0x0C8 0 \n" "gpr r10b 1 0x0C8 0 \n" "gpr r11 8 0x0D0 0 \n" "gpr r11d 4 0x0D0 0 \n" "gpr r11w 2 0x0D0 0 \n" "gpr r11b 1 0x0D0 0 \n" "gpr r12 8 0x0D8 0 \n" "gpr r12d 4 0x0D8 0 \n" "gpr r12w 2 0x0D8 0 \n" "gpr r12b 1 0x0D8 0 \n" "gpr r13 8 0x0E0 0 \n" "gpr r13d 4 0x0E0 0 \n" "gpr r13w 2 0x0E0 0 \n" "gpr r13b 1 0x0E0 0 \n" "gpr r14 8 0x0E8 0 \n" "gpr r14d 4 0x0E8 0 \n" "gpr r14w 2 0x0E8 0 \n" "gpr r14b 1 0x0E8 0 \n" "gpr r15 8 0x0F0 0 \n" "gpr r15d 4 0x0F0 0 \n" "gpr r15w 2 0x0F0 0 \n" "gpr r15b 1 0x0F0 0 \n" "gpr rip 8 0x0F8 0 \n" "gpr cf .1 .544 0 carry\n" "gpr pf .1 .546 0 parity\n" "gpr af .1 .548 0 adjust\n" "gpr zf .1 .550 0 zero\n" "gpr sf .1 .551 0 sign\n" "gpr tf .1 .552 0 trap\n" "gpr if .1 .553 0 interrupt\n" "gpr df .1 .554 0 direction\n" "gpr of .1 .555 0 overflow\n" */ ); } return NULL; } RDebugPlugin r_debug_plugin_bochs = { .name = "bochs", .license = "LGPL3", .arch = "x86", .bits = R_SYS_BITS_16 | R_SYS_BITS_32 | R_SYS_BITS_64, .step = r_debug_bochs_step, .cont = r_debug_bochs_continue, .attach = &r_debug_bochs_attach, .detach = &r_debug_bochs_detach, .canstep = 1, .stop = &r_debug_bochs_stop, .wait = &r_debug_bochs_wait, .map_get = r_debug_bochs_map_get, .breakpoint = &r_debug_bochs_breakpoint, .reg_read = &r_debug_bochs_reg_read, .reg_write = &r_debug_bochs_reg_write, .reg_profile = (void *)r_debug_bochs_reg_profile, }; #ifndef CORELIB struct r_lib_struct_t radare_plugin = { .type = R_LIB_TYPE_DBG, .data = &r_debug_plugin_bochs, .version = R2_VERSION }; #endif