Beispiel #1
0
def mmapx(sm, p, syscall_name, args, offset):
    MAP_SHARED = 0x1
    memory_region_name = syscall_name
    handle = sm.z.handles.get(args.fd)
    if handle is not None:
        memory_region_name = f"{syscall_name} -> {handle.Name}"

    addr = args.addr
    if addr == 0:
        addr = p.memory._find_free_space(args.length)

    data = b""
    if handle is not None:
        f = sm.z.files.open_library(handle.Name)
        if f is not None:
            f.seek(offset)
            data = f.read(args.length)
            f.close()

    data += b"\0" * (args.length - len(data))

    # If this is shared, map it with the pointer
    if args.flags & MAP_SHARED != 0:
        print(len(data))
        ptr = ctypes.POINTER(ctypes.c_void_p)(ctypes.c_void_p.from_buffer(
            bytearray(data)))
        p.memory.map(
            addr,
            align(args.length),
            name=memory_region_name,
            kind=syscall_name,
            ptr=ptr,
        )
        return addr

    try:
        p.memory.map(
            addr,
            align(args.length),
            name=memory_region_name,
            kind=syscall_name,
        )
    except Exception:
        if args.flags & 0x10 > 0:
            # This must be mapped to this region, we should be able to
            # just write over the existing data.
            # This should crash if we are unable to write to the desired
            # region
            pass
        else:
            sm.logger.notice(f"Address {addr:x} already mapped")
            addr = p.memory.map_anywhere(args.length,
                                         name=memory_region_name,
                                         kind=syscall_name)

    p.memory.write(addr, data)

    return addr
Beispiel #2
0
    def alloc(self, size: int, name: str = None, align: int = 0x4) -> int:
        """
        Allocates memory to the heap. These are rounded up to the size
        of the alignment.

        Args:
            size: Number of bytes to allocate.
            name: Used to keep track of what information was allocated.
                Used for debugging
            align: Ensures that the memory allocated is a multiple of
                this value. Defaults to 4.

        Returns:
            Address of the new heap boundary
        """
        self.logger.debug(f"Allocating {size:x} bytes named {name}")
        ret = self.current_offset
        requested_size = util.align(size, alignment=align)
        if (self.current_offset + requested_size >=
                self.heap_start + self.heap_max_size):
            self.logger.error(
                "Ran out of heap memory . Try increasing max heap size.")
            return ret
        self.current_offset += requested_size
        # TODO(kvalakuzhy): It would be nice if this could be moved into
        # a heap tracking class.
        self.heap_objects.add(_HeapObjInfo(ret, size, name=name))
        return ret
Beispiel #3
0
    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
Beispiel #4
0
    def protect(self, address: int, size: int, prot: int) -> None:
        """
        Sets memory permissions on the specified memory region. Respects
        alignment of 0x1000.

        Args:
            address: Address of memory region to modify permissions.
                Rounds down to nearest 0x1000.
            size: Size of region to protect. Rounds up to nearest
                0x1000.
            prot: Desired RWX permissions.

        TODO:
            This does not correspond to Sections at the moment.

        """
        if self.disableNX:
            prot = prot | ProtType.EXEC
        aligned_address = address & 0xFFFFF000  # Address needs to align with
        aligned_size = util.align((address & 0xFFF) + size)
        try:
            self.emu.mem_protect(aligned_address, aligned_size, prot)
            self.logger.debug(
                "Protected region 0x%x + 0x%x, Prot: %x",
                aligned_address,
                aligned_size,
                prot,
            )
        except Exception as e:
            self.logger.error(f"Error trying to protect region "
                              f"0x{aligned_address:x} + 0x{aligned_size:x}, "
                              f"Prot: {prot:x}: {e}")
Beispiel #5
0
 def _load_module(self, elf, module_name):
     module_path, normalized_module_name = self._get_module_name(
         module_name)
     data = bytearray(elf.Data)
     base = self.memory._alloc_at(
         "",
         "main",
         basename(normalized_module_name),
         elf.ImageBase,
         elf.VirtualSize,
     )
     self.memory.write(base, bytes(data))
     # Set proper permissions for each section of the module
     for s in elf.Sections:
         try:
             self.memory.protect(
                 s.Address,
                 align(s.VirtualSize, s.Alignment),
                 s.Permissions,
                 # s.Name,
                 # "main",
                 # module_name=basename(module_path),
             )
         except Exception:
             raise ZelosLoadException(
                 f"Bad section {hex(s.Address)}  {hex(s.VirtualSize)}")
     return base
Beispiel #6
0
    def __init__(self, memory, gdt_base=0x80000000, size=0x1000):
        self.emu = memory.emu

        memory.map(gdt_base, align(size), prot=0x3)
        self.emu.set_reg("gdtr", (0, gdt_base, size, 0x0))
        self.gdt_base = gdt_base
        self._init_gdt()
Beispiel #7
0
def sys_getdents64(sm, p):
    global run_once
    if run_once is not None:
        return 0

    args = sm.get_args([
        ("unsigned int", "fd"),
        ("struct linux_dirent64 *", "dirp"),
        ("unsigned int", "count"),
    ])
    #    struct linux_dirent64 {
    #        ino64_t        d_ino;    /* 64-bit inode number */
    #        off64_t        d_off;    /* 64-bit offset to next struct */
    #        unsigned short d_reclen; /* Size of this dirent */
    #        unsigned char  d_type;   /* File type */
    #        char           d_name[]; /* Filename (null-terminated) */
    #    };

    p.memory.write_int(args.dirp + 0x0, 56, sz=8)
    p.memory.write_int(args.dirp + 0x8, 0x0, sz=8)

    p.memory.write_int(args.dirp + 0x12, 6, sz=1)
    s_len = p.memory.write_string(args.dirp + 0x13, "FolderContents")
    struct_size = align(0x13 + s_len, 4)

    # val = bytes([0xb + s_len, 0xb + s_len])
    # from zelos.util import p16
    # val2 = p16(0x13+s_len +0x100 )

    # p.memory.write(args.dirp + 0x10, bytes([0x30]))

    p.memory.write_int(args.dirp + 0x10, struct_size, sz=2)
    run_once = 1
    return struct_size
Beispiel #8
0
 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()
Beispiel #9
0
    def hook_first_read(self, region_addr, hook):
        region = self.get_region(region_addr)
        size = self.get_size(region_addr)
        perms = self.get_perms(region_addr)
        if region is None or size is None or perms is None:
            return False
        addr = region.address

        try:
            self.emu.mem_protect(addr, util.align(size), ProtType.NONE)
        except Exception:
            self.logger.exception(
                "Error trying to protect portion 0x%x + 0x%x, Prot: %x",
                addr,
                util.align(size),
                ProtType.NONE,
            )
        self.mem_hooks[addr] = _MemHook(addr, size, perms, hook)
        return True
Beispiel #10
0
 def _hook_read_prot(self, uc, access, address, size, value, user_data):
     region = self.get_region(address)
     addr = region.address if region is not None else None
     if addr not in self.mem_hooks:
         return False
     mem_hook = self.mem_hooks[addr]
     self.emu.mem_protect(mem_hook.addr, util.align(mem_hook.size),
                          mem_hook.orig_perms)
     del self.mem_hooks[addr]
     return mem_hook.hook(uc, access, address, size, value, user_data)
Beispiel #11
0
    def copy_section(self, section: Section, other_memory: "Memory") -> None:
        """
        Copies a section from this instance of memory into another
        instance of memory.

        Args:
            section: The section to copy. Must correspond to a section
                within this memory object.
            other_memory: An instance of memory to copy the specified
                section to.
        """
        start = section.address
        size = section.size
        end = start + size

        # We have the beginning mapped for special addresses
        if start == 0:
            return

        # Some sections are added to differentiate different sections in
        # the binary. These are typically not aligned. If they are,
        # should only be an extra copy.
        if start != util.align(start) or end != util.align(end):
            return

        self.logger.spam(f"Copying {start:x}-{end:x}")

        if section.ptr is None:
            data = other_memory.read(start, size)
            self.map(start, size)
            self.write(start, bytes(data))
        else:
            self.map(start, size, ptr=section.ptr)
        self._new_section(
            section.address,
            section.size,
            name=section.name,
            kind=section.kind,
            module_name=section.module_name,
            ptr=section.ptr,
        )
Beispiel #12
0
    def test_align(self):
        self.assertEqual(0x1000, util.align(0x1000))
        self.assertEqual(0x2000, util.align(0x1001))
        self.assertEqual(0x1000, util.align(1))
        self.assertEqual(0x12000, util.align(0x11002))

        self.assertEqual(0x14, util.align(0x11, alignment=0x4))
        self.assertEqual(0x10, util.align(0xF, alignment=0x4))
Beispiel #13
0
 def find_free_space(
     self,
     size,
     preferred_address=None,
     min_addr=0x1000,
     max_addr=MAX_UINT32,
     alignment=0x10000,
     top_down=False,
 ):
     """
     Returns the start address of the next region between start and
     end that allows for memory of the given size to be mapped.
     """
     if preferred_address is not None and not self._has_overlap(
             preferred_address, size):
         return preferred_address
     regions = self.get_regions()
     # Check if space before first region is free
     min_addr = util.align(min_addr, alignment=alignment)
     if len(regions) == 0 or min_addr + size <= regions[0].address:
         return min_addr
     # Check if space between regions is free
     for i in range(len(regions) - 1):
         gap_begin = util.align(max(regions[i].end, min_addr),
                                alignment=alignment)
         gap_end = min(min(max_addr, gap_begin + size),
                       regions[i + 1].start)
         gap_size = gap_end - gap_begin
         if gap_size >= size:
             return gap_begin
     # Check if space after last region is free
     gap_begin = util.align(max(regions[-1].end, min_addr),
                            alignment=alignment)
     gap_end = max_addr
     gap_size = gap_end - gap_begin
     if gap_size >= size:
         return gap_begin
     return None
Beispiel #14
0
    def _alloc_at(
        self,
        name,
        kind,
        module_name,
        requested_addr,
        size,
        min_addr=0x60000000,
        max_addr=0x90000000,
        prot=ProtType.RWX,
        ptr=None,
    ):
        # if requested_addr < min_addr:
        #     requested_addr = min_addr
        if requested_addr > max_addr:
            requested_addr = min_addr
        size = util.align(size)
        relocated_addr = 0
        if self._has_overlap(requested_addr, size):
            relocated_addr = self._get_next_gap(size, min_addr, max_addr)

            self.logger.debug("[Loader] Relocating Overlapping Region from "
                              "0x{0:08x} to 0x{1:08x}".format(
                                  requested_addr, relocated_addr))
            try:
                self.map(
                    relocated_addr,
                    size,
                    name,
                    kind,
                    module_name=module_name,
                    prot=prot,
                    ptr=ptr,
                )
                return relocated_addr
            except Exception:
                self.logger.exception("Couldn't relocate properly")
                exit()
        else:
            self.map(
                requested_addr,
                size,
                name,
                kind,
                module_name=module_name,
                prot=prot,
                ptr=ptr,
            )
        return requested_addr
Beispiel #15
0
 def _load_state(self, data):
     for meminfo, mem in data:
         self.logger.debug("Loading: ", hex(meminfo.address),
                           hex(meminfo.size), meminfo)
         mem = bytes(mem)
         try:
             self.emu.mem_write(meminfo.address, mem)
         except Exception:
             self.map(
                 meminfo.address,
                 util.align(meminfo.size),
                 meminfo.name,
                 meminfo.kind,
             )
             self.emu.mem_write(meminfo.address, mem)
Beispiel #16
0
def sys_getdents(sm, p):
    args = sm.get_args([
        ("unsigned int", "fd"),
        ("struct linux_dirent *", "dirp"),
        ("unsigned int", "count"),
    ])

    handle = sm.z.handles.get(args.fd)
    if handle is None:
        return -1

    folder_contents = handle.data.get("dents", None)
    if folder_contents is None:
        # Get the dents and run this function
        folder_contents = sm.z.files.list_dir(handle.Name)
    if len(folder_contents) == 0:
        handle.data["dents"] = folder_contents
        return 0

    prev_struct_start = None
    struct_start = args.dirp
    total_bytes_written = 0
    while len(folder_contents) > 0:
        full_name = os.path.join(handle.Name, folder_contents[-1])
        bytes_written = _write_dirent_x86_64(
            sm,
            p,
            full_name,
            folder_contents[-1],
            struct_start,
            prev_struct_start,
            args.dirp + args.count,
        )
        if bytes_written == 0:
            break
        else:
            folder_contents.pop()
            total_bytes_written += bytes_written
        prev_struct_start = struct_start
        struct_start = align(struct_start + bytes_written, alignment=0x4)

    handle.data["dents"] = folder_contents
    return total_bytes_written
Beispiel #17
0
 def mem_map_file(
     self,
     address: int,
     filename: str,
     offset: int = 0,
     size: int = 0,
     prot: int = ProtType.RW,
     shared: bool = False,
 ):
     if address % 0x1000 != 0:
         raise ValueError("invalid argument: address not aligned")
     if offset % 0x1000 != 0:
         raise ValueError("invalid argument: offset not aligned")
     with open(filename, "rb") as f:
         basename = os.path.basename(filename)
         file_map = mmap.mmap(f.fileno(),
                              length=0,
                              offset=offset,
                              access=mmap.ACCESS_COPY)
         ptr = ctypes.POINTER(ctypes.c_void_p)(
             ctypes.c_void_p.from_buffer(file_map))
         if size == 0:
             size = os.fstat(f.fileno()).st_size
         size = align(size)
         if self._mem_area_overlaps(address, size):
             raise ValueError("invalid argument: {address, size} overlaps")
         mr = MemoryRegion(
             self,
             address,
             size,
             prot,
             basename,
             "mapped",
             basename,
             shared=shared,
             host_address=ctypes.addressof(ptr.contents),
             managed_object=file_map,
         )
         self._mem_map_region(mr)
         return
     raise ValueError("invalid argument: filename")
Beispiel #18
0
 def _load_module(self, elf, module_name):
     module_path, normalized_module_name = self._get_module_name(
         module_name)
     data = bytearray(elf.Data)
     base = self.memory.map_anywhere(
         elf.VirtualSize,
         preferred_address=elf.ImageBase,
         name="",
         kind="main",
         module_name=basename(normalized_module_name),
     )
     self.memory.write(base, bytes(data))
     # Set proper permissions for each section of the module
     for s in elf.Sections:
         try:
             self.memory.protect(s.Address, align(s.VirtualSize,
                                                  s.Alignment),
                                 s.Permissions)
         except Exception:
             raise ZelosLoadException(
                 f"Bad section {hex(s.Address)}  {hex(s.VirtualSize)}")
     return base
Beispiel #19
0
    def _get_next_gap(self, size, start, end):
        """
        Returns the start address of the next region between start and
        end that allows for memory of the given size to be mapped.
        """
        min_addr_so_far = start
        for region in sorted(list(self.emu.mem_regions()), key=lambda x: x[0]):
            region_begin = region[0]
            region_end = region[1]
            if region_begin >= end or region_end < start:
                continue

            gap = region_begin - min_addr_so_far
            if gap < size:
                min_addr_so_far = util.align(region_end)
                continue
            return min_addr_so_far
        # Check to see there is a gap after the last region
        gap = end - min_addr_so_far
        if gap < size:
            self.logger.error("No gap of size %x between %x and %x" %
                              (size, start, end))
        return min_addr_so_far
Beispiel #20
0
 def __init__(
     self,
     emu,
     address: int,
     size: int,
     prot: int,
     name: str,
     kind: str,
     module_name: str,
     shared: bool = False,
     reserve: bool = False,
     host_address: int = None,
     managed_object: any = None,
 ):
     if address % 0x1000 != 0:
         raise ValueError("invalid argument: address not aligned")
     if size <= 0:
         raise ValueError("invalid argument: size invalid")
     size = align(size)
     self.emu = emu
     self.address = address
     self.size = size
     self.prot = prot
     self.name = name
     self.kind = kind
     self.module_name = module_name
     self.reserved = reserve
     self.shared = shared
     if host_address is None:
         self._managed_object = ctypes.create_string_buffer(size)
         host_pointer = ctypes.cast(self._managed_object,
                                    ctypes.POINTER(ctypes.c_char))
         self.host_address = ctypes.addressof(host_pointer.contents)
     else:
         self.host_address = host_address
         self._managed_object = managed_object
     self.host_data = (ctypes.c_char * size).from_address(self.host_address)
Beispiel #21
0
    def map_anywhere(
        self,
        size: int,
        name: str = "",
        kind: str = "",
        min_addr: int = 0,
        max_addr: int = 0xFFFFFFFFFFFFFFFF,
        alignment: int = 0x1000,
        prot: int = ProtType.RWX,
    ) -> 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.
            name: String used to identify mapped region. Used for
                debugging.
            kind: String used to identify the purpose of the mapped
                region. Used for debugging.
            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.
            prot: RWX permissions of the mapped region. Defaults to
                granting all permissions.
        Returns:
            Start address of mapped region.
        """
        address = self._find_free_space(size,
                                        min_addr=min_addr,
                                        max_addr=max_addr,
                                        alignment=alignment)
        self.map(address, util.align(size), name, kind)
        return address
Beispiel #22
0
def _write_dirent_x86_64(sm, p, full_name, basename, struct_start,
                         prev_struct_start, max_addr):
    struct_len = align(len(basename) + 2 + 0x12, 4)
    if struct_start + struct_len > max_addr:
        return 0

    library_path = sm.z.files.find_library(full_name)
    if library_path is None or not path.exists(library_path):
        return -1

    statinfo = os.stat(library_path)
    p.memory.write_uint64(struct_start, statinfo.st_ino)
    # This will be overridden in the next call to this func
    p.memory.write_uint64(struct_start + 0x8, 0)  # next struct_start
    p.memory.write_uint16(struct_start + 0x10, struct_len)
    p.memory.write_string(struct_start + 0x12,
                          basename,
                          terminal_null_byte=True)
    p.memory.write_uint8(struct_start + struct_len - 1, 8)  # regular

    if prev_struct_start is not None:
        p.memory.write_uint64(prev_struct_start + 0x8, struct_start)

    return struct_len
Beispiel #23
0
    def parse(self, path, binary):
        # Get symbols for the target dynamic binary before we replace
        # it with the loader in the loading process. Keep in mind,
        # these still need to be relocated.
        # TODO: Need OS agnostic place to put this information
        self._elf_dynamic_import_addrs = {
            x.symbol.name: x.address
            for x in binary.pltgot_relocations
        }
        self._target_entrypoint = binary.entrypoint
        self._target_imagebase = binary.imagebase

        interpreter = self._get_interpreter(binary)
        if interpreter is not None:
            # TODO: automatically do setup to run dynamic linux binaries
            (path, binary) = self._setup_dynamic_binary(interpreter, binary)
        self.Filepath = path
        self.binary = binary

        # Refer parsed binary and symbols for better logging
        # @@NOTE binary.get_function_address on binary.symbols invokes
        # a _lot_ of brk()
        functions = {}
        for symbol in binary.static_symbols:
            if symbol.is_function:
                text_sections = binary.get_section(".text")
                text_va = text_sections.virtual_address
                text_offset = text_sections.offset
                text_base = text_va - text_offset
                symbol_offset = symbol.value - text_base
                if symbol_offset > 0:
                    functions[symbol.value] = symbol.name
        self.exported_functions = functions

        # Parse Architecture
        machine = binary.header.machine_type
        if machine == lief.ELF.ARCH.i386:
            self.Architecture = "x86"
            self.Mode = "32"
            self.Bits = 32
        elif machine == lief.ELF.ARCH.x86_64:
            self.Architecture = "x86_64"
            self.Mode = "64"
            self.Bits = 64
        elif machine == lief.ELF.ARCH.ARM:
            self.Architecture = "arm"
            self.Mode = "32"
            self.Bits = 32
        # When looking at other archs, this gives information about
        # stack for arm:
        # https://stackoverflow.com/questions/1802783/initial-state-of-program-registers-and-stack-on-linux-arm/6002815#6002815
        elif machine == lief.ELF.ARCH.MIPS:
            self.Architecture = "mips"
            self.mode = "32"
            self.bits = 32
        else:
            raise UnsupportedBinaryError(f"Unsupported arch {machine} for ELF")

        if binary.is_pie:
            raise UnsupportedBinaryError("Can't handle PIE binaries")

        self.Data = [0] * binary.virtual_size

        # TODO: More time should be invested here to figure out whether
        # this is legit.
        # lets arbitrarily load things at 0x0b000000
        self.logger.debug(f"Binary's imagebase is {binary.imagebase:x}")
        relocated_base = 0 if binary.imagebase != 0 else 0xB000000
        base = relocated_base + binary.imagebase
        self.base = base

        # Only load segments that are the LOAD type.
        segments_to_load = []
        for s in binary.segments:
            if s.type == lief.ELF.SEGMENT_TYPES.LOAD:
                segments_to_load.append(s)
        if len(segments_to_load) == 0:
            raise UnsupportedBinaryError("No loadable segment")

        for segment in segments_to_load:

            virtual_offset = segment.virtual_address - binary.imagebase
            self.Data[virtual_offset:virtual_offset +
                      len(segment.content)] = segment.content
            self.logger.debug(
                f"Load segment from {binary.imagebase + virtual_offset:x} to"
                f" {binary.imagebase+virtual_offset+len(segment.content):x}")
            for s in segment.sections:
                section = Section()
                section.Name = s.name
                alignment = s.alignment
                section.Size = util.align(s.size, alignment)
                section.VirtualSize = util.align(s.size, alignment)
                section.Address = relocated_base + s.virtual_address
                section.Permissions = 7
                section.Alignment = 0 if s.alignment < 2 else s.alignment
                # print(s)
                # print(dir(s))
                self.Sections.append(section)
                offset = section.Address - self.base
                self.logger.verbose(
                    "Adding data for section %s at offset %x of size %x",
                    s.name,
                    offset,
                    len(s.content),
                )

        # Load the ELF header and the program/section headers.
        ph_offset = binary.header.program_header_offset
        ph_data_size = (binary.header.program_header_size *
                        binary.header.numberof_segments)
        self.Data[:ph_offset +
                  ph_data_size] = binary.get_content_from_virtual_address(
                      binary.imagebase, ph_offset + ph_data_size)

        self.set_tls_data(binary)

        # Set Misc. Binary Attributes
        self.Filename = basename(self.Filepath)
        self.Shortname = splitext(self.Filename)[0]
        self.ImageBase = base
        self.EntryPoint = relocated_base + binary.entrypoint
        self.VirtualSize = binary.virtual_size
        self.HeaderAddress = base + binary.header.program_header_offset
        self.HeaderSize = binary.header.program_header_size
        self.NumberOfProgramHeaders = binary.header.numberof_segments
        return
Beispiel #24
0
    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