#!/usr/bin/python from pyoida import Plugin from pyoida.analysis import RenderingOptions from pyoida.arch import ArchProcessorType class SysCallDB(): """xxx""" def __init__(self): self.__syscalls = [ "__NR_restart_syscall", "__NR_exit", "__NR_fork", "__NR_read", "__NR_write", "__NR_open", "__NR_close", "__NR_waitpid", "__NR_creat", "__NR_link", "__NR_unlink", "__NR_execve", "__NR_chdir", "__NR_time", "__NR_mknod", "__NR_chmod", "__NR_lchown", "__NR_break", "__NR_oldstat", "__NR_lseek", "__NR_getpid", "__NR_mount", "__NR_umount", "__NR_setuid", "__NR_getuid", "__NR_stime", "__NR_ptrace", "__NR_alarm", "__NR_oldfstat", "__NR_pause", "__NR_utime", "__NR_stty", "__NR_gtty", "__NR_access", "__NR_nice", "__NR_ftime", "__NR_sync", "__NR_kill", "__NR_rename", "__NR_mkdir", "__NR_rmdir", "__NR_dup", "__NR_pipe", "__NR_times", "__NR_prof", "__NR_brk", "__NR_setgid", "__NR_getgid", "__NR_signal", "__NR_geteuid", "__NR_getegid", "__NR_acct", "__NR_umount2", "__NR_lock", "__NR_ioctl", "__NR_fcntl", "__NR_mpx", "__NR_setpgid", "__NR_ulimit", "__NR_oldolduname", "__NR_umask", "__NR_chroot", "__NR_ustat", "__NR_dup2", "__NR_getppid", "__NR_getpgrp", "__NR_setsid", "__NR_sigaction", "__NR_sgetmask", "__NR_ssetmask", "__NR_setreuid", "__NR_setregid", "__NR_sigsuspend", "__NR_sigpending", "__NR_sethostname", "__NR_setrlimit", "__NR_getrlimit", "__NR_getrusage", "__NR_gettimeofday", "__NR_settimeofday", "__NR_getgroups", "__NR_setgroups", "__NR_select", "__NR_symlink", "__NR_oldlstat", "__NR_readlink", "__NR_uselib", "__NR_swapon", "__NR_reboot", "__NR_readdir", "__NR_mmap", "__NR_munmap", "__NR_truncate", "__NR_ftruncate", "__NR_fchmod", "__NR_fchown", "__NR_getpriority", "__NR_setpriority", "__NR_profil", "__NR_statfs", "__NR_fstatfs", "__NR_ioperm", "__NR_socketcall", "__NR_syslog", "__NR_setitimer", "__NR_getitimer", "__NR_stat", "__NR_lstat", "__NR_fstat", "__NR_olduname", "__NR_iopl", "__NR_vhangup", "__NR_idle", "__NR_vm86old", "__NR_wait4", "__NR_swapoff", "__NR_sysinfo", "__NR_ipc", "__NR_fsync", "__NR_sigreturn", "__NR_clone", "__NR_setdomainname", "__NR_uname", "__NR_modify_ldt", "__NR_adjtimex", "__NR_mprotect", "__NR_sigprocmask", "__NR_create_module", "__NR_init_module", "__NR_delete_module", "__NR_get_kernel_syms", "__NR_quotactl", "__NR_getpgid", "__NR_fchdir", "__NR_bdflush", "__NR_sysfs", "__NR_personality", "__NR_afs_syscall", "__NR_setfsuid", "__NR_setfsgid", "__NR__llseek", "__NR_getdents", "__NR__newselect", "__NR_flock", "__NR_msync", "__NR_readv", "__NR_writev", "__NR_getsid", "__NR_fdatasync", "__NR__sysctl", "__NR_mlock", "__NR_munlock", "__NR_mlockall", "__NR_munlockall", "__NR_sched_setparam", "__NR_sched_getparam", "__NR_sched_setscheduler", "__NR_sched_getscheduler", "__NR_sched_yield", "__NR_sched_get_priority_max", "__NR_sched_get_priority_min", "__NR_sched_rr_get_interval", "__NR_nanosleep", "__NR_mremap", "__NR_setresuid", "__NR_getresuid", "__NR_vm86", "__NR_query_module", "__NR_poll", "__NR_nfsservctl", "__NR_setresgid", "__NR_getresgid", "__NR_prctl", "__NR_rt_sigreturn", "__NR_rt_sigaction", "__NR_rt_sigprocmask", "__NR_rt_sigpending", "__NR_rt_sigtimedwait", "__NR_rt_sigqueueinfo", "__NR_rt_sigsuspend", "__NR_pread64", "__NR_pwrite64", "__NR_chown", "__NR_getcwd", "__NR_capget", "__NR_capset", "__NR_sigaltstack", "__NR_sendfile", "__NR_getpmsg", "__NR_putpmsg", "__NR_vfork", "__NR_ugetrlimit", "__NR_mmap2", "__NR_truncate64", "__NR_ftruncate64", "__NR_stat64", "__NR_lstat64", "__NR_fstat64", "__NR_lchown32", "__NR_getuid32", "__NR_getgid32", "__NR_geteuid32", "__NR_getegid32", "__NR_setreuid32", "__NR_setregid32", "__NR_getgroups32", "__NR_setgroups32", "__NR_fchown32", "__NR_setresuid32", "__NR_getresuid32", "__NR_setresgid32", "__NR_getresgid32", "__NR_chown32", "__NR_setuid32", "__NR_setgid32", "__NR_setfsuid32", "__NR_setfsgid32", "__NR_pivot_root", "__NR_mincore", "__NR_madvise", "__NR_madvise1", "__NR_getdents64", "__NR_fcntl64", "__NR_unused", "__NR_gettid", "__NR_readahead", "__NR_setxattr", "__NR_lsetxattr", "__NR_fsetxattr", "__NR_getxattr", "__NR_lgetxattr", "__NR_fgetxattr", "__NR_listxattr", "__NR_llistxattr", "__NR_flistxattr", "__NR_removexattr", "__NR_lremovexattr", "__NR_fremovexattr", "__NR_tkill", "__NR_sendfile64", "__NR_futex", "__NR_sched_setaffinity", "__NR_sched_getaffinity", "__NR_set_thread_area", "__NR_get_thread_area", "__NR_io_setup", "__NR_io_destroy", "__NR_io_getevents", "__NR_io_submit", "__NR_io_cancel", "__NR_fadvise64", "__NR_unused", "__NR_exit_group", "__NR_lookup_dcookie", "__NR_epoll_create", "__NR_epoll_ctl", "__NR_epoll_wait", "__NR_remap_file_pages", "__NR_set_tid_address", "__NR_timer_create", "__NR_timer_settime", "__NR_timer_gettime", "__NR_timer_getoverrun", "__NR_timer_delete", "__NR_clock_settime", "__NR_clock_gettime", "__NR_clock_getres", "__NR_clock_nanosleep", "__NR_statfs64", "__NR_fstatfs64", "__NR_tgkill", "__NR_utimes", "__NR_fadvise64_64", "__NR_vserver", "__NR_mbind", "__NR_get_mempolicy", "__NR_set_mempolicy", "__NR_mq_open", "__NR_mq_unlink", "__NR_mq_timedsend", "__NR_mq_timedreceive", "__NR_mq_notify", "__NR_mq_getsetattr", "__NR_kexec_load", "__NR_waitid", "__NR_sys_setaltroot", "__NR_add_key", "__NR_request_key", "__NR_keyctl", "__NR_ioprio_set", "__NR_ioprio_get", "__NR_inotify_init", "__NR_inotify_add_watch", "__NR_inotify_rm_watch", "__NR_migrate_pages", "__NR_openat", "__NR_mkdirat", "__NR_mknodat", "__NR_fchownat", "__NR_futimesat", "__NR_fstatat64", "__NR_unlinkat", "__NR_renameat", "__NR_linkat", "__NR_symlinkat", "__NR_readlinkat", "__NR_fchmodat", "__NR_faccessat", "__NR_pselect6", "__NR_ppoll", "__NR_unshare", "__NR_set_robust_list", "__NR_get_robust_list", "__NR_splice", "__NR_sync_file_range", "__NR_tee", "__NR_vmsplice", "__NR_move_pages", "__NR_getcpu", "__NR_epoll_pwait", "__NR_utimensat", "__NR_signalfd", "__NR_timerfd_create", "__NR_eventfd", "__NR_fallocate", "__NR_timerfd_settime", "__NR_timerfd_gettime", "__NR_signalfd4", "__NR_eventfd2", "__NR_epoll_create1", "__NR_dup3", "__NR_pipe2", "__NR_inotify_init1", "__NR_preadv", "__NR_pwritev", "__NR_rt_tgsigqueueinfo", "__NR_perf_event_open" ] self.__args = { "sys_restart_syscall" : [], "sys_exit" : ["int error_code"], "sys_write" : ["unsigned int fd", "const char __user *buf", "size_t count"] } def get_syscall_name(self, index): """Convert a syscall index into a human name.""" return self.__syscalls[index] def get_syscall_args(self, name): """Provide the function name, the needed registers and the used arguments of a syscall.""" name = name.replace("__NR_", "sys_") try: args = self.__args[name] except: return None targets = {} if len(args) >= 4: pass else: registers = ["ebx", "ecx", "edx", "esi", "edi"] i = 0 for val in args: targets[registers[i]] = val i = i + 1 return [name, targets] class LinuxSysCallsPlugin(Plugin): """A simple example class""" def __rendering_options(self, binary): """Build the options needed to get the ASM code only.""" exe = binary.get_format() ropts = RenderingOptions(exe) ropts.show_code(True) ropts.show_address = False return ropts def __is_syscall(self, code): """Tell weither the ASM line of code is a syscall or not.""" result = False if code.find("int") != -1: list = code.split("\t") if len(list) == 2: result = list == ["int", "0x80"] return result def __find_used_register(self, ropts, start, target): """Look for a given register used to supply argument for a syscall.""" for found in reversed(start): code = found.get_text(ropts) parts = code.expandtabs(1).replace(",", "").split(" ") # Next registers are used by a new interruption if parts[0] == "int": continue # No operand if len(parts) == 1: continue # Only simple cases are processed... if parts[1] == target: if len(parts) == 2: return None else: return [found, parts[2]] return None def run(self, binary): """Resolve all registers / interruptions involved in a syscall.""" db = SysCallDB() ropts = self.__rendering_options(binary) lines = binary.get_lines() for line in lines: code = line.get_text(ropts) if self.__is_syscall(code): # What kind of syscall ? line_eax = self.__find_used_register(ropts, line, "eax") if line_eax is None: line.comment = "== UNIX Syscall ==" continue index = int(line_eax[1], 16) name = db.get_syscall_name(index) line_eax[0].comment = name # What function / arguments ? targets = db.get_syscall_args(name) if targets == None: line.comment = "== UNIX Syscall ==" continue else: line.comment = "== UNIX Syscall to %s() ==" % (targets[0]) for reg, arg in targets[1].items(): found = self.__find_used_register(ropts, line, reg) if found != None: found[0].comment = arg def get_instance(binary): print " --- toto from Python ---" a = LinuxSysCallsPlugin() a.run(binary) return Plugin.PGA_CODE_PROCESS