Example #1
0
    def hook_winapi(self, ql: Qiling, address: int, size: int):
        if address in ql.loader.import_symbols:
            entry = ql.loader.import_symbols[address]
            api_name = entry['name']

            if api_name is None:
                api_name = const.Mapper[entry['dll']][entry['ordinal']]
            else:
                api_name = api_name.decode()

            api_func = self.user_defined_api[QL_INTERCEPT.CALL].get(api_name)

            if not api_func:
                api_func = getattr(api, f'hook_{api_name}', None)

                self.syscall_count.setdefault(api_name, 0)
                self.syscall_count[api_name] += 1

            if api_func:
                try:
                    api_func(ql, address, api_name)
                except Exception as ex:
                    ql.log.exception(ex)
                    ql.log.debug("%s Exception Found" % api_name)

                    raise QlErrorSyscallError("Windows API Implementation Error")
            else:
                ql.log.warning(f'api {api_name} is not implemented')

                if ql.debug_stop:
                    raise QlErrorSyscallNotFound("Windows API implementation not found")
Example #2
0
def hook_kernel_api(ql: Qiling, address: int, size: int):
    # call kernel api
    if address in ql.loader.import_symbols:
        api_name = ql.loader.import_symbols[address]
        # print("OK, found hook for %s" %api_name)

        api_func = ql.os.user_defined_api[QL_INTERCEPT.CALL].get(api_name)

        if not api_func:
            api_func = getattr(api, f'hook_{api_name}', None)

        if api_func:
            try:
                api_func(ql, address, api_name)
            except Exception:
                ql.log.exception("")
                ql.log.debug("%s Exception Found" % api_name)

                raise QlErrorSyscallError(
                    "MacOS kernel API Implementation Error")
        else:
            ql.log.warning(f'api {api_name} is not implemented')

            if ql.debug_stop:
                raise QlErrorSyscallNotFound(
                    "MacOS kernel API implementation not found")
Example #3
0
    def load_syscall(self):
        syscall_id = self.get_syscall()
        syscall_name = self.syscall_mapper(syscall_id)

        # get syscall on-enter hook (if any)
        hooks_dict = self.posix_syscall_hooks[QL_INTERCEPT.ENTER]
        onenter_hook = hooks_dict.get(syscall_name) or hooks_dict.get(syscall_id)

        # get syscall on-exit hook (if any)
        hooks_dict = self.posix_syscall_hooks[QL_INTERCEPT.EXIT]
        onexit_hook = hooks_dict.get(syscall_name) or hooks_dict.get(syscall_id)

        # get syscall replacement hook (if any)
        hooks_dict = self.posix_syscall_hooks[QL_INTERCEPT.CALL]
        syscall_hook = hooks_dict.get(syscall_name) or hooks_dict.get(syscall_id)

        if not syscall_hook:
            def __get_os_module(osname: str):
                return ql_get_module(f'.os.{osname.lower()}.syscall')

            os_syscalls = __get_os_module(self.type.name)
            posix_syscalls = __get_os_module('posix')

            # look in os-specific and posix syscall hooks
            syscall_hook = getattr(os_syscalls, syscall_name, None) or getattr(posix_syscalls, syscall_name, None)

        if syscall_hook:
            syscall_name = syscall_hook.__name__

            # extract the parameters list from hook signature
            param_names = tuple(signature(syscall_hook).parameters.values())

            # skip first arg (always 'ql') and filter out python special args (*args and **kwargs)
            param_names = [info.name for info in param_names[1:] if info.kind == Parameter.POSITIONAL_OR_KEYWORD]

            # read parameter values
            params = [self.__syscall_cc.getRawParam(i) for i in range(len(param_names))]

            try:
        		# if set, fire up the on-enter hook and let it override original args set
                if onenter_hook:
                    overrides = onenter_hook(self.ql, *params)

                    if overrides is not None:
                        _, params = overrides

        		# perform syscall
                retval = syscall_hook(self.ql, *params)

                # if set, fire up the on-exit hook and let it override the return value
                if onexit_hook:
                    override = onexit_hook(self.ql, *params, retval)

                    if override is not None:
                        retval = override

                # set return value
                if retval is not None:
                    self.__syscall_cc.setReturnValue(retval)

            except KeyboardInterrupt:
                raise

            except Exception as e:
                self.ql.log.exception(f'Syscall ERROR: {syscall_name} DEBUG: {e}')
                raise e

            # print out log entry
            syscall_basename = syscall_name[len(SYSCALL_PREF) if syscall_name.startswith(SYSCALL_PREF) else 0:] 

            args = []

            for name, value in zip(param_names, params):
                # cut the first part of the arg if it is of form fstatat64_fd
                if name.startswith(f'{syscall_basename}_'):
                    name = name.partition('_')[-1]

                args.append((name, f'{value:#x}'))

            sret = QlOsPosix.getNameFromErrorCode(retval)
            self.utils.print_function(self.ql.arch.regs.arch_pc, syscall_basename, args, sret, False)

            # record syscall statistics
            self.stats.log_api_call(self.ql.arch.regs.arch_pc, syscall_name, dict(zip(param_names, params)), retval, None)
        else:
            self.ql.log.warning(f'{self.ql.arch.regs.arch_pc:#x}: syscall {syscall_name} number = {syscall_id:#x}({syscall_id:d}) not implemented')

            if self.ql.debug_stop:
                raise QlErrorSyscallNotFound(f'Syscall not found: {syscall_name}')
Example #4
0
    def load_syscall(self):
        # import syscall mapping function
        map_syscall = ql_syscall_mapping_function(self.ql.ostype)
        syscall = self.syscall
        syscall_name = map_syscall(self.ql, syscall)

        # get syscall on-enter hook (if any)
        hooks_dict = self.posix_syscall_hooks[QL_INTERCEPT.ENTER]
        onenter_hook = hooks_dict.get(syscall_name) or hooks_dict.get(syscall)

        # get syscall on-exit hook (if any)
        hooks_dict = self.posix_syscall_hooks[QL_INTERCEPT.EXIT]
        onexit_hook = hooks_dict.get(syscall_name) or hooks_dict.get(syscall)

        # get syscall replacement hook (if any)
        hooks_dict = self.posix_syscall_hooks[QL_INTERCEPT.CALL]
        syscall_hook = hooks_dict.get(syscall_name) or hooks_dict.get(syscall)

        if syscall_hook:
            syscall_name = syscall_hook.__name__
        else:
            _ostype_str = ostype_convert_str(self.ql.ostype)
            _posix_syscall = ql_get_module_function(f"qiling.os.posix",
                                                    "syscall")
            _os_syscall = ql_get_module_function(
                f"qiling.os.{_ostype_str.lower()}", "syscall")

            if syscall_name in dir(_posix_syscall) or syscall_name in dir(
                    _os_syscall):
                syscall_hook = eval(syscall_name)
                syscall_name = syscall_hook.__name__
            else:
                syscall_hook = None

        if syscall_hook:
            args = self.get_syscall_args()

            self.utils.syscalls.setdefault(syscall_name, []).append({
                "params": {
                    "param0": args[0],
                    "param1": args[1],
                    "param2": args[2],
                    "param3": args[3],
                    "param4": args[4],
                    "param5": args[5]
                },
                "result":
                None,
                "address":
                self.ql.reg.arch_pc,
                "return_address":
                None,
                "position":
                self.utils.syscalls_counter
            })

            self.utils.syscalls_counter += 1

            try:

                if onenter_hook is not None:
                    onenter_hook(self.ql, *self.get_syscall_args())

                syscall_basename = syscall_hook.__name__[len(SYSCALL_PREF):]
                args = []

                # ignore first arg, which is 'ql'
                arg_names = tuple(
                    signature(syscall_hook).parameters.values())[1:]
                arg_values = self.get_syscall_args()

                for name, value in zip(arg_names, arg_values):
                    name = str(name)

                    # ignore python special args
                    if name in ('*args', '**kw', '**kwargs'):
                        continue

                    # cut the first part of the arg if it is of form fstatat64_fd
                    if name.startswith(f'{syscall_basename}_'):
                        name = name.partition('_')[-1]

                    args.append(f'{name} = {value:#x}')

                faddr = f'{self.ql.reg.arch_pc:#0{self.ql.archbit // 4 + 2}x}: ' if self.ql.verbose >= QL_VERBOSE.DEBUG else ''
                fargs = ', '.join(args)

                log = f'{faddr}{syscall_basename}({fargs})'

                if self.ql.verbose >= QL_VERBOSE.DEBUG:
                    self.ql.log.debug(log)
                else:
                    self.ql.log.info(log)

                ret = syscall_hook(self.ql, *arg_values)

                if ret is not None and type(ret) is int:
                    # each name has a list of calls, we want the last one and we want to update the return value
                    self.utils.syscalls[syscall_name][-1]["result"] = ret
                    ret = self.set_syscall_return(ret)
                    self.ql.log.debug(
                        f'{syscall_basename}() = {QlOsPosix.getNameFromErrorCode(ret)}'
                    )

                if onexit_hook is not None:
                    onexit_hook(self.ql, *self.get_syscall_args())

            except KeyboardInterrupt:
                raise
            except Exception as e:
                self.ql.log.exception("")
                self.ql.log.info(f'Syscall ERROR: {syscall_name} DEBUG: {e}')
                raise e
        else:
            self.ql.log.warning(
                f'{self.ql.reg.arch_pc:#x}: syscall {syscall_name} number = {syscall:#x}({syscall:d}) not implemented'
            )

            if self.ql.debug_stop:
                raise QlErrorSyscallNotFound("Syscall Not Found")