""" 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 miasm2.core.bin_stream_ida import bin_stream_ida from miasm2.analysis.depgraph import DependencyGraph from miasm2.analysis.machine import Machine 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]"] # max_size_to_size and guess_machine from miasm/example/ida/utils.py def max_size_to_size(max_size): for size in [16, 32, 64]: if (1 << size) - 1 == max_size: return size return None def guess_machine(): "Return an instance of Machine corresponding to the IDA guessed processor" processor_name = GetLongPrm(INF_PROCNAME) max_size = GetLongPrm(INF_START_SP) size = max_size_to_size(max_size) if processor_name == "metapc": # HACK: check 32/64 using INF_START_SP if max_size == 0x80: # TODO XXX check machine = Machine("x86_16") elif size == 32: machine = Machine("x86_32") elif size == 64: machine = Machine("x86_64") else: raise ValueError('cannot guess 32/64 bit! (%x)' % max_size) elif processor_name == "ARM": # TODO ARM/thumb # hack for thumb: set armt = True in globals :/ # set bigendiant = True is bigendian # Thumb, size, endian info2machine = {(True, 32, True): "armtb", (True, 32, False): "armtl", (False, 32, True): "armb", (False, 32, False): "arml", (False, 64, True): "aarch64b", (False, 64, False): "aarch64l", } is_armt = globals().get('armt', False) is_bigendian = globals().get('bigendian', False) infos = (is_armt, size, is_bigendian) if not infos in info2machine: raise NotImplementedError('not fully functional') machine = Machine(info2machine[infos]) from miasm2.analysis.disasm_cb import guess_funcs, guess_multi_cb from miasm2.analysis.disasm_cb import arm_guess_subcall, arm_guess_jump_table guess_funcs.append(arm_guess_subcall) guess_funcs.append(arm_guess_jump_table) elif processor_name == "msp430": machine = Machine("msp430") elif processor_name == "mipsl": machine = Machine("mips32l") elif processor_name == "mipsb": machine = Machine("mips32b") else: print repr(processor_name) raise NotImplementedError('not fully functional') return machine 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])[0]) 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])[0]) 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 getSystemCallNumber(self, addr): """ Get the value of rax/eax at the time of the system call. """ # Init machine = guess_machine() mn, dis_engine, ira = machine.mn, machine.dis_engine, machine.ira bs = bin_stream_ida() mdis = dis_engine(bs, dont_dis_nulstart_bloc=True) ir_arch = ira(mdis.symbol_pool) # Populate symbols with ida names for ad, name in Names(): if name is None: continue mdis.symbol_pool.add_label(name, ad) # Get the current function func = idaapi.get_func(addr) blocs = mdis.dis_multibloc(func.startEA) # Generate IR for bloc in blocs: ir_arch.add_bloc(bloc) cur_bloc = list(ir_arch.getby_offset(addr))[0] cur_label = cur_bloc.label elements = set([mn.regs.RAX]) for line_nb, l in enumerate(cur_bloc.lines): if l.offset == addr: break # Get dependency graphs dg = DependencyGraph(ir_arch, follow_call=False) graphs = dg.get(cur_label, elements, line_nb, set([ir_arch.symbol_pool.getby_offset(func.startEA)])) # Display the result sol = list() while 1: try: graph = graphs.next() except StopIteration: break if not graph.has_loop: sol.append(graph.emul().values()[0]) return sol 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()