def _find_free_space(self, size, min_addr=0, max_addr=MAX_UINT64, alignment=0x10000): """ Finds a region of memory that is free, larger than 'size' arg, and aligned. """ sections = list(self.memory_info.values()) for i in range(0, len(sections)): addr = util.align(sections[i].address + sections[i].size, alignment=alignment) # Enable allocating memory in the middle of a gap when the # min requested address falls in the middle of a gap if addr < min_addr: addr = min_addr # Cap the gap's max address by accounting for the next # section's start address, requested max address, and the # max possible address max_gap_addr = (self.max_addr if i == len(sections) - 1 else sections[i + 1].address) max_gap_addr = min(max_gap_addr, max_addr) # Ensure the end address is less than the max and the start # address is free if addr + size < max_gap_addr and self._is_free(addr): return addr raise OutOfMemoryException()
def map_file_anywhere( self, filename: str, offset: int = 0, size: int = 0, preferred_address: int = None, min_addr: int = 0x1000, max_addr: int = 0xFFFFFFFFFFFFFFFF, alignment: int = 0x1000, top_down: bool = False, prot: int = ProtType.RWX, shared: bool = False, ) -> int: """ Maps a region of memory with requested size, within the addresses specified. The size and start address will respect the alignment. Args: filename: Name of the file to memory map offset: Page-aligned offset of file to start mapping size: # of bytes to map. This will be rounded up to the nearest page. preferred_address: If the specified address is available, it will be used for the mapping. min_addr: The lowest address that could be mapped. max_addr: The highest address that could be mapped. alignment: Ensures the size and start address are multiples of this. Must be a multiple of 0x1000. Default 0x1000. top_down: If True, the region will be mapped to the highest available address instead of the lowest. prot: RWX permissions of the mapped region. Defaults to granting all permissions. shared: if True, region is shared with subprocesses. Returns: Start address of mapped region. """ if size == 0: with open(filename, "rb") as f: size = os.fstat(f.fileno()).st_size size = util.align(size) address = self.find_free_space( size, preferred_address=preferred_address, min_addr=min_addr, max_addr=max_addr, alignment=alignment, top_down=top_down, ) if address is None: raise OutOfMemoryException() self.map_file( address, filename, offset=offset, size=size, prot=prot, shared=shared, ) return address
def _split_region( self, mr: MemoryRegion, address: int, size: int, do_delete: bool = False, ): chunk_end = address + size if (address <= mr.address and chunk_end > mr.end) or size == 0: return if address > mr.end or chunk_end <= mr.address: raise OutOfMemoryException() self._mem_unmap_region(mr) if address < mr.address: address = mr.address if chunk_end > mr.end + 1: chunk_end = mr.end + 1 l_size = address - mr.address m_size = chunk_end - address r_size = mr.end + 1 - chunk_end if l_size > 0: l_mr = copy.copy(mr) l_mr.shrink(mr.address, l_size) self._mem_map_region(l_mr) if m_size > 0 and not do_delete: m_mr = copy.copy(mr) m_mr.shrink(address, m_size) self._mem_map_region(m_mr) if r_size > 0: r_mr = copy.copy(mr) r_mr.shrink(chunk_end, r_size) self._mem_map_region(r_mr)
def map_anywhere( self, size: int, preferred_address: int = None, name: str = "", kind: str = "", module_name: str = "", min_addr: int = 0x1000, max_addr: int = 0xFFFFFFFFFFFFFFFF, alignment: int = 0x1000, top_down: bool = False, prot: int = ProtType.RWX, shared: bool = False, ) -> int: """ Maps a region of memory with requested size, within the addresses specified. The size and start address will respect the alignment. Args: size: # of bytes to map. This will be rounded up to match the alignment. preferred_address: If the specified address is available, it will be used for the mapping. name: String used to identify mapped region. Used for debugging. kind: String used to identify the purpose of the mapped region. Used for debugging. module_name: String used to identify the module that mapped this region. min_addr: The lowest address that could be mapped. max_addr: The highest address that could be mapped. alignment: Ensures the size and start address are multiples of this. Must be a multiple of 0x1000. Default 0x1000. top_down: If True, the region will be mapped to the highest available address instead of the lowest. prot: RWX permissions of the mapped region. Defaults to granting all permissions. shared: if True, region is shared with subprocesses. Returns: Start address of mapped region. """ address = self.find_free_space( size, preferred_address=preferred_address, min_addr=min_addr, max_addr=max_addr, alignment=alignment, top_down=top_down, ) if address is None: raise OutOfMemoryException() self.map( address, util.align(size), name=name, kind=kind, module_name=module_name, prot=prot, shared=shared, ) return address