示例#1
0
 def uc_get_pc(self, uc) -> int:
     """
     Gets the current pc from unicorn for this arch
     :param uc: the unicorn instance
     :return: value of the pc
     """
     return uc_get_pc(uc, self.arch)
示例#2
0
 def uc_run(self, uc: Uc, entry_point: int, exit_point: int) -> None:
     """
     Run initialized unicorn
     :param entry_point: The entry point
     :param exit_point: First final address. Hack something to get more exits
     :param uc: The unicorn instance to run
     """
     try:
         uc.emu_start(begin=entry_point, until=exit_point, timeout=0, count=0)
     except UcError as e:
         print(
             "[!] Execution failed with error: {} at address {:x}".format(
                 e, uc_get_pc(uc, self.arch)
             )
         )
         self.force_crash(e)
     # Exit without clean python vm shutdown:
     # "The os._exit() function can be used if it is absolutely positively necessary to exit immediately"
     # Many times faster!
     os._exit(0)
示例#3
0
    def uc_init(
        self, input_file, wait: bool = False, trace: bool = False, verbose: bool = False
    ) -> Tuple[Uc, int, List[int]]:
        """
        Initializes unicorn with the given params
        :param input_file: input file to drop into the emulator with config.init_func
        :param wait: block until state dir becomes available
        :param trace: if we should add trace hooks to unicorn
        :param verbose: enables some more logging
        :return: Tuple of (unicorn, entry_point, exits)
        """
        config = self.config
        uc = Uc(self.arch.unicorn_arch, self.arch.unicorn_mode)

        if trace:
            print("[+] Settings trace hooks")
            uc.hook_add(UC_HOOK_BLOCK, unicorn_debug_block)
            uc.hook_add(UC_HOOK_CODE, unicorn_debug_instruction, self)
            uc.hook_add(
                UC_HOOK_MEM_WRITE | UC_HOOK_MEM_READ | UC_HOOK_MEM_FETCH,
                unicorn_debug_mem_access,
            )

        if wait:
            self.wait_for_probe_wrapper()

        if verbose:
            print("[*] Reading from file {}".format(input_file))

        # we leave out gs_base and fs_base on x64 since they start the forkserver
        self.uc_load_registers(uc)

        # let's see if the user wants a change.
        config.init_func(self, uc)

        # get pc from unicorn state since init_func may have altered it.
        pc = uc_get_pc(uc, self.arch)
        exits = self.calculate_exits(pc)
        # mappings used in init_func didn't have the pc yet.
        for ex in self._deferred_exits:
            self.set_exits(uc, ex, exits)
        self.map_known_mem(uc)
        if not exits:
            raise ValueError(
                "No exits founds. Would run forever... Please set an exit address in config.py."
            )
        entry_point = pc

        # On error: map memory, add exits.
        uc.hook_add(UC_HOOK_MEM_UNMAPPED, unicorn_debug_mem_invalid_access, self)

        if len(exits) > 1:
            # unicorn supports a single exit only (using the length param).
            # We'll path the binary on load if we have need to support more.
            if self.arch == X64:
                uc.hook_add(
                    UC_HOOK_INSN,
                    syscall_exit_hook,
                    user_data=(exits, os._exit),
                    arg1=UC_X86_INS_SYSCALL,
                )
            else:
                # TODO: (Fast) solution for X86, ARM, ...
                raise Exception(
                    "Multiple exits not yet supported for arch {}".format(self.arch)
                )

        # starts the afl forkserver
        self.uc_start_forkserver(uc)

        input_file = open(input_file, "rb")  # load afl's input
        input = input_file.read()
        input_file.close()

        try:
            config.place_input(self, uc, input)
        except Exception as ex:
            raise Exception(
                "[!] Error setting testcase for input {}: {}".format(input, ex)
            )
        return uc, entry_point, exits