""" IDAPython plugin to display all system calls of AMD/Intel 32/64bit Linux userland binaries. Work in progress... The system call ABI from the following link are supported. http://esec-lab.sogeti.com/post/2011/07/05/Linux-syscall-ABI by n0p """ from idaapi import * # Taken from /usr/include/asm/unistd_32.h at Arch Linux i686 3.16.3-1. x86SystemCalls = ["sys_restart_syscall", "sys_exit", "sys_fork", "sys_read", "sys_write", "sys_open", "sys_close", "sys_waitpid", "sys_creat", "sys_link", "sys_unlink", "sys_execve", "sys_chdir", "sys_time", "sys_mknod", "sys_chmod", "sys_lchown", "sys_break", "sys_oldstat", "sys_lseek", "sys_getpid", "sys_mount", "sys_umount", "sys_setuid", "sys_getuid", "sys_stime", "sys_ptrace", "sys_alarm", "sys_oldfstat", "sys_pause", "sys_utime", "sys_stty", "sys_gtty", "sys_access", "sys_nice", "sys_ftime", "sys_sync", "sys_kill", "sys_rename", "sys_mkdir", "sys_rmdir", "sys_dup", "sys_pipe", "sys_times", "sys_prof", "sys_brk", "sys_setgid", "sys_getgid", "sys_signal", "sys_geteuid", "sys_getegid", "sys_acct", "sys_umount2", "sys_lock", "sys_ioctl", "sys_fcntl", "sys_mpx", "sys_setpgid", "sys_ulimit", "sys_oldolduname", "sys_umask", "sys_chroot", "sys_ustat", "sys_dup2", "sys_getppid", "sys_getpgrp", "sys_setsid", "sys_sigaction", "sys_sgetmask", "sys_ssetmask", "sys_setreuid", "sys_setregid", "sys_sigsuspend", "sys_sigpending", "sys_sethostname", "sys_setrlimit", "sys_getrlimit", "sys_getrusage", "sys_gettimeofday", "sys_settimeofday", "sys_getgroups", "sys_setgroups", "sys_select", "sys_symlink", "sys_oldlstat", "sys_readlink", "sys_uselib", "sys_swapon", "sys_reboot", "sys_readdir", "sys_mmap", "sys_munmap", "sys_truncate", "sys_ftruncate", "sys_fchmod", "sys_fchown", "sys_getpriority", "sys_setpriority", "sys_profil", "sys_statfs", "sys_fstatfs", "sys_ioperm", "sys_socketcall", "sys_syslog", "sys_setitimer", "sys_getitimer", "sys_stat", "sys_lstat", "sys_fstat", "sys_olduname", "sys_iopl", "sys_vhangup", "sys_idle", "sys_vm86old", "sys_wait4", "sys_swapoff", "sys_sysinfo", "sys_ipc", "sys_fsync", "sys_sigreturn", "sys_clone", "sys_setdomainname", "sys_uname", "sys_modify_ldt", "sys_adjtimex", "sys_mprotect", "sys_sigprocmask", "sys_create_module", "sys_init_module", "sys_delete_module", "sys_get_kernel_syms", "sys_quotactl", "sys_getpgid", "sys_fchdir", "sys_bdflush", "sys_sysfs", "sys_personality", "sys_afs_syscall", "sys_setfsuid", "sys_setfsgid", "sys__llseek", "sys_getdents", "sys__newselect", "sys_flock", "sys_msync", "sys_readv", "sys_writev", "sys_getsid", "sys_fdatasync", "sys__sysctl", "sys_mlock", "sys_munlock", "sys_mlockall", "sys_munlockall", "sys_sched_setparam", "sys_sched_getparam", "sys_sched_setscheduler", "sys_sched_getscheduler", "sys_sched_yield", "sys_sched_get_priority_max", "sys_sched_get_priority_min", "sys_sched_rr_get_interval", "sys_nanosleep", "sys_mremap", "sys_setresuid", "sys_getresuid", "sys_vm86", "sys_query_module", "sys_poll", "sys_nfsservctl", "sys_setresgid", "sys_getresgid", "sys_prctl", "sys_rt_sigreturn", "sys_rt_sigaction", "sys_rt_sigprocmask", "sys_rt_sigpending", "sys_rt_sigtimedwait", "sys_rt_sigqueueinfo", "sys_rt_sigsuspend", "sys_pread64", "sys_pwrite64", "sys_chown", "sys_getcwd", "sys_capget", "sys_capset", "sys_sigaltstack", "sys_sendfile", "sys_getpmsg", "sys_putpmsg", "sys_vfork", "sys_ugetrlimit", "sys_mmap2", "sys_truncate64", "sys_ftruncate64", "sys_stat64", "sys_lstat64", "sys_fstat64", "sys_lchown32", "sys_getuid32", "sys_getgid32", "sys_geteuid32", "sys_getegid32", "sys_setreuid32", "sys_setregid32", "sys_getgroups32", "sys_setgroups32", "sys_fchown32", "sys_setresuid32", "sys_getresuid32", "sys_setresgid32", "sys_getresgid32", "sys_chown32", "sys_setuid32", "sys_setgid32", "sys_setfsuid32", "sys_setfsgid32", "sys_pivot_root", "sys_mincore", "sys_madvise", "sys_getdents64", "sys_fcntl64", "sys_gettid", "sys_readahead", "sys_setxattr", "sys_lsetxattr", "sys_fsetxattr", "sys_getxattr", "sys_lgetxattr", "sys_fgetxattr", "sys_listxattr", "sys_llistxattr", "sys_flistxattr", "sys_removexattr", "sys_lremovexattr", "sys_fremovexattr", "sys_tkill", "sys_sendfile64", "sys_futex", "sys_sched_setaffinity", "sys_sched_getaffinity", "sys_set_thread_area", "sys_get_thread_area", "sys_io_setup", "sys_io_destroy", "sys_io_getevents", "sys_io_submit", "sys_io_cancel", "sys_fadvise64", "sys_exit_group", "sys_lookup_dcookie", "sys_epoll_create", "sys_epoll_ctl", "sys_epoll_wait", "sys_remap_file_pages", "sys_set_tid_address", "sys_timer_create", "sys_timer_settime", "sys_timer_gettime", "sys_timer_getoverrun", "sys_timer_delete", "sys_clock_settime", "sys_clock_gettime", "sys_clock_getres", "sys_clock_nanosleep", "sys_statfs64", "sys_fstatfs64", "sys_tgkill", "sys_utimes", "sys_fadvise64_64", "sys_vserver", "sys_mbind", "sys_get_mempolicy", "sys_set_mempolicy", "sys_mq_open", "sys_mq_unlink", "sys_mq_timedsend", "sys_mq_timedreceive", "sys_mq_notify", "sys_mq_getsetattr", "sys_kexec_load", "sys_waitid", "sys_add_key", "sys_request_key", "sys_keyctl", "sys_ioprio_set", "sys_ioprio_get", "sys_inotify_init", "sys_inotify_add_watch", "sys_inotify_rm_watch", "sys_migrate_pages", "sys_openat", "sys_mkdirat", "sys_mknodat", "sys_fchownat", "sys_futimesat", "sys_fstatat64", "sys_unlinkat", "sys_renameat", "sys_linkat", "sys_symlinkat", "sys_readlinkat", "sys_fchmodat", "sys_faccessat", "sys_pselect6", "sys_ppoll", "sys_unshare", "sys_set_robust_list", "sys_get_robust_list", "sys_splice", "sys_sync_file_range", "sys_tee", "sys_vmsplice", "sys_move_pages", "sys_getcpu", "sys_epoll_pwait", "sys_utimensat", "sys_signalfd", "sys_timerfd_create", "sys_eventfd", "sys_fallocate", "sys_timerfd_settime", "sys_timerfd_gettime", "sys_signalfd4", "sys_eventfd2", "sys_epoll_create1", "sys_dup3", "sys_pipe2", "sys_inotify_init1", "sys_preadv", "sys_pwritev", "sys_rt_tgsigqueueinfo", "sys_perf_event_open", "sys_recvmmsg", "sys_fanotify_init", "sys_fanotify_mark", "sys_prlimit64", "sys_name_to_handle_at", "sys_open_by_handle_at", "sys_clock_adjtime", "sys_syncfs", "sys_sendmmsg", "sys_setns", "sys_process_vm_readv", "sys_process_vm_writev", "sys_kcmp", "sys_finit_module", "sys_sched_setattr", "sys_sched_getattr", "sys_renameat2"] # Taken from /usr/include/asm/unistd_64.h at Arch Linux x86_64 3.16.1-1. x86_64SystemCalls = ["sys_read", "sys_write", "sys_open", "sys_close", "sys_stat", "sys_fstat", "sys_lstat", "sys_poll", "sys_lseek", "sys_mmap", "sys_mprotect", "sys_munmap", "sys_brk", "sys_rt_sigaction", "sys_rt_sigprocmask", "sys_rt_sigreturn", "sys_ioctl", "sys_pread64", "sys_pwrite64", "sys_readv", "sys_writev", "sys_access", "sys_pipe", "sys_select", "sys_sched_yield", "sys_mremap", "sys_msync", "sys_mincore", "sys_madvise", "sys_shmget", "sys_shmat", "sys_shmctl", "sys_dup", "sys_dup2", "sys_pause", "sys_nanosleep", "sys_getitimer", "sys_alarm", "sys_setitimer", "sys_getpid", "sys_sendfile", "sys_socket", "sys_connect", "sys_accept", "sys_sendto", "sys_recvfrom", "sys_sendmsg", "sys_recvmsg", "sys_shutdown", "sys_bind", "sys_listen", "sys_getsockname", "sys_getpeername", "sys_socketpair", "sys_setsockopt", "sys_getsockopt", "sys_clone", "sys_fork", "sys_vfork", "sys_execve", "sys_exit", "sys_wait4", "sys_kill", "sys_uname", "sys_semget", "sys_semop", "sys_semctl", "sys_shmdt", "sys_msgget", "sys_msgsnd", "sys_msgrcv", "sys_msgctl", "sys_fcntl", "sys_flock", "sys_fsync", "sys_fdatasync", "sys_truncate", "sys_ftruncate", "sys_getdents", "sys_getcwd", "sys_chdir", "sys_fchdir", "sys_rename", "sys_mkdir", "sys_rmdir", "sys_creat", "sys_link", "sys_unlink", "sys_symlink", "sys_readlink", "sys_chmod", "sys_fchmod", "sys_chown", "sys_fchown", "sys_lchown", "sys_umask", "sys_gettimeofday", "sys_getrlimit", "sys_getrusage", "sys_sysinfo", "sys_times", "sys_ptrace", "sys_getuid", "sys_syslog", "sys_getgid", "sys_setuid", "sys_setgid", "sys_geteuid", "sys_getegid", "sys_setpgid", "sys_getppid", "sys_getpgrp", "sys_setsid", "sys_setreuid", "sys_setregid", "sys_getgroups", "sys_setgroups", "sys_setresuid", "sys_getresuid", "sys_setresgid", "sys_getresgid", "sys_getpgid", "sys_setfsuid", "sys_setfsgid", "sys_getsid", "sys_capget", "sys_capset", "sys_rt_sigpending", "sys_rt_sigtimedwait", "sys_rt_sigqueueinfo", "sys_rt_sigsuspend", "sys_sigaltstack", "sys_utime", "sys_mknod", "sys_uselib", "sys_personality", "sys_ustat", "sys_statfs", "sys_fstatfs", "sys_sysfs", "sys_getpriority", "sys_setpriority", "sys_sched_setparam", "sys_sched_getparam", "sys_sched_setscheduler", "sys_sched_getscheduler", "sys_sched_get_priority_max", "sys_sched_get_priority_min", "sys_sched_rr_get_interval", "sys_mlock", "sys_munlock", "sys_mlockall", "sys_munlockall", "sys_vhangup", "sys_modify_ldt", "sys_pivot_root", "sys__sysctl", "sys_prctl", "sys_arch_prctl", "sys_adjtimex", "sys_setrlimit", "sys_chroot", "sys_sync", "sys_acct", "sys_settimeofday", "sys_mount", "sys_umount2", "sys_swapon", "sys_swapoff", "sys_reboot", "sys_sethostname", "sys_setdomainname", "sys_iopl", "sys_ioperm", "sys_create_module", "sys_init_module", "sys_delete_module", "sys_get_kernel_syms", "sys_query_module", "sys_quotactl", "sys_nfsservctl", "sys_getpmsg", "sys_putpmsg", "sys_afs_syscall", "sys_tuxcall", "sys_security", "sys_gettid", "sys_readahead", "sys_setxattr", "sys_lsetxattr", "sys_fsetxattr", "sys_getxattr", "sys_lgetxattr", "sys_fgetxattr", "sys_listxattr", "sys_llistxattr", "sys_flistxattr", "sys_removexattr", "sys_lremovexattr", "sys_fremovexattr", "sys_tkill", "sys_time", "sys_futex", "sys_sched_setaffinity", "sys_sched_getaffinity", "sys_set_thread_area", "sys_io_setup", "sys_io_destroy", "sys_io_getevents", "sys_io_submit", "sys_io_cancel", "sys_get_thread_area", "sys_lookup_dcookie", "sys_epoll_create", "sys_epoll_ctl_old", "sys_epoll_wait_old", "sys_remap_file_pages", "sys_getdents64", "sys_set_tid_address", "sys_restart_syscall", "sys_semtimedop", "sys_fadvise64", "sys_timer_create", "sys_timer_settime", "sys_timer_gettime", "sys_timer_getoverrun", "sys_timer_delete", "sys_clock_settime", "sys_clock_gettime", "sys_clock_getres", "sys_clock_nanosleep", "sys_exit_group", "sys_epoll_wait", "sys_epoll_ctl", "sys_tgkill", "sys_utimes", "sys_vserver", "sys_mbind", "sys_set_mempolicy", "sys_get_mempolicy", "sys_mq_open", "sys_mq_unlink", "sys_mq_timedsend", "sys_mq_timedreceive", "sys_mq_notify", "sys_mq_getsetattr", "sys_kexec_load", "sys_waitid", "sys_add_key", "sys_request_key", "sys_keyctl", "sys_ioprio_set", "sys_ioprio_get", "sys_inotify_init", "sys_inotify_add_watch", "sys_inotify_rm_watch", "sys_migrate_pages", "sys_openat", "sys_mkdirat", "sys_mknodat", "sys_fchownat", "sys_futimesat", "sys_newfstatat", "sys_unlinkat", "sys_renameat", "sys_linkat", "sys_symlinkat", "sys_readlinkat", "sys_fchmodat", "sys_faccessat", "sys_pselect6", "sys_ppoll", "sys_unshare", "sys_set_robust_list", "sys_get_robust_list", "sys_splice", "sys_tee", "sys_sync_file_range", "sys_vmsplice", "sys_move_pages", "sys_utimensat", "sys_epoll_pwait", "sys_signalfd", "sys_timerfd_create", "sys_eventfd", "sys_fallocate", "sys_timerfd_settime", "sys_timerfd_gettime", "sys_accept4", "sys_signalfd4", "sys_eventfd2", "sys_epoll_create1", "sys_dup3", "sys_pipe2", "sys_inotify_init1", "sys_preadv", "sys_pwritev", "sys_rt_tgsigqueueinfo", "sys_perf_event_open", "sys_recvmmsg", "sys_fanotify_init", "sys_fanotify_mark", "sys_prlimit64", "sys_name_to_handle_at", "sys_open_by_handle_at", "sys_clock_adjtime", "sys_syncfs", "sys_sendmmsg", "sys_setns", "sys_getcpu", "sys_process_vm_readv", "sys_process_vm_writev", "sys_kcmp", "sys_finit_module", "sys_sched_setattr", "sys_sched_getattr"] systemCallTypes = ["int 80h", "sysenter", "syscall", "gs:[10h]"] raxVariations = ["rax", "eax", "ax", "al"] regVariations = [ ["rbx", "ebx", "bx", "bl"], ["rcx", "ecx", "cx", "cl"], ["rdx", "edx", "dx", "dl"], ["rsi", "esi", "si", "sil"], ["rdi", "edi", "di", "dil"], ["rbp", "ebp", "bp", "bpl"], ["rsp", "esp", "sp", "spl"], ["r8", "r8d", "r8w", "r8b"], ["r9", "r9d", "r9w", "r9b"], ["r10", "r10d", "r10w", "r10b"], ["r11", "r11d", "r11w", "r11b"], ["r12", "r12d", "r12w", "r12b"], ["r13", "r13d", "r13w", "r13b"], ["r14", "r14d", "r14w", "r14b"], ["r15", "r15d", "r15w", "r15b"] ] hexChars = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "a", "b", "c", "d", "e", "f"] class SystemCallView(Choose2): def __init__(self, systemCalls): self.systemCalls = systemCalls Choose2.__init__(self, "System call", [ ["Address", 13], ["Type", 10], ["Number", 10], ["Name", 20], ["Pointer Size", 12] ]) self.items = list() self.nop_items = list() self.icon = 150 self.cmd_nop = None self.initialized = False def __fillView(self): self.systemCalls.searchSystemCalls() self.items = list() if len(self.systemCalls.x86) != 0: for call in self.systemCalls.x86: try: callNr = int(self.systemCalls.getSystemCallNumber(call[0]), 16) self.items.append(["0x%X" % call[0], systemCallTypes[call[1]], "0x%03X" % callNr, x86SystemCalls[callNr], "32bit"]) except: # No hex system call number found. self.items.append(["0x%X" % call[0], systemCallTypes[call[1]], "", "", "32bit"]) if len(self.systemCalls.x86_64) != 0: for call in self.systemCalls.x86_64: try: callNr = int(self.systemCalls.getSystemCallNumber(call[0]), 16) self.items.append(["0x%X" % call[0], systemCallTypes[call[1]], "0x%03X" % callNr, x86_64SystemCalls[callNr], "64bit"]) except: # No hex system call number found. self.items.append(["0x%X" % call[0], systemCallTypes[call[1]], "", "", "64bit"]) def OnClose(self): pass def OnCommand(self, n, cmd_id): if cmd_id == self.cmd_nop: start_ea = int(self.items[n][0], 16) end_ea = start_ea+ItemSize(start_ea) self.nop_items.append(self.items[n][0]) for i in xrange(start_ea, end_ea): PatchByte(i, 0x90) def OnGetIcon(self, n): if not len(self.items) > 0: return -1 if self.items[n][2] == "": # No system call number found => display red icon. return 59 else: # Display green icon. return 61 def OnGetLine(self, n): return self.items[n] def OnGetLineAttr(self, n): if len(self.nop_items) > 0: if self.items[n][0] in self.nop_items: return [0xB6B6B4, 0] def OnGetSize(self): return len(self.items) def OnRefresh(self, n): self.__fillView() def OnSelectLine(self, n): idaapi.jumpto(int(self.items[n][0], 16)) def show(self): if not self.initialized: self.initialized = True self.__fillView() if self.Show() < 0: return False if self.cmd_nop == None: self.cmd_nop = self.AddCommand("NOP system call", flags = idaapi.CHOOSER_POPUP_MENU, icon=50) return True class SystemCall(): def __init__(self): self.x86 = list() self.x86_64 = list() self.systemCallView = SystemCallView(self) def __formatHexStr(self, hexStr, hexLen): if hexStr[-1] == 'h': hexStr = hexStr[:-1] for c in hexStr: if not c in hexChars: return "" if len(hexStr) <= hexLen: return '0'*(hexLen-len(hexStr)) + hexStr return hexStr def __traceRegister(self, addr, targetRegVariation, xRefTo): """ Try to get the value of targetRegVariation at addr via back tracing. """ try: funcStart = get_func(addr).startEA except: funcStart = 0 while 1: if GetMnem(addr) == "mov": if GetOpnd(addr, 0) in targetRegVariation: # A MOV instruction with targetRegVariation as the destination # register. for regVariation in regVariations: if GetOpnd(addr, 1) in regVariation: # The source of the instruction is another register. # => Get the value of the destination register. return self.__traceRegister(addr, regVariation, addr) # We got the (possibly hex) value of the target register. return GetOpnd(addr, 1) if GetMnem(addr) == "lea": if GetOpnd(addr, 0) in targetRegVariation: # The value of the target register is changed but LEA is # currently not supported. break for xref in XrefsTo(addr, 0): # Follow all xrefs to the location and check if the target register # is set at this path. ret = self.__traceRegister(xref.frm, targetRegVariation, addr) if ret != 0xFFFFFFFF: return ret addr = PrevHead(addr) if addr < funcStart: break if addr == xRefTo: break if addr == BADADDR: break if not isCode(GetFlags(addr)): break return 0xFFFFFFFF def getSystemCallNumber(self, addr): """ Get the value of rax/eax at the time of the system call. """ systemCallNumber = self.__traceRegister(PrevHead(addr), raxVariations, addr) if systemCallNumber != 0xFFFFFFFF: return self.__formatHexStr(systemCallNumber, 3) return "" def searchSystemCalls(self): """ Looks for 'int 80', 'sysenter', 'syscall' and 'gs:[10h]' system calls. """ # Iterating through all segments for segment in Segments(): # Iterating through all instructions in each segment for head in Heads(segment, SegEnd(segment)): if isCode(GetFlags(head)): inst = DecodeInstruction(head) if ( inst.size == 2 and get_many_bytes(head, inst.size) .startswith("\xCD\x80")): # int 80h. Just on 32bit. if not [head, 0] in self.x86: self.x86.append([head, 0]) elif ( inst.size == 2 and get_many_bytes(head, inst.size) .startswith("\x0F\x34")): # sysenter. Just on 32bit. if not [head, 1] in self.x86: self.x86.append([head, 1]) elif ( inst.size == 2 and get_many_bytes(head, inst.size) .startswith("\x0F\x05")): # syscall. 32bit just on AMD. 64bit on AMD and Intel. if idaapi.ph.flag & idaapi.PR_USE64: if not [head, 2] in self.x86_64: self.x86_64.append([head, 2]) else: if not [head, 2] in self.x86: self.x86.append([head, 2]) elif ( inst.size == 7 and get_many_bytes(head, inst.size) .startswith("\x65\xFF\x15\x10\x00\x00\x00")): # gs:[10h]. Just on 32bit. if not [head, 3] in self.x86: self.x86.append([head, 3]) def showView(self): self.systemCallView.show() class SystemCallPlugin_t(idaapi.plugin_t): flags = 0 comment = "" help = "" wanted_name = "System Calls" wanted_hotkey = "" def init(self): global systemCalls if idaapi.ph_get_id() == idaapi.PLFM_386: # Check if already initialized if not 'systemCalls' in globals(): systemCalls = SystemCall() return idaapi.PLUGIN_KEEP else: return idaapi.PLUGIN_SKIP def run(self, arg): global systemCalls systemCalls.showView() def term(self): if 'systemCalls' in globals(): del globals()['systemCalls'] def PLUGIN_ENTRY(): return SystemCallPlugin_t()