class MyScriptedProcess(ScriptedProcess): memory_regions = [ lldb.SBMemoryRegionInfo("stack", 0x1040b2000, 0x1040b4000, 0b110, True, True) ] stack_memory_dump = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'main.stack-dump') def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData): super().__init__(target, args) def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo: for region in self.memory_regions: if region.GetRegionBase() <= addr < region.GetRegionEnd(): return region return None def get_thread_with_id(self, tid: int): return {} def get_registers_for_thread(self, tid: int): return {} def read_memory_at_address(self, addr: int, size: int) -> lldb.SBData: data = lldb.SBData() with open(self.stack_memory_dump, 'rb') as f: stack_mem = f.read(-1) if not stack_mem: return data mem_region = self.get_memory_region_containing_address(addr) if not mem_region or addr + size > mem_region.GetRegionEnd(): return data offset = addr - mem_region.GetRegionBase() shrunk_stack_mem = stack_mem[offset:offset + size] error = lldb.SBError() data.SetData(error, shrunk_stack_mem, self.target.GetByteOrder(), self.target.GetAddressByteSize()) return data def get_loaded_images(self): return self.loaded_images def get_process_id(self) -> int: return 42 def should_stop(self) -> bool: return True def is_alive(self) -> bool: return True def get_scripted_thread_plugin(self): return MyScriptedThread.__module__ + "." + MyScriptedThread.__name__
def get_memory_region_containing_address( self, addr: int) -> lldb.SBMemoryRegionInfo: mem_region = lldb.SBMemoryRegionInfo() error = self.corefile_process.GetMemoryRegionInfo(addr, mem_region) if error.Fail(): return None return mem_region
def address_breakpoints(self): """Test that breakpoints set on a bad address say they are bad.""" target, process, thread, bkpt = \ lldbutil.run_to_source_breakpoint(self, "Set a breakpoint here", lldb.SBFileSpec("main.c")) # illegal_address will hold (optionally) an address that, if # used as a breakpoint, will generate an unresolved breakpoint. illegal_address = None # Walk through all the memory regions in the process and # find an address that is invalid. regions = process.GetMemoryRegions() for region_idx in range(regions.GetSize()): region = lldb.SBMemoryRegionInfo() regions.GetMemoryRegionAtIndex(region_idx, region) if illegal_address == None or \ region.GetRegionEnd() > illegal_address: illegal_address = region.GetRegionEnd() if illegal_address is not None: # Now, set a breakpoint at the address we know is illegal. bkpt = target.BreakpointCreateByAddress(illegal_address) # Verify that breakpoint is not resolved. for bp_loc in bkpt: self.assertEquals(bp_loc.IsResolved(), False) else: self.fail( "Could not find an illegal address at which to set a bad breakpoint." )
def test_no_overlapping_regions(self): # In the past on Windows we were recording AllocationBase as the base address # of the current region, not BaseAddress. So if a range of pages was split # into regions you would see several regions with the same base address. # This checks that this no longer happens (and it shouldn't happen on any # other OS either). self.setup_program() regions = self.process().GetMemoryRegions() num_regions = regions.GetSize() if num_regions: region = lldb.SBMemoryRegionInfo() regions.GetMemoryRegionAtIndex(0, region) previous_base = region.GetRegionBase() previous_end = region.GetRegionEnd() for idx in range(1, regions.GetSize()): regions.GetMemoryRegionAtIndex(idx, region) # Check that it does not overlap the previous region. # This could happen if we got the base addresses or size wrong. # Also catches the base addresses being the same. region_base = region.GetRegionBase() region_end = region.GetRegionEnd() self.assertFalse((region_base < previous_end) and (previous_base < region_end), "Unexpected overlapping memory region found.") previous_base = region_base previous_end = region_end
def check_region(index, start, end, read, write, execute, mapped, name): region_info = lldb.SBMemoryRegionInfo() self.assertTrue( self.process.GetMemoryRegionInfo(start, region_info).Success()) self.assertEqual(start, region_info.GetRegionBase()) self.assertEqual(end, region_info.GetRegionEnd()) self.assertEqual(read, region_info.IsReadable()) self.assertEqual(write, region_info.IsWritable()) self.assertEqual(execute, region_info.IsExecutable()) self.assertEqual(mapped, region_info.IsMapped()) self.assertEqual(name, region_info.GetName()) # Ensure we have the same regions as SBMemoryRegionInfoList contains. if index >= 0 and index < regions_count: region_info_from_list = lldb.SBMemoryRegionInfo() self.assertTrue(region_info_list.GetMemoryRegionAtIndex( index, region_info_from_list)) self.assertEqual(region_info_from_list, region_info)
def test(self): class MyResponder(MockGDBServerResponder): def qHostInfo(self): return "ptrsize:8;endian:little;vm-page-size:4096;" def qMemoryRegionInfo(self, addr): if addr == 0: return "start:0;size:100000000;" if addr == 0x100000000: return "start:100000000;size:4000;permissions:rx;dirty-pages:;" if addr == 0x100004000: return "start:100004000;size:4000;permissions:r;dirty-pages:0x100004000;" if addr == 0x1000a2000: return "start:1000a2000;size:5000;permissions:r;dirty-pages:0x1000a2000,0x1000a3000,0x1000a4000,0x1000a5000,0x1000a6000;" self.server.responder = MyResponder() target = self.dbg.CreateTarget('') if self.TraceOn(): self.runCmd("log enable gdb-remote packets") self.addTearDownHook( lambda: self.runCmd("log disable gdb-remote packets")) process = self.connect(target) # A memory region where we don't know anything about dirty pages region = lldb.SBMemoryRegionInfo() err = process.GetMemoryRegionInfo(0, region) self.assertTrue(err.Success()) self.assertFalse(region.HasDirtyMemoryPageList()) self.assertEqual(region.GetNumDirtyPages(), 0) region.Clear() # A memory region with dirty page information -- and zero dirty pages err = process.GetMemoryRegionInfo(0x100000000, region) self.assertTrue(err.Success()) self.assertTrue(region.HasDirtyMemoryPageList()) self.assertEqual(region.GetNumDirtyPages(), 0) self.assertEqual(region.GetPageSize(), 4096) region.Clear() # A memory region with one dirty page err = process.GetMemoryRegionInfo(0x100004000, region) self.assertTrue(err.Success()) self.assertTrue(region.HasDirtyMemoryPageList()) self.assertEqual(region.GetNumDirtyPages(), 1) self.assertEqual(region.GetDirtyPageAddressAtIndex(0), 0x100004000) region.Clear() # A memory region with multple dirty pages err = process.GetMemoryRegionInfo(0x1000a2000, region) self.assertTrue(err.Success()) self.assertTrue(region.HasDirtyMemoryPageList()) self.assertEqual(region.GetNumDirtyPages(), 5) self.assertEqual(region.GetDirtyPageAddressAtIndex(4), 0x1000a6000) region.Clear()
def do_info(self, name): meminfo = lldb.SBMemoryRegionInfo() if name == 'memory': process = self.interpreter.GetProcess() minfolist = process.GetMemoryRegions() for i in range(10): if minfolist.GetMemoryRegionAtIndex(i, meminfo): print('Got %d name: %s' % (i, meminfo.GetName())) else: print('Got %d name: %s' % (i, 'failed')) break
def get_search_regions() : memoryRegions = lldb.process.GetMemoryRegions() print 'total memory regions: ', memoryRegions.GetSize() region = lldb.SBMemoryRegionInfo() searchRegions = [] for i in range(memoryRegions.GetSize()): if memoryRegions.GetMemoryRegionAtIndex(i, region): if region.IsWritable() and region.IsReadable() and not region.IsExecutable(): #print '[{0:x},{1:x}]'.format(region.GetRegionBase(), region.GetRegionEnd()) searchRegions.append((region.GetRegionBase(), region.GetRegionEnd())) #sort regions in descending order, so that large regions get processed early searchRegions.sort(key=lambda tup: tup[1] - tup[0], reverse=True) # for region in searchRegions : # print '{0:x} [{1:x}, {2:x})'.format(region[1]-region[0], region[0], region[1]) searchRegionCount = len(searchRegions) print 'target memory regions: ', searchRegionCount return searchRegions
def get_all_memory_sections(self): # currently missing stack and heap.. great i know # lldb-devs mentions how its not possible, but vmmap does it :( process = self.get_current_process() region_list = process.GetMemoryRegions() maps = [] for i in range(region_list.GetSize()): region = lldb.SBMemoryRegionInfo() region_list.GetMemoryRegionAtIndex(i, region) begin_address = region.GetRegionBase() end_address = region.GetRegionEnd() - 1 name = region.GetName() if name is None: name = '' perm_str = '' maps.append(MemoryMap(begin_address, end_address, region.IsReadable(), region.IsWritable(), region.IsExecutable(), name)) return maps
def check_memory_regions(self, process, region_count): region_list = process.GetMemoryRegions() self.assertEqual(region_list.GetSize(), region_count) region = lldb.SBMemoryRegionInfo() # Check we have the right number of regions. self.assertEqual(region_list.GetSize(), region_count) # Check that getting a region beyond the last in the list fails. self.assertFalse( region_list.GetMemoryRegionAtIndex(region_count, region)) # Check each region is valid. for i in range(region_list.GetSize()): # Check we can actually get this region. self.assertTrue(region_list.GetMemoryRegionAtIndex(i, region)) # Every region in the list should be mapped. self.assertTrue(region.IsMapped()) # Test the address at the start of a region returns it's enclosing # region. begin_address = region.GetRegionBase() region_at_begin = lldb.SBMemoryRegionInfo() error = process.GetMemoryRegionInfo(begin_address, region_at_begin) self.assertEqual(region, region_at_begin) # Test an address in the middle of a region returns it's enclosing # region. middle_address = (region.GetRegionBase() + region.GetRegionEnd()) // 2 region_at_middle = lldb.SBMemoryRegionInfo() error = process.GetMemoryRegionInfo(middle_address, region_at_middle) self.assertEqual(region, region_at_middle) # Test the address at the end of a region returns it's enclosing # region. end_address = region.GetRegionEnd() - 1 region_at_end = lldb.SBMemoryRegionInfo() error = process.GetMemoryRegionInfo(end_address, region_at_end) self.assertEqual(region, region_at_end) # Check that quering the end address does not return this region but # the next one. next_region = lldb.SBMemoryRegionInfo() error = process.GetMemoryRegionInfo(region.GetRegionEnd(), next_region) self.assertNotEqual(region, next_region) self.assertEqual(region.GetRegionEnd(), next_region.GetRegionBase()) # Check that query beyond the last region returns an unmapped region # that ends at LLDB_INVALID_ADDRESS last_region = lldb.SBMemoryRegionInfo() region_list.GetMemoryRegionAtIndex(region_count - 1, last_region) end_region = lldb.SBMemoryRegionInfo() error = process.GetMemoryRegionInfo(last_region.GetRegionEnd(), end_region) self.assertFalse(end_region.IsMapped()) self.assertEqual(last_region.GetRegionEnd(), end_region.GetRegionBase()) self.assertEqual(end_region.GetRegionEnd(), lldb.LLDB_INVALID_ADDRESS)
def handle_command(debugger, command, exe_ctx, result, internal_dict): ''' Documentation for how to use info goes here ''' command_args = shlex.split(command, posix=False) parser = generate_option_parser() target = debugger.GetSelectedTarget() try: (options, args) = parser.parse_args(command_args) except: result.SetError(parser.usage) return if len(args) != 1: result.SetError("Expects an address") return try: if args[0].startswith("0x") or args[0].startswith("0X"): address = int(args[0], 16) else: address = int(args[0], 10) except ValueError: frame = target.GetProcess().GetSelectedThread().GetSelectedFrame() val = frame.var(args[0]) if val.IsValid() == False: result.SetError("can't parse \"{}\"".format(args[0])) return if options.address_of: derefVal = val.AddressOf() if derefVal.IsValid() == False: result.SetError("can't deref \"{}\"".format(args[0])) return address = derefVal.unsigned else: address = val.unsigned # else: # result.SetError("info expects a pointer, try \"info &{}\"".format(args[0])) # return addr = target.ResolveLoadAddress(address) res = lldb.SBCommandReturnObject() interpreter = debugger.GetCommandInterpreter() returnDescription = "" foundAddress = False if addr.GetSection().IsValid(): foundAddress, returnDescription = tryMachOAddress(addr, target, options) if foundAddress == False: foundAddress, returnDescription = tryHeapAddress(addr, target, options) if foundAddress == False: foundAddress, returnDescription = tryStackAddress(addr, target, options) memString = "" if options.verbose: memRegion = lldb.SBMemoryRegionInfo() if target.GetProcess().GetMemoryRegionInfo(address, memRegion).success: memString = hex(memRegion.GetRegionBase()) + "-" + hex(memRegion.GetRegionEnd()) memString += " {}{}{}".format("R" if memRegion.IsReadable() else "-", "W" if memRegion.IsWritable() else "-", "X" if memRegion.IsExecutable() else "-") if foundAddress: result.AppendMessage('{}{}, {} {}'.format("&" if options.address_of else "", args[0],returnDescription, memString)) else: result.AppendMessage("Couldn't find address, reverting to \"image lookup -a {}\"".format(addr)) debugger.HandleCommand("image lookup -v -a {}".format(addr))
def dump_process_memory(output_dir): # Segment information dictionary raw_segment_list = [] raw_memory_list = [] # 1st pass: # Loop over the segments, fill in the segment info dictionary for module in lldb.target.module_iter(): for seg_ea in module.section_iter(): seg_info = {'module': module.file.GetFilename() } seg_info['start'], seg_info['end'], seg_size, seg_info['name'] = get_section_info(seg_ea) # TODO: Ugly hack for -1 LONG address on 32-bit if seg_info['start'] >= sys.maxint or seg_size <= 0: print "Throwing away page: {}".format(seg_info['name']) continue # Page-align segment seg_info['start'] = ALIGN_PAGE_DOWN(seg_info['start']) seg_info['end'] = ALIGN_PAGE_UP(seg_info['end']) print("Appending: {}".format(seg_info['name'])) raw_segment_list.append(seg_info) # Add the stack memory region (just hardcode 0x1000 around the current SP) sp = lldb.frame.GetSP() start_sp = ALIGN_PAGE_DOWN(sp) raw_segment_list.append({'start': start_sp, 'end': start_sp + 0x1000, 'name': 'STACK'}) # Write the original memory to file for debugging index_file = open(os.path.join(output_dir, DEBUG_MEM_FILE_NAME), 'w') index_file.write(json.dumps(raw_segment_list, indent=4)) index_file.close() # Loop over raw memory regions mem_info = lldb.SBMemoryRegionInfo() start_addr = -1 next_region_addr = 0 while next_region_addr > start_addr: err = lldb.process.GetMemoryRegionInfo(next_region_addr, mem_info) # TODO: Should check err.success. If False, what do we do? if not err.success: break next_region_addr = mem_info.GetRegionEnd() if next_region_addr >= sys.maxsize: break start_addr = mem_info.GetRegionBase() end_addr = mem_info.GetRegionEnd() # Unknown region name region_name = 'UNKNOWN' # Ignore regions that aren't even mapped if mem_info.IsMapped() and mem_info.IsReadable(): mem_info_obj = {'start': start_addr, 'end': end_addr, 'name': region_name, 'permissions': { "r": mem_info.IsReadable(), "w": mem_info.IsWritable(), "x": mem_info.IsExecutable() }} raw_memory_list.append(mem_info_obj) final_segment_list = overlap_alignments(raw_segment_list, raw_memory_list) for seg_info in final_segment_list: try: seg_info['content_file'] = '' start_addr = seg_info['start'] end_addr = seg_info['end'] region_name = seg_info['name'] # Compress and dump the content to a file err = lldb.SBError() seg_content = lldb.process.ReadMemory(start_addr, end_addr - start_addr, err) if(seg_content == None): print("Segment empty: @0x{0:016x} (size:UNKNOWN) {1}".format(start_addr, region_name)) seg_info['content_file'] = '' else: print("Dumping segment @0x{0:016x} (size:0x{1:x}): {2} [{3}]".format(start_addr, len(seg_content), region_name, repr(seg_info['permissions']))) compressed_seg_content = zlib.compress(seg_content) md5_sum = hashlib.md5(compressed_seg_content).hexdigest() + ".bin" seg_info['content_file'] = md5_sum # Write the compressed contents to disk out_file = open(os.path.join(output_dir, md5_sum), 'wb') out_file.write(compressed_seg_content) out_file.close() except: print("Exception reading segment ({}): {}".format(region_name, sys.exc_info()[0])) return final_segment_list