Beispiel #1
0
 def load(self, file, process, entrypoint_override=None):
     if self.chosen_os is None:
         raise UnsupportedBinaryError(
             f"No supported parser was identified during parsing")
     self.chosen_os.load(file,
                         process,
                         entrypoint_override=entrypoint_override)
Beispiel #2
0
    def _parse_file_data(self, filename, filedata):
        parsed_file = self.os_plugins.parse(filename, filedata)

        if parsed_file is not None:
            assert len(parsed_file.Data) > 0, "File has no data"
            return parsed_file
        raise UnsupportedBinaryError(f"{filename} is unsupported file format")
Beispiel #3
0
    def parse(self, path, binary):
        if self.chosen_os is not None:
            return self.chosen_os.parse(path, binary)

        for os_plugin in self._registered_os_plugins:
            parsed_file = os_plugin.parse(path, binary)
            if parsed_file is not None:
                self.chosen_os = os_plugin
                return parsed_file
        raise UnsupportedBinaryError(
            f"File {path} does not have a supported parser")
Beispiel #4
0
    def _find_interpreter(self, requested_interpreter, binary):
        if requested_interpreter == "":
            self.logger.notice("Requested interpreter is blank")
        linker_path = self._files.emulated_path_to_host_path(
            requested_interpreter)
        if linker_path is not None and exists(linker_path):
            return linker_path

        machine = binary.header.machine_type
        if machine == lief.ELF.ARCH.i386:
            path = "/lib/ld-linux.so.2"
        elif machine == lief.ELF.ARCH.ARM:
            path = "/lib/ld-linux.so.3"
        else:
            self.logger.notice("No default interpreter for this arch")
            return ""
        self.logger.verbose(f"Attempting with default linker {path}")
        default_linker_path = self._files.emulated_path_to_host_path(path)
        if default_linker_path is not None and exists(default_linker_path):
            return default_linker_path
        raise UnsupportedBinaryError(
            f"Couldn't find linker {requested_interpreter}")
Beispiel #5
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