//-------------------------------------------------------------------------- bool win32_debmod_t::set_debug_hook(ea_t base) { // the debug hook for borland is located at the very beginning of // the program's text segment, with a clear signature before peheader_t pe; ea_t peoff = get_pe_header(base, &pe); if ( peoff == BADADDR ) return false; ea_t text = base + pe.text_start; uchar buf[4096]; if ( _read_memory(text, buf, sizeof(buf)) != sizeof(buf) ) return false; ssize_t bcc_hook_off = find_bcc_sign(buf, sizeof(buf)); if ( bcc_hook_off == -1 ) return false; uint32 bcc_hook; if ( _read_memory(text+bcc_hook_off, &bcc_hook, 4) != 4 ) return false; // now the bcc_hook might be already relocated or not. // it seems that vista loads files without relocating them for // the 'open file' dialog box. This is an heuristic rule: if ( bcc_hook < base + pe.text_start || bcc_hook > base + pe.imagesize ) return false; const uint32 active_hook = 2; // borland seems to want this number return _write_memory(bcc_hook, &active_hook, 4) == 4; }
static unsigned char save_breakpoint_data(seL4_Word addr) { // Read data we will write over unsigned char data[2]; /*? me.from_instance.name ?*/_read_memory(addr, BREAKPOINT_INSTRUCTION_SIZE , data); unsigned char next_breakpoint = free_breakpoint_head; free_breakpoint_head = breakpoints[next_breakpoint].saved_data[0]; memcpy(breakpoints[next_breakpoint].saved_data, data, BREAKPOINT_INSTRUCTION_SIZE); return next_breakpoint; }
static void handle_breakpoint(void) { unsigned char inst_data[BREAKPOINT_INSTRUCTION_SIZE]; /*? me.from_instance.name ?*/_read_memory(reg_pc, BREAKPOINT_INSTRUCTION_SIZE, (unsigned char *) &inst_data); if (inst_data[BREAKPOINT_INSTRUCTION_INDEX] == BREAKPOINT_INSTRUCTION) { curr_breakpoint = inst_data[BREAKPOINT_NUM_INDEX]; if (DEBUG_PRINT) printf("Breakpoint %d\n", curr_breakpoint); restore_breakpoint_data(curr_breakpoint); } }
//-------------------------------------------------------------------------- bool win32_debmod_t::add_thread_areas( HANDLE process_handle, thid_t tid, images_t &thread_areas, images_t &class_areas) { thread_info_t *ti = threads.get(tid); if ( ti == NULL ) return false; // This structure is specific to NT, but stack related records are Win9X compatible _NT_TIB tib; ea_t ea_tib = EA_T(ti->lpThreadLocalBase); if ( _read_memory(ea_tib, &tib, sizeof(tib)) != sizeof(tib) ) // read the TIB return false; // additional test: we verify that TIB->Self contains the TIB's linear address if ( EA_T(tib.Self) != ea_tib ) return false; // add TIB area char name[MAXSTR]; qsnprintf(name, sizeof(name), "TIB[%08X]", tid); // we suppose the whole page is reserved for the TIB image_info_t ii_tib(this, ea_tib, system_teb_size, name); thread_areas.insert(std::make_pair(ii_tib.base, ii_tib)); // add stack area - we also verify it is valid by analyzing SP if ( EA_T(tib.StackLimit) > ti->ctx.Esp || ti->ctx.Esp >= EA_T(tib.StackBase) ) return false; asize_t size = EA_T(tib.StackBase) - EA_T(tib.StackLimit); qsnprintf(name, sizeof(name), "Stack[%08X]", tid); image_info_t ii_stack(this, EA_T(tib.StackLimit), size, name); thread_areas.insert(std::make_pair(ii_stack.base, ii_stack)); ii_stack.name = "STACK"; class_areas.insert(std::make_pair(ii_stack.base, ii_stack)); // verify a Stack PAGE_GUARD page exists ea_t ea_guard = ii_stack.base - MEMORY_PAGE_SIZE; MEMORY_BASIC_INFORMATION MemoryBasicInformation; if ( VirtualQueryEx(process_handle, (LPCVOID)ea_guard, &MemoryBasicInformation, sizeof(MemoryBasicInformation)) ) { if ( MemoryBasicInformation.Protect & PAGE_GUARD ) // a Stack PAGE_GUARD exists { qsnprintf(name, sizeof(name), "Stack_PAGE_GUARD[%08X]", tid); image_info_t ii_guard(this, ea_guard, MEMORY_PAGE_SIZE, name); thread_areas.insert(std::make_pair(ii_guard.base, ii_guard)); ii_guard.name = "STACK"; class_areas.insert(std::make_pair(ii_guard.base, ii_guard)); } } return true; }
//-------------------------------------------------------------------------- // get name from export directory in PE image in debugged process bool win32_debmod_t::get_pe_export_name_from_process( ea_t imagebase, char *name, size_t namesize) { peheader_t pe; ea_t peoff = get_pe_header(imagebase, &pe); if ( peoff != BADADDR && pe.expdir.rva != 0) { ea_t ea = imagebase + pe.expdir.rva; peexpdir_t expdir; if ( _read_memory(ea, &expdir, sizeof(expdir)) == sizeof(expdir) ) { ea = imagebase + expdir.dllname; name[0] = '\0'; _read_memory(ea, name, namesize); // don't check the return code because // we might have read more than necessary if ( name[0] != '\0' ) return true; } } return false; }
//-------------------------------------------------------------------------- // Get PE header // In: ea=DLL imagebase, nh=buffer to keep the answer // child==true:ea is an address in the child process // child==false:ea is an address in the the debugger itself // Returns: offset to the headers, BADADDR means failure ea_t win32_debmod_t::get_pe_header(ea_t ea, peheader_t *nh) { uint32 offset = 0; uint32 magic; if ( _read_memory(ea, &magic, sizeof(magic)) != sizeof(magic) ) return BADADDR; if ( ushort(magic) == MC2('M','Z') ) { if ( _read_memory(ea+PE_PTROFF, &offset, sizeof(offset)) != sizeof(offset) ) return BADADDR; } peheader64_t pe64; if ( _read_memory(ea+offset, &pe64, sizeof(pe64)) != sizeof(pe64) ) return BADADDR; if ( !pe64_to_pe(*nh, pe64, true, true) ) return BADADDR; if ( nh->signature != PEEXE_ID ) return BADADDR; #ifdef __X64__ if ( debapp_attrs.addrsize == 8 && !pe64.is_pe_plus() ) debapp_attrs.addrsize = 4; #endif return offset; }
static gboolean arv_gv_device_read_memory (ArvDevice *device, guint32 address, guint32 size, void *buffer, GError **error) { ArvGvDevice *gv_device = ARV_GV_DEVICE (device); int i; gint32 block_size; for (i = 0; i < (size + ARV_GVCP_DATA_SIZE_MAX - 1) / ARV_GVCP_DATA_SIZE_MAX; i++) { block_size = MIN (ARV_GVCP_DATA_SIZE_MAX, size - i * ARV_GVCP_DATA_SIZE_MAX); if (!_read_memory (gv_device->priv->io_data, address + i * ARV_GVCP_DATA_SIZE_MAX, block_size, buffer + i * ARV_GVCP_DATA_SIZE_MAX, error)) return FALSE; } return TRUE; }
static gboolean arv_uv_device_read_memory (ArvDevice *device, guint64 address, guint32 size, void *buffer, GError **error) { ArvUvDevice *uv_device = ARV_UV_DEVICE (device); int i; gint32 block_size; guint data_size_max; data_size_max = uv_device->priv->ack_packet_size_max - sizeof (ArvUvcpHeader); for (i = 0; i < (size + data_size_max - 1) / data_size_max; i++) { block_size = MIN (data_size_max, size - i * data_size_max); if (!_read_memory (uv_device, address + i * data_size_max, block_size, ((char *) buffer) + i * data_size_max, error)) return FALSE; } return TRUE; }
//---------------------------------------------------------- main thread --- void win32_debmod_t::handle_pdb_request() { if ( pdbthread.req_kind == 1 ) { // read input file bytevec_t cmd; append_dq(cmd, pdbthread.off_ea); append_dd(cmd, pdbthread.count); void *outbuf = NULL; ssize_t outsize = 0; // send request to IDA int rc = send_ioctl(WIN32_IOCTL_READFILE, &cmd[0], cmd.size(), &outbuf, &outsize); if ( rc == 1 && outbuf != NULL ) { // OK size_t copylen = qmin(pdbthread.count, outsize); memcpy(pdbthread.buffer, outbuf, copylen); pdbthread.count = copylen; pdbthread.req_result = true; } else { pdbthread.req_result = false; } if ( outbuf != NULL ) qfree(outbuf); } else if ( pdbthread.req_kind == 2 ) { // read memory ssize_t rc = _read_memory(ea_t(pdbthread.off_ea), pdbthread.buffer, pdbthread.count); if ( rc >= 0 ) pdbthread.count = rc; pdbthread.req_result = rc >= 0; } else { // unknown request pdbthread.req_result = false; } }
// GDB read memory format: // m[addr],[length] static void GDB_read_memory(char *command) { // Get address to read from command char *addr_string = strtok(command, "m,"); // Get num of bytes to read from command char *length_string = strtok(NULL, ","); // Convert strings to values seL4_Word addr = (seL4_Word) strtol(addr_string, NULL, HEX_STRING); seL4_Word length = (seL4_Word) strtol(length_string, NULL, DEC_STRING); // Buffer for raw data unsigned char data[length]; // Buffer for data formatted as hex string int buf_len = CHAR_HEX_SIZE * length + 1; char data_string[buf_len]; if (DEBUG_PRINT) printf("length: %d\n", length); // Do a read call to the GDB delegate who will read from the process on our behalf /*? me.from_instance.name ?*/_read_memory(addr, length, data); // Format the data for (int i = 0; i < length; i++) { sprintf(&data_string[CHAR_HEX_SIZE * i], "%02x", data[i]); } send_message(data_string, buf_len); }