static void handle_msg( mol_dgram_t *dg ) { cmd_entry_t *ce = sv.cmd_root; int i, val; switch( dg->what ) { case kMDG_connect: printm("Debugger attached\n"); sv.dbg_attached = 1; send_dgram( sv.sock, kMDG_connect ); send_mregs(); send_dgram( sv.sock, kMDG_refresh_debugger ); /* send debugger commands */ for( ce=sv.cmd_root; ce; ce=ce->next ) { int s = strlen( ce->cmdname ) + 1; int t = strlen( ce->help ) + 1; char *b = malloc( s + t ); strcpy( b, ce->cmdname ); strcpy( b+s, ce->help ); send_dgram_buf2( sv.sock, kMDG_dbg_cmd, b, s+t, s, -1 /*dummy*/ ); free( b ); } break; case kMDG_disconnect: sv.dbg_attached = 0; close_sock(); printm("Debugger detached\n"); break; case kMDG_mregs: send_mregs(); break; case kMDG_write_mregs: receive_mregs( (mac_regs_t*)dg->data ); break; case kMDG_read_dpage: { /* ea, context, data_access */ char buf[0x2000]; dg->p0 &= ~0xfff; restore_breakpoints(); for( i=0; i<2; i++ ) { char *lvptr; if( ea_to_lvptr( dg->p0 + i*0x1000, dg->p1, &lvptr, dg->p2 ) ) memset( buf+i*0x1000, 0xDE, 0x1000 ); else memcpy( buf+i*0x1000, lvptr, 0x1000 ); } setup_breakpoints(); send_dgram_buf( sv.sock, kMDG_dpage_data, buf, 0x2000 ); break; } case kMDG_in_ppc_mode: /* flag */ sv.in_ppc_mode = dg->p0; break; case kMDG_debug_action: /* action (go, single-step, etc.) */ debug_action( dg->p0 ); break; case kMDG_add_breakpoint: /* addr, flags, data */ add_breakpoint( dg->p0, dg->p1, dg->p2 ); break; case kMDG_is_breakpoint: { /* mvptr */ char breakbuf[ BREAK_BUF_SIZE ]; for(i=0; i<BREAK_BUF_SIZE; i++ ){ if( !is_breakpoint( dg->p0 + i*4, &breakbuf[i] ) ) breakbuf[i] = 0; } send_dgram_buf1( sv.sock, kMDG_is_breakpoint, breakbuf, BREAK_BUF_SIZE, dg->p0 ); break; } case kMDG_dbg_cmd: val = do_dbg_cmd( (remote_cmd_t*)dg->data ); send_dgram1( sv.sock, kMDG_result, val ); break; default: printm("Unknown dbg-message %d received\n", dg->what ); break; } }
void debugger_proc(pid_t child_proc, struct execute_context *ctx) { /* about child process */ int child_stat; kern_return_t kret; mach_port_t task; int wait_cnt = 0; char **args = ctx->passing_args; /* related analysys of target process binary. */ int i; int nsym; int text_section; uint64_t text_section_offset; uint64_t text_section_size; uint64_t text_section_vmaddr; struct symbol_info *psymbol_table; int init = 0; struct breakpoint_entry top; int stack_depth = 0; /* error check */ if (child_proc == 0 || child_proc == -1) return; /* initialize */ memset(&top, 0x00, sizeof(top)); /* open the port (do as an administrator) */ kret = task_for_pid(mach_task_self(), child_proc, &task); if (kret != KERN_SUCCESS) { fprintf(stderr, "task_for_pid() failed\n"); fprintf(stderr, "%s\n", mach_error_string(kret)); exit(0); } fprintf(stderr, "[Tracer] child_proc: %d\n", child_proc); /* main loop */ while(waitpid(child_proc, &child_stat, WUNTRACED)) { /* {{{ */ char buffer[128]; char w_buf[128]; w_buf[0] = 0x90; /* nop */ if (WIFEXITED(child_stat)) { /* Child Process Terminated */ fprintf(stderr, "[Tracer] Process :%d Terminated\n", child_proc); return; } memset(buffer, 0x00, 128); if(wait_cnt == 0) { /* The First time trapped {{{ */ /* -- The debugee program has not been expanded.-- */ /* -- lookup named symbol -- */ struct file_info bininfo; ud_t ud_obj; uint64_t previous_eip; uint64_t func_start_addr; uint64_t func_end_addr; nsym = get_func_table(args[0], &psymbol_table, &text_section, &text_section_offset, &text_section_size, &text_section_vmaddr); debug_printf("nsym: %d\n", nsym); debug_printf("text section = %d\n", text_section); debug_printf("text section offset: 0x%llx\n", text_section_offset); debug_printf("text section size: 0x%llx\n", text_section_size); debug_printf("text section vmaddr: 0x%llx\n", text_section_vmaddr); qsort(psymbol_table, nsym, sizeof(struct symbol_info), symbolinfo_comp); /* XXX for debugging */ /*display_symbol_table(psymbol_table, nsym); */ /* code analysys */ map_binary(args[0], &bininfo); ud_init(&ud_obj); ud_set_input_buffer(&ud_obj, bininfo.top + text_section_offset, text_section_size); ud_set_mode(&ud_obj, 64); previous_eip = text_section_vmaddr; /* set breakpoint at the entry and exit points of functions */ for(i = 0; i < nsym; i++) { /* Set breakpoints {{{ */ if (is_exclude_func(psymbol_table + i) == 1) { continue; } /* 1, specifying the region of the function */ func_start_addr = psymbol_table[i].nlist64.n_value; if (i != nsym - 1) { /* next section's entry point - 1 */ func_end_addr = psymbol_table[i + 1].nlist64.n_value; } else { func_end_addr = text_section_vmaddr + text_section_size + 1; } printf("%s: 0x%llx --> 0x%llx\n", psymbol_table[i].name, func_start_addr, func_end_addr); /* if (strstr(psymbol_table[i].name, "main") != NULL) { __asm__("int3"); } */ psymbol_table[i].ret_address_num = 0; previous_eip = ud_obj.pc + text_section_vmaddr; while(ud_disassemble(&ud_obj) && previous_eip < func_start_addr) { previous_eip = ud_obj.pc + text_section_vmaddr; } while(ud_disassemble(&ud_obj) && previous_eip < func_end_addr) { if (func_start_addr <= previous_eip && ud_obj.mnemonic == UD_Iret) { set_breakpoint(task, previous_eip, &top); psymbol_table[i].ret_inst_address[ psymbol_table[i].ret_address_num ] = previous_eip; psymbol_table[i].ret_address_num++; } previous_eip = ud_obj.pc + text_section_vmaddr; } /* if (0 < psymbol_table[i].ret_address_num) { set_breakpoint(task, psymbol_table[i].nlist64.n_value, &top); } */ set_breakpoint(task, psymbol_table[i].nlist64.n_value, &top); /* }}} */ } debug_printf("break point insert\n"); unmap_binary(&bininfo); /* }}} */ } else { /* {{{ */ /* break point */ /* 1, Get current address from RIP value. * 2, Find current function name by EIP, and Logging. * 3, Substitute original instruction code for current break point code(0x90). * 4, Decrement EIP value. * 5, Execute only one op-code. * 6, Substitute 0x90 for oroginal code (located in entrance of function). * */ uint64_t rip; read_process_register_64(task, RIP, &rip); if (is_breakpoint(rip - 1, &top) == 1) { stack_depth = breakpoint_handler(task, rip - 1, psymbol_table, nsym, stack_depth); write_process_register_64(task, RIP, RELATIVE_VAL, -1); disable_breakpoint(task, rip - 1, &top); ptrace(PT_STEP, child_proc, (caddr_t)1, 0); set_breakpoint(task, rip - 1, &top); } /* }}} */ } wait_cnt++; ptrace(PT_CONTINUE, child_proc, (caddr_t)1, 0); } /* }}} */ }