Exemple #1
0
    def test_create_args(self):
        arg_factory = ArgFactory(lambda arg: "")

        args = arg_factory.gen_args(
            [("int", "fd"), ("void*", "buf"), ("size_t", "count")],
            [0x4, 0xDEADBEEF, 0x10],
        )
        self.assertEqual(args.fd, 0x4)
        self.assertEqual(args.buf, 0xDEADBEEF)
        self.assertEqual(args.count, 0x10)
Exemple #2
0
    def __init__(self, arch, engine):
        super(LinuxSyscallManager, self).__init__(engine)
        self.arch = arch
        self.call_map = self.__load_linux_syscall_maps(arch)
        self._name2syscall_func = self._load_linux_syscall_funcs()
        self.rev_map = {v: k for k, v in self.call_map.items()}

        self.offset_dict = defaultdict(int)

        self.arg_factory = ArgFactory(functools.partial(
            get_arg_string, self.z))

        self.socketcall_dict = {
            1: "socket",
            2: "bind",
            3: "connect",
            4: "listen",
            5: "accept",
            6: "getsockname",
            7: "getpeername",
            8: "socketpair",
            9: "send",
            10: "recv",
            11: "sendto",
            12: "recvfrom",
            13: "shutdown",
            14: "setsockopt",
            15: "getsockopt",
            16: "sendmsg",
            17: "recvmsg",
            18: "accept4",
            19: "recvmmsg",
            20: "sendmmsg",
        }

        # These are processes that are exited, and so a parent process
        # can wait on them.
        # parent_pid -> child_pid
        self.child_state_changes = defaultdict(list)
Exemple #3
0
class LinuxKernel(IKernel):
    def __init__(self, arch, engine):
        super(LinuxKernel, self).__init__(engine)
        self.arch = arch
        self.call_map = self.__load_linux_syscall_maps(arch)
        self._name2syscall_func = self._load_linux_syscall_funcs()
        self.rev_map = {v: k for k, v in self.call_map.items()}

        self.arg_factory = ArgFactory(functools.partial(
            get_arg_string, self.z))

        self.socketcall_dict = {
            1: "socket",
            2: "bind",
            3: "connect",
            4: "listen",
            5: "accept",
            6: "getsockname",
            7: "getpeername",
            8: "socketpair",
            9: "send",
            10: "recv",
            11: "sendto",
            12: "recvfrom",
            13: "shutdown",
            14: "setsockopt",
            15: "getsockopt",
            16: "sendmsg",
            17: "recvmsg",
            18: "accept4",
            19: "recvmmsg",
            20: "sendmmsg",
        }

        # These are processes that are exited, and so a parent process
        # can wait on them.
        # parent_pid -> child_pid
        self.child_state_changes = defaultdict(list)

    def _load_linux_syscall_funcs(
        self, ) -> Dict[str, Callable[[any], Optional[int]]]:
        """
        Returns map of name -> syscall implementation.
        """
        from .syscalls import syscalls as linux_syscall_module

        linux_syscalls = inspect.getmembers(linux_syscall_module,
                                            inspect.isfunction)

        return {
            name.partition("sys_")[-1]: func
            for name, func in linux_syscalls if name.startswith("sys_")
        }

    def __load_linux_syscall_maps(self, arch):
        """
        Loads the list of supported syscalls from the syscalls table.
        """
        from .syscalls.syscalls_table import cols, table

        try:
            i = cols.index(arch)
        except ValueError:
            raise ZelosException(f"Invalid architecture '{arch}'")

        return {k: v[i] for (k, v) in table.items() if v[i] != -1}

    def handle_syscall(self, process):
        """
        Additionally translate `socketcall` syscalls to their target
        socket system call, e.g. `recv`, for the purpose of syscall
        breaks. This ensures that breakpoints for `recv` will be
        triggered both for `recv` and `socketcall` syscalls that invoke
        `recv`, etc.
        """
        sys_num = self.get_syscall_number()
        sys_name = self.find_syscall_name_by_number(sys_num)
        if sys_name == "socketcall":
            socketcall_args = self.get_last_syscall_args()
            args = self.get_args(
                [("int", "call"), ("unsigned long *", "callargs")],
                sys_num=sys_num,
            )
        status = super(LinuxKernel, self).handle_syscall(process)
        if sys_name == "socketcall":
            socketcall = self.socketcall_dict.get(args.call, None)
            if socketcall is not None:
                self.last_syscall_args = socketcall_args
                self._handle_syscall_break(socketcall)
        return status

    def set_errno(self, val):
        pass

    def _get_socketcall_args(self,
                             process,
                             func_name,
                             args_addr,
                             arg_list,
                             arg_string_overrides={}):
        # If calling these syscalls directly, get_args the old
        # fashioned way.
        if args_addr < 0:
            return self.get_args(arg_list, arg_string_overrides)

        arg_vals = [
            process.memory.read_int(args_addr + i * 4)
            for i in range(len(arg_list))
        ]
        args = self.arg_factory.gen_args(
            arg_list, arg_vals, arg_string_overrides=arg_string_overrides)
        self.last_syscall_args = args
        self._print_socket_syscall(func_name, args)
        return args

    def _print_socket_syscall(self, func_name, args):
        s = colored(f"{func_name}", "white", attrs=["bold"]) + f" ( {args} )"
        self.z.plugins.trace.print("SOCKET SYSCALL", s)

    ####################
    # HELPER FUNCTIONS #
    ####################

    def get_args(self, arg_list, arg_string_overrides={}, sys_num=None):
        """
        Gets arguments according to linux syscall calling convention
        """
        z = self.z
        if sys_num is None:
            sys_num = self.get_syscall_number()
        reg_list = self._REG_ARGS

        arg_regs = reg_list[:len(arg_list)]

        arg_vals = [z.current_thread.get_reg(arg) for arg in arg_regs]

        # Get the rest of the arguments off of the stack
        i = len(arg_vals)
        while len(arg_vals) < len(arg_list):
            arg_vals.append(self.emu.getstack(i))
            i += 1
        args = self.arg_factory.gen_args(
            arg_list, arg_vals, arg_string_overrides=arg_string_overrides)
        self.last_syscall_args = args
        return args