def _get_pc(dbg: DebugAdapter.DebugAdapter) -> int: pc_names = ['rip', 'eip', 'pc'] for reg_name in pc_names: if reg_name in dbg.reg_list(): return dbg.reg_read(reg_name) raise Exception('[!] No program counter name (%s) found in registers: %s' % (pc_names, dbg.reg_list()))
def read_value(dbg: DebugAdapter.DebugAdapter, reg: Optional[str], offset: Optional[int]) -> Optional[int]: """Read the requested value from the debug adapter. If only reg is specified, gets the value of that register. If only offset is specified, reads a 64-bit int from memory at the address. If reg+offset is specified, reads a 64-bit int from memory at [reg+offset] Will try to rebase address if you only supply and offset and it appears to be within the target module. DebugAdapter will raise exceptions if you do something wrong. """ if reg is not None and offset is None: return dbg.reg_read(reg) elif offset is not None: if reg is None: addr = _rebase_if_needed(dbg, offset) if reg is not None: addr = dbg.reg_read(reg) addr += offset #print('DBG: reading addr 0x%x+0x%x (0x%x)' % (addr, offset, addr+offset)) data = dbg.mem_read(addr, 8) return struct.unpack('<Q', data)[0] else: raise Exception( '[!] Must specify at least one of reg or offset arguments')
def _rebase_bv(bv: BinaryView, dbg: DebugAdapter.DebugAdapter) -> BinaryView: """Get a rebased BinaryView for support of ASLR compatible binaries.""" new_base = dbg.target_base() if core_ui_enabled() and new_base != bv.start: dbg.quit() raise Exception('[!] Can\'t do necessary rebase in GUI, try headless operation') new_bv = bv.rebase(new_base) if new_bv is None: # None if rebasing is unecessary return bv print('[*] Rebasing bv from 0x%x to 0x%x' % (bv.start, new_base)) new_bv.update_analysis_and_wait() # required after rebase return new_bv
def get_value_at(dbg: DebugAdapter.DebugAdapter, reg: Optional[str], offset: Optional[int], breakpoint_addr: int, breakpoint_times: int = 0) -> int: """Run the DebugAdapter to the specified addr and read the requested value. If only reg is specified, gets the value of that register. If only offset is specified, reads a 64-bit int from memory at the address. If reg+offset is specified, reads a 64-bit int from memory at [reg+offset] Will try to rebase address if you only supply and offset and it appears to be within the target module. Raises exceptions on errors, for example if breakpoint_addr isn't hit or is hit fewer times than specified. """ value_read = None times_hit = 0 dbg.breakpoint_set(breakpoint_addr) while True: (reason, _) = dbg.go() # second item in tuple "data" unused if reason == DebugAdapter.STOP_REASON.BREAKPOINT: stop_addr = _get_pc(dbg) dbg.breakpoint_clear(stop_addr) if times_hit < breakpoint_times: dbg.step_into() dbg.breakpoint_set(stop_addr) times_hit += 1 else: value_read = read_value(dbg, reg, offset) break elif reason == DebugAdapter.STOP_REASON.PROCESS_EXITED: break else: print('[!] Unexpected stop reason: %s' % str(reason)) break if value_read is None: if times_hit == 0: raise Exception('[!] Never hit requested breakpoint') elif times_hit < breakpoint_times: raise Exception( '[!] Only hit breakpoint %d times, requested read after %d' % (times_hit, breakpoint_times)) else: raise Exception( '[!] Unexpected error: Breakpoint hit but value_read is None') return value_read