def format(value, limit=LIMIT, code=True, offset=0, hard_stop=None, hard_end=0): """ Recursively dereferences an address into string representation, or convert the list representation of address dereferences into string representation. Arguments: value(int|list): Either the starting address to be sent to get, or the result of get (a list) limit(int): Number of valid pointers code(bool): Hint that indicates the value may be an instruction offset(int): Offset into the address to get the next pointer hard_stop(int): Value to stop on hard_end: Value to append when hard_stop is reached: null, value of hard stop, a string. Returns: A string representing pointers of each address and reference Strings format: 0x0804a10 —▸ 0x08061000 ◂— 0x41414141 """ limit = int(limit) + 1 # Allow results from get function to be passed to format if type(value) == list: chain = value else: chain = get(value, limit, offset, hard_stop, hard_end) arrow_left = C.arrow(' %s ' % config_arrow_left) arrow_right = C.arrow(' %s ' % config_arrow_right) # Enhance the last entry # If there are no pointers (e.g. eax = 0x41414141), then enhance # the only element there is. if len(chain) == 1: enhanced = pwndbg.enhance.enhance(chain[-1], code=code) # Otherwise, the last element in the chain is the non-pointer value. # We want to enhance the last pointer value. If an offset was used # chain failed at that offset, so display that offset. elif len(chain) < limit: enhanced = pwndbg.enhance.enhance(chain[-2] + offset, code=code) else: enhanced = C.contiguous('%s' % config_contiguous) # Colorize the rest rest = [] for link in chain[:-1]: symbol = pwndbg.symbol.get(link) or None if symbol: symbol = '%#x (%s)' % (link, symbol) rest.append(M.get(link, symbol)) if len(chain) == 1: return enhanced return arrow_right.join(rest) + arrow_left + enhanced
def format(value, limit=LIMIT, code=True, offset=0): chain = get(value, limit, offset) arrow_left = C.arrow(' %s ' % config_arrow_left) arrow_right = C.arrow(' %s ' % config_arrow_right) # Enhance the last entry # If there are no pointers (e.g. eax = 0x41414141), then enhance # the only element there is. if len(chain) == 1: enhanced = pwndbg.enhance.enhance(chain[-1], code=code) # Otherwise, the last element in the chain is the non-pointer value. # We want to enhance the last pointer value. elif len(chain) < limit: enhanced = pwndbg.enhance.enhance(chain[-2], code=code) else: enhanced = C.contiguous('%s' % config_contiguous) # Colorize the rest rest = [] for link in chain[:-1]: symbol = pwndbg.symbol.get(link) or None if symbol: symbol = '%#x (%s)' % (link, symbol) rest.append(M.get(link, symbol)) if len(chain) == 1: return enhanced return arrow_right.join(rest) + arrow_left + enhanced
def get_rec_addr_string(addr,visited_map): page = pwndbg.vmmap.find(addr) arrow_right = C.arrow(' %s ' % config_arrow_right) if not page is None: if not addr in visited_map: return "" parent_info = visited_map[addr] parent = parent_info[0] parent_base_addr = parent_info[1] if parent - parent_base_addr < 0: curText = hex(parent_base_addr) + hex(parent - parent_base_addr) else: curText = hex(parent_base_addr) + "+" + hex(parent - parent_base_addr) if parent_base_addr == addr: return "" return get_rec_addr_string(parent_base_addr,visited_map) + M.get(parent_base_addr,text=curText) + arrow_right else: return ""
def leakfind(address=None, page_name=None, max_offset=0x40, max_depth=0x4, stride=0x1, negative_offset=0x0): if address is None: raise argparse.ArgumentTypeError('No starting address provided.') foundPages = pwndbg.vmmap.find(address) if not foundPages: raise argparse.ArgumentTypeError('Starting address is not mapped.') if not pwndbg.memory.peek(address): raise argparse.ArgumentTypeError( 'Unable to read from starting address.') max_depth = int(max_depth) # Just warn the user that a large depth might be slow. # Probably worth checking offset^depth < threshold. Do this when more benchmarking is established. if max_depth > 8: print("leakfind may take a while to run on larger depths.") stride = int(stride) address = int(address) max_offset = int(max_offset) negative_offset = int(negative_offset) # The below map stores a map of child address->(parent_address,parent_start_address) # In the above tuple, parent_address is the exact address with a pointer to the child adddress. # parent_start_address is an address that a previous address pointed to. # We need to store both so that we can nicely create our leak chain. visited_map = {} visited_set = {int(address)} address_queue = Queue() address_queue.put(int(address)) depth = 0 time_to_depth_increase = 0 # Run a bfs # TODO look into performance gain from checking if an address is mapped before calling pwndbg.memory.pvoid() # TODO also check using pwndbg.memory.read for possible performance boosts. while address_queue.qsize() > 0 and depth < max_depth: if time_to_depth_increase == 0: depth = depth + 1 time_to_depth_increase = address_queue.qsize() cur_start_addr = address_queue.get() time_to_depth_increase -= 1 for cur_addr in range(cur_start_addr - negative_offset, cur_start_addr + max_offset, stride): try: result = int(pwndbg.memory.pvoid(cur_addr)) if result in visited_map or result in visited_set: continue visited_map[result] = ( cur_addr, cur_start_addr ) # map is of form child->(parent,parent_start) address_queue.put(result) visited_set.add(result) except gdb.error: # That means the memory was unmapped. Just skip it if we can't read it. break # A map of length->list of lines. Used to let us print in a somewhat nice manner. output_map = {} arrow_right = C.arrow(' %s ' % config_arrow_right) for child in visited_map: child_page = pwndbg.vmmap.find(child) if child_page is not None: if page_name is not None and page_name not in child_page.objfile: continue line = get_rec_addr_string( child, visited_map) + M.get(child) + " " + M.get( child, text=child_page.objfile) chain_length = line.count(arrow_right) if chain_length in output_map: output_map[chain_length].append(line) else: output_map[chain_length] = [line] # Output sorted by length of chain for chain_length in output_map: for line in output_map[chain_length]: print(line) if pwndbg.qemu.is_qemu(): print( "\n[QEMU target detected - leakfind result might not be accurate; see `help vmmap`]" )
def format(value, limit=LIMIT, code=True, offset=0, hard_stop=None, hard_end=0): """ Recursively dereferences an address into string representation, or convert the list representation of address dereferences into string representation. Arguments: value(int|list): Either the starting address to be sent to get, or the result of get (a list) limit(int): Number of valid pointers code(bool): Hint that indicates the value may be an instruction offset(int): Offset into the address to get the next pointer hard_stop(int): Value to stop on hard_end: Value to append when hard_stop is reached: null, value of hard stop, a string. Returns: A string representing pointers of each address and reference Strings format: 0x0804a10 —▸ 0x08061000 ◂— 0x41414141 """ limit = int(limit) # Allow results from get function to be passed to format if isinstance(value, list): chain = value else: chain = get(value, limit, offset, hard_stop, hard_end) arrow_left = C.arrow(' %s ' % config_arrow_left) arrow_right = C.arrow(' %s ' % config_arrow_right) # Colorize the chain rest = [] for link in chain: symbol = pwndbg.symbol.get(link) or None if symbol: symbol = '%#x (%s)' % (link, symbol) rest.append(M.get(link, symbol)) # If the dereference limit is zero, skip any enhancements. if limit == 0: return rest[0] # Otherwise replace last element with the enhanced information. rest = rest[:-1] # Enhance the last entry # If there are no pointers (e.g. eax = 0x41414141), then enhance # the only element there is. if len(chain) == 1: enhanced = pwndbg.enhance.enhance(chain[-1], code=code) # Otherwise, the last element in the chain is the non-pointer value. # We want to enhance the last pointer value. If an offset was used # chain failed at that offset, so display that offset. elif len(chain) < limit + 1: enhanced = pwndbg.enhance.enhance(chain[-2] + offset, code=code) else: enhanced = C.contiguous('%s' % config_contiguous) if len(chain) == 1: return enhanced return arrow_right.join(rest) + arrow_left + enhanced