#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include #include #include #include /* For SYS_xxx definitions */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "debug.h" #include "box64stack.h" #include "x64emu.h" #include "x64run.h" #include "x64emu_private.h" #include "x64run_private.h" //#include "x64primop.h" #include "x64trace.h" //#include "myalign.h" #include "box64context.h" #include "callback.h" #include "signals.h" #include "x64tls.h" typedef struct x64_sigaction_s x64_sigaction_t; typedef struct x64_stack_s x64_stack_t; extern int mkdir(const char *path, mode_t mode); extern int fchmodat (int __fd, const char *__file, mode_t __mode, int __flag); //int32_t my_getrandom(x64emu_t* emu, void* buf, uint32_t buflen, uint32_t flags); int of_convert(int flag); int32_t my_open(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode); ssize_t my_readlink(x64emu_t* emu, void* path, void* buf, size_t sz); int my_stat(x64emu_t *emu, void* filename, void* buf); int my_lstat(x64emu_t *emu, void* filename, void* buf); int my_fstat(x64emu_t *emu, int fd, void* buf); int my_fstatat(x64emu_t *emu, int fd, const char* path, void* buf, int flags); int my_sigaction(x64emu_t* emu, int signum, const x64_sigaction_t *act, x64_sigaction_t *oldact); int my_sigaltstack(x64emu_t* emu, const x64_stack_t* ss, x64_stack_t* oss); //int32_t my_execve(x64emu_t* emu, const char* path, char* const argv[], char* const envp[]); void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int64_t offset); int my_munmap(x64emu_t* emu, void* addr, unsigned long length); int my_mprotect(x64emu_t* emu, void *addr, unsigned long len, int prot); void* my_mremap(x64emu_t* emu, void* old_addr, size_t old_size, size_t new_size, int flags, void* new_addr); #ifndef NOALIGN int32_t my_epoll_ctl(x64emu_t* emu, int32_t epfd, int32_t op, int32_t fd, void* event); int32_t my_epoll_wait(x64emu_t* emu, int32_t epfd, void* events, int32_t maxevents, int32_t timeout); int32_t my_epoll_pwait(x64emu_t* emu, int32_t epfd, void* events, int32_t maxevents, int32_t timeout, const sigset_t *sigmask); pid_t my_vfork(x64emu_t* emu); #endif int32_t my_fcntl(x64emu_t* emu, int32_t a, int32_t b, void* c); int32_t my_execve(x64emu_t* emu, const char* path, char* const argv[], char* const envp[]); // cannot include , it conflict with some asm includes... #ifndef O_NONBLOCK #define O_NONBLOCK 04000 #endif #undef fcntl int fcntl(int fd, int cmd, ... /* arg */ ); // Syscall table for x86_64 can be found typedef struct scwrap_s { uint32_t x64s; // 32 bits? int nats; int nbpars; } scwrap_t; static scwrap_t syscallwrap[] = { //{ 0, __NR_read, 3 }, // wrapped so SA_RESTART can be handled by libc //{ 1, __NR_write, 3 }, // same //{ 2, __NR_open, 3 }, // flags need transformation //{ 3, __NR_close, 1 }, // wrapped so SA_RESTART can be handled by libc //{ 4, __NR_stat, 2 }, // Need to align struct stat //{ 5, __NR_fstat, 2}, //{ 6, __NR_lstat, 2}, #ifdef __NR_poll { 7, __NR_poll, 3}, #endif { 8, __NR_lseek, 3}, //{ 9, __NR_mmap, 6}, // wrapped to track mmap //{ 10, __NR_mprotect, 3}, // same //{ 11, __NR_munmap, 2}, // same { 12, __NR_brk, 1}, //{ 13, __NR_rt_sigaction, 4}, // wrapped to use my_ version { 14, __NR_rt_sigprocmask, 4}, { 16, __NR_ioctl, 3}, { 17, __NR_pread64, 4}, { 18, __NR_pwrite64, 4}, { 20, __NR_writev, 3}, #ifdef __NR_access { 21, __NR_access, 2}, #endif #ifdef __NR_pipe { 22, __NR_pipe, 1}, #endif { 24, __NR_sched_yield, 0}, #ifdef __NR_select { 23, __NR_select, 5}, #endif //{ 25, __NR_mremap, 5}, // wrapped to track protection { 27, __NR_mincore, 3}, { 28, __NR_madvise, 3}, #ifdef __NR_dup2 { 33, __NR_dup2, 2}, #endif { 35, __NR_nanosleep, 2}, { 39, __NR_getpid, 0}, { 41, __NR_socket, 3}, { 42, __NR_connect, 3}, { 43, __NR_accept, 3}, { 44, __NR_sendto, 6}, { 45, __NR_recvfrom, 6}, { 46, __NR_sendmsg, 3}, { 47, __NR_recvmsg, 3}, { 49, __NR_bind, 3}, { 50, __NR_listen, 2}, { 51, __NR_getsockname, 3}, { 52, __NR_getpeername, 3}, { 53, __NR_socketpair, 4}, { 54, __NR_setsockopt, 5}, { 55, __NR_getsockopt, 5}, //{56, __NR_clone, 5}, #ifdef __NR_fork { 57, __NR_fork, 0 }, // should wrap this one, because of the struct pt_regs (the only arg)? #endif //{58, __NR_vfork, 0}, //{59, __NR_execve, 3}, { 60, __NR_exit, 1}, // Nees wrapping? { 61, __NR_wait4, 4}, { 62, __NR_kill, 2 }, //{ 63, __NR_uname, 1}, // Needs wrapping, use old_utsname { 66, __NR_semctl, 4}, //{ 72, __NR_fnctl, 3}, // Needs wrapping, and not always defined anyway { 73, __NR_flock, 2}, { 74, __NR_fsync, 1}, #ifdef __NR_getdents { 78, __NR_getdents, 3}, #endif { 79, __NR_getcwd, 2}, { 80, __NR_chdir, 1}, #ifdef __NR_rename { 82, __NR_rename, 2}, #endif #ifdef __NR_mkdir { 83, __NR_mkdir, 2}, #endif #ifdef __NR_unlink { 87, __NR_unlink, 1}, #endif //{ 89, __NR_readlink, 3}, // not always existing, better use the wrapped version anyway { 96, __NR_gettimeofday, 2}, { 97, __NR_getrlimit, 2}, { 101, __NR_ptrace, 4}, { 102, __NR_getuid, 0}, { 104, __NR_getgid, 0}, { 105, __NR_setuid, 1}, { 106, __NR_setgid, 1}, { 107, __NR_geteuid, 0}, { 108, __NR_getegid, 0}, { 109, __NR_setpgid, 2}, { 110, __NR_getppid, 0}, //{ 111, __NR_getpgrp, 0}, { 112, __NR_setsid, 0}, { 113, __NR_setreuid, 2}, { 114, __NR_setregid, 2}, { 118, __NR_getresuid, 3}, { 120, __NR_getresgid, 3}, { 125, __NR_capget, 2}, { 126, __NR_capset, 2}, { 127, __NR_rt_sigpending, 2}, { 128, __NR_rt_sigtimedwait, 4}, //{ 131, __NR_sigaltstack, 2}, // wrapped to use my_sigaltstack* { 140, __NR_getpriority, 2}, { 155, __NR_pivot_root, 2}, { 157, __NR_prctl, 5 }, // needs wrapping? //{ 158, __NR_arch_prctl, 2}, //need wrapping { 160, __NR_setrlimit, 2}, { 161, __NR_chroot, 1}, { 186, __NR_gettid, 0 }, //0xBA { 200, __NR_tkill, 2 }, #ifdef __NR_time { 201, __NR_time, 1}, #endif { 202, __NR_futex, 6}, { 203, __NR_sched_setaffinity, 3}, { 204, __NR_sched_getaffinity, 3}, { 206, __NR_io_setup, 2}, { 207, __NR_io_destroy, 1}, { 208, __NR_io_getevents, 4}, { 209, __NR_io_submit, 3}, { 210, __NR_io_cancel, 3}, { 212, __NR_lookup_dcookie, 3}, #ifdef __NR_epoll_create { 213, __NR_epoll_create, 1}, #endif { 217, __NR_getdents64, 3}, { 218, __NR_set_tid_address, 1}, { 220, __NR_semtimedop, 4}, { 228, __NR_clock_gettime, 2}, { 229, __NR_clock_getres, 2}, { 230, __NR_clock_nanosleep, 4}, { 231, __NR_exit_group, 1}, #if defined(__NR_epoll_wait) && defined(NOALIGN) { 232, __NR_epoll_wait, 4}, #endif #if defined(__NR_epoll_ctl) && defined(NOALIGN) { 233, __NR_epoll_ctl, 4}, #endif { 234, __NR_tgkill, 3}, { 238, __NR_set_mempolicy, 3}, { 239, __NR_get_mempolicy, 5}, { 247, __NR_waitid, 5}, #ifdef __NR_inotify_init { 253, __NR_inotify_init, 0}, //0xFD #endif { 254, __NR_inotify_add_watch, 3}, { 255, __NR_inotify_rm_watch, 2}, #ifdef NOALIGN { 257, __NR_openat, 4}, #endif { 258, __NR_mkdirat, 3}, //{ 262, __NR_fstatat, 4}, { 263, __NR_unlinkat, 3}, #ifdef __NR_renameat { 264, __NR_renameat, 4}, #endif { 267, __NR_readlinkat, 4}, { 268, __NR_fchmodat, 3}, { 270, __NR_pselect6, 6}, { 272, __NR_unshare, 1}, { 273, __NR_set_robust_list, 2}, { 274, __NR_get_robust_list, 3}, #ifdef NOALIGN { 281, __NR_epoll_pwait, 6}, #endif //{ 282, __NR__signalfd, 3}, #ifdef _NR_eventfd { 284, __NR_eventfd, 1}, #endif { 285, __NR_fallocate, 4}, { 288, __NR_accept4, 4}, { 290, __NR_eventfd2, 2}, { 291, __NR_epoll_create1, 1}, { 292, __NR_dup3, 3}, { 293, __NR_pipe2, 2}, { 294, __NR_inotify_init1, 1}, { 297, __NR_rt_tgsigqueueinfo, 4}, { 298, __NR_perf_event_open, 5}, { 302, __NR_prlimit64, 4}, { 309, __NR_getcpu, 3}, // need wrapping? { 315, __NR_sched_getattr, 4}, //{ 317, __NR_seccomp, 3}, { 318, __NR_getrandom, 3}, { 319, __NR_memfd_create, 2}, { 324, __NR_membarrier, 2}, #ifdef __NR_statx // TODO: implement fallback if __NR_statx is not defined { 332, __NR_statx, 5}, #endif #ifdef __NR_fchmodat4 { 434, __NR_fchmodat4, 4}, #endif #ifdef __NR_futex_waitv { 449, __NR_futex_waitv, 5}, #endif }; struct mmap_arg_struct { unsigned long addr; unsigned long len; unsigned long prot; unsigned long flags; unsigned long fd; unsigned long offset; }; #ifndef __NR_getdents typedef struct x86_linux_dirent_s { unsigned long d_ino; unsigned long d_off; unsigned short d_reclen; char d_name[]; } x86_linux_dirent_t; typedef struct nat_linux_dirent64_s { ino64_t d_ino; off64_t d_off; unsigned short d_reclen; unsigned char d_type; char d_name[]; } nat_linux_dirent64_t; ssize_t DirentFromDirent64(void* dest, void* source, ssize_t count) { nat_linux_dirent64_t *src = (nat_linux_dirent64_t*)source; x86_linux_dirent_t *dst = (x86_linux_dirent_t*)dest; x86_linux_dirent_t *old = NULL; ssize_t ret = 0; while(count>0) { ssize_t sz = src->d_reclen+sizeof(x86_linux_dirent_t)-sizeof(nat_linux_dirent64_t)+2; if(sz>=count) { dst->d_ino = src->d_ino; dst->d_reclen = sz; ret+=sz; strcpy(dst->d_name, src->d_name); dst->d_off = src->d_off?(src->d_off+sizeof(x86_linux_dirent_t)-sizeof(nat_linux_dirent64_t)+2):0; *(uint8_t*)((uintptr_t)dst + dst->d_reclen -2) = 0; *(uint8_t*)((uintptr_t)dst + dst->d_reclen -1) = src->d_type; count -= src->d_reclen; ret += 1; old = dst; src = (nat_linux_dirent64_t*)(((uintptr_t)src) + src->d_reclen); dst = (x86_linux_dirent_t*)(((uintptr_t)dst) + dst->d_reclen); } else { if(old) old->d_off = 0; count = 0; } } return (count<0)?count:ret; } #endif typedef struct old_utsname_s { char sysname[65]; char nodename[65]; char release[65]; char version[65]; char machine[65]; } old_utsname_t; //struct x86_pt_regs { // long ebx; // long ecx; // long edx; // long esi; // long edi; // long ebp; // long eax; // int xds; // int xes; // int xfs; // int xgs; // long orig_eax; // long eip; // int xcs; // long eflags; // long esp; // int xss; //}; static int clone_fn(void* arg) { x64emu_t *emu = (x64emu_t*)arg; thread_set_emu(emu); R_RAX = 0; DynaRun(emu); int ret = R_EAX; FreeX64Emu(&emu); my_context->stack_clone_used = 0; return ret; } void EXPORT x64Syscall(x64emu_t *emu) { RESET_FLAGS(emu); uint32_t s = R_EAX; // EAX? (syscalls only go up to 547 anyways) int log = 0; char t_buff[256] = "\0"; char t_buffret[128] = "\0"; char buff2[64] = "\0"; char* buff = NULL; char* buffret = NULL; if(box64_log>=LOG_DEBUG || cycle_log) { log = 1; buff = cycle_log?my_context->log_call[my_context->current_line]:t_buff; buffret = cycle_log?my_context->log_ret[my_context->current_line]:t_buffret; if(cycle_log) my_context->current_line = (my_context->current_line+1)%cycle_log; snprintf(buff, 255, "%04d|%p: Calling syscall 0x%02X (%d) %p %p %p %p %p %p", GetTID(), (void*)R_RIP, s, s, (void*)R_RDI, (void*)R_RSI, (void*)R_RDX, (void*)R_R10, (void*)R_R8, (void*)R_R9); if(!cycle_log) printf_log(LOG_NONE, "%s", buff); } // check wrapper first int cnt = sizeof(syscallwrap) / sizeof(scwrap_t); for (int i=0; iquit = 1; return; } if(R_EAX==0xffffffff && errno>0) R_RAX = (uint64_t)-errno; if(log) snprintf(buffret, 127, "0x%x%s", R_EAX, buff2); if(log && !cycle_log) printf_log(LOG_NONE, "=> %s\n", buffret); return; } } switch (s) { case 0: // sys_read *(int64_t*)&R_RAX = read((int)R_EDI, (void*)R_RSI, (size_t)R_RDX); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; case 1: // sys_write *(int64_t*)&R_RAX = write((int)R_EDI, (void*)R_RSI, (size_t)R_RDX); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; case 2: // sys_open if(s==5) {if (log) snprintf(buff2, 63, " [sys_open(\"%s\", %d, %d)]", (char*)R_RDI, of_convert(R_ESI), R_EDX);}; //*(int64_t*)&R_RAX = open((void*)R_EDI, of_convert(R_ESI), R_EDX); *(int64_t*)&R_RAX = my_open(emu, (void*)R_RDI, of_convert(R_ESI), R_EDX); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; case 3: // sys_close *(int64_t*)&R_RAX = close((int)R_EDI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; case 4: // sys_stat *(int64_t*)&R_RAX = my_stat(emu, (void*)R_RDI, (void*)R_RSI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; case 5: // sys_fstat *(int64_t*)&R_RAX = my_fstat(emu, (int)R_EDI, (void*)R_RSI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; case 6: // sys_lstat *(int64_t*)&R_RAX = my_lstat(emu, (void*)R_RDI, (void*)R_RSI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #ifndef __NR_poll case 7: // sys_poll *(int64_t*)&R_RAX = poll((struct pollfd*)R_RDI, (nfds_t)R_RSI, (int)R_EDX); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif case 9: // sys_mmap R_RAX = (uintptr_t)my_mmap64(emu, (void*)R_RDI, R_RSI, (int)R_EDX, (int)R_R10d, (int)R_R8d, R_R9); break; case 10: // sys_mprotect *(int64_t*)&R_RAX = my_mprotect(emu, (void*)R_RDI, R_RSI, (int)R_EDX); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; case 11: // sys_munmap *(int64_t*)&R_RAX = my_munmap(emu, (void*)R_RDI, R_RSI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; case 13: // sys_rt_sigaction #if 1 R_RAX = (int64_t)my_syscall_rt_sigaction(emu, (int)R_EDI, (const x64_sigaction_restorer_t *)R_RSI, (x64_sigaction_restorer_t *)R_RDX, (size_t)R_R10); #else { x64_sigaction_t n ={0}; x64_sigaction_t o = {0}; if(R_RSI) { x64_sigaction_restorer_t *p = (x64_sigaction_restorer_t*)R_RSI; n._u._sa_sigaction = p->_u._sa_sigaction; n.sa_flags = p->sa_flags; n.sa_restorer = p->sa_restorer; memcpy(&n.sa_mask, &p->sa_mask, R_R10); } R_RAX = (int64_t)(int64_t)my_sigaction(emu, (int)R_EDI, R_RSI?&n:NULL, R_RDX?&o:NULL/*, (size_t)R_R10*/); if(R_RAX>=0 && R_RDX) { x64_sigaction_restorer_t *p = (x64_sigaction_restorer_t*)R_RDX; p->_u._sa_sigaction = o._u._sa_sigaction; p->sa_flags = o.sa_flags; p->sa_restorer = o.sa_restorer; memcpy(&p->sa_mask, &o.sa_mask, R_R10); } } #endif if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #ifndef __NR_access case 21: // sys_access *(int64_t*)&R_RAX = access((void*)R_RDI, R_ESI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif #ifndef __NR_pipe case 22: *(int64_t*)&R_RAX = pipe((void*)R_RDI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif #ifndef __NR_select case 23: // sys_select R_EAX = (uint32_t)select(R_RDI, (void*)R_RSI, (void*)R_RDX, (void*)R_R10, (void*)R_R8); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif case 25: // sys_mremap R_RAX = (uintptr_t)my_mremap(emu, (void*)R_RDI, R_RSI, R_RDX, R_R10d, (void*)R_R8); break; #ifndef __NR_dup2 case 33: // sys_dup2 R_EAX = (uint32_t)dup2((int)R_EDI, (int)R_ESI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif case 56: // sys_clone // x86_64 raw syscall is long clone(unsigned long flags, void *stack, int *parent_tid, int *child_tid, unsigned long tls); // so flags=R_RDI, stack=R_RSI, parent_tid=R_RDX, child_tid=R_R10, tls=R_R8 if((R_EDI&~0xff)==0x4100) { // this is a case of vfork... R_EAX = my_vfork(emu); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; } else { if(R_RSI) { void* stack_base = (void*)R_RSI; int stack_size = 0; if(!R_RSI) { // allocate a new stack... int currstack = 0; if((R_RSP>=(uintptr_t)emu->init_stack) && (R_RSP<=((uintptr_t)emu->init_stack+emu->size_stack))) currstack = 1; stack_size = (currstack && emu->size_stack)?emu->size_stack:(1024*1024); stack_base = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN, -1, 0); // copy value from old stack to new stack if(currstack) memcpy(stack_base, emu->init_stack, stack_size); else { int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_RSP); memcpy(stack_base+stack_size-size_to_copy, (void*)R_RSP, size_to_copy); } } x64emu_t * newemu = NewX64Emu(emu->context, R_RIP, (uintptr_t)stack_base, stack_size, (R_RSI)?0:1); SetupX64Emu(newemu, emu); //CloneEmu(newemu, emu); Push64(newemu, 0); PushExit(newemu); void* mystack = NULL; if(my_context->stack_clone_used) { mystack = box_malloc(1024*1024); // stack for own process... memory leak, but no practical way to remove it } else { if(!my_context->stack_clone) my_context->stack_clone = box_malloc(1024*1024); mystack = my_context->stack_clone; my_context->stack_clone_used = 1; } int64_t ret = clone(clone_fn, (void*)((uintptr_t)mystack+1024*1024), R_RDI, newemu, R_RDX, R_R8, R_R10); R_RAX = (uint64_t)ret; } else #ifdef NOALIGN R_RAX = (uint64_t)syscall(__NR_clone, R_RDI, R_RSI, R_RDX, R_R10, R_R8); #else R_RAX = (uint64_t)syscall(__NR_clone, R_RDI, R_RSI, R_RDX, R_R8, R_R10); // invert R_R8/R_R10 on Aarch64 and most other #endif } break; #ifndef __NR_fork case 57: R_RAX = fork(); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif case 58: // vfork { int64_t r = my_vfork(emu); R_RAX = r; if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; } break; case 59: // execve { int64_t r = my_execve(emu, (const char*)R_RDI, (char* const*)R_RSI, (char* const*)R_RDX); R_RAX = r; if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; } break; case 63: //uname { old_utsname_t *old = (old_utsname_t*)R_RDI; struct utsname uts; R_RAX = uname(&uts); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; memcpy(old, &uts, sizeof(*old)); // old_uts is just missing a field from new_uts strcpy(old->machine, "x86_64"); } break; case 72: //fcntl R_RAX = (uint64_t)my_fcntl(emu, (int)R_EDI, (int)R_ESI, (void*)R_RDX); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #ifndef __NR_getdents case 78: { size_t count = R_RDX; nat_linux_dirent64_t *d64 = (nat_linux_dirent64_t*)alloca(count); ssize_t ret = syscall(__NR_getdents64, R_EDI, d64, count); ret = DirentFromDirent64((void*)R_RSI, d64, ret); R_RAX = (uint64_t)ret; if(ret==-1) R_RAX = (uint64_t)-errno; } break; #endif #ifndef __NR_rename case 82: // sys_rename *(int64_t*)&R_RAX = rename((void*)R_RDI, (void*)R_RSI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif #ifndef __NR_mkdir case 83: // sys_mkdir *(int64_t*)&R_RAX = mkdir((void*)R_RDI, R_ESI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif #ifndef __NR_unlink case 87: //sys_unlink *(int64_t*)&R_RAX = unlink((void*)R_RDI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif case 89: // sys_readlink R_RAX = (ssize_t)my_readlink(emu,(void*)R_RDI, (void*)R_RSI, (size_t)R_RDX); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; case 131: // sys_sigaltstack *(int64_t*)&R_RAX = my_sigaltstack(emu, (void*)R_RDI, (void*)R_RSI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; case 158: // sys_arch_prctl *(int64_t*)&R_RAX = my_arch_prctl(emu, (int)R_EDI, (void*)R_RSI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #ifndef __NR_time case 201: // sys_time R_RAX = (uintptr_t)time((void*)R_RDI); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif #if !defined(__NR_epoll_wait) || !defined(NOALIGN) case 232: R_RAX = my_epoll_wait(emu, (int)R_EDI, (void*)R_RSI, (int)R_EDX, (int)R_R10d); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif #if !defined(__NR_epoll_ctl) || !defined(NOALIGN) case 233: R_EAX = my_epoll_ctl(emu, (int)R_EDI, (int)R_ESI, (int)R_EDX, (void*)R_R10); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif #ifndef __NR_inotify_init case 253: R_EAX = (int)syscall(__NR_inotify_init1, 0); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif #ifndef NOALIGN case 257: R_EAX = (int)syscall(__NR_openat, (int)R_EDI, (void*)R_RSI, of_convert((int)R_EDX), R_R10d); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif case 262: R_EAX = (uint32_t)my_fstatat(emu, (int)R_RDI, (char*)R_RSI, (void*)R_RDX, (int)R_R10d); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #ifndef __NR_renameat case 264: R_EAX = (uint32_t)renameat((int)R_RDI, (const char*)R_RSI, (int)R_EDX, (const char*)R_R10); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif #ifndef NOALIGN case 281: // sys_epool_pwait R_EAX = (uint32_t)my_epoll_pwait(emu, (int)R_EDI, (void*)R_RSI, (int)R_EDX, (int)R_R10d, (void*)R_R8); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif case 282: // sys_signalfd // need to mask SIGSEGV { sigset_t * set = (sigset_t *)R_RSI; if(sigismember(set, SIGSEGV)) { sigdelset(set, SIGSEGV); printf_log(LOG_INFO, "Warning, signalfd on SIGSEGV unsuported\n"); } R_EAX = signalfd((int)R_EDI, set, 0); if(R_EAX==-1) R_EAX = -errno; } break; #ifndef _NR_eventfd case 284: // sys_eventfd R_EAX = eventfd((int)R_EDI, 0); if(R_EAX==-1) R_EAX = -errno; #endif case 317: // sys_seccomp R_RAX = 0; // ignoring call break; case 334: // It is helpeful to run static binary R_RAX = -ENOSYS; break; #ifndef __NR_fchmodat4 case 434: *(int64_t*)R_RAX = fchmodat((int)R_EDI, (void*)R_RSI, (mode_t)R_RDX, (int)R_R10d); if(R_EAX==0xffffffff) R_RAX = (uint64_t)-errno; break; #endif default: printf_log(LOG_INFO, "Error: Unsupported Syscall 0x%02Xh (%d)\n", s, s); emu->quit = 1; emu->error |= ERR_UNIMPL; return; } if(log) snprintf(buffret, 127, "0x%lx%s", R_RAX, buff2); if(log && !cycle_log) printf_log(LOG_NONE, "=> %s\n", buffret); } #define stack(n) (R_RSP+8+n) #define i32(n) *(int32_t*)stack(n) #define u32(n) *(uint32_t*)stack(n) #define i64(n) *(int64_t*)stack(n) #define u64(n) *(uint64_t*)stack(n) #define p(n) *(void**)stack(n) uintptr_t EXPORT my_syscall(x64emu_t *emu) { static uint32_t warned = 0; uint32_t s = R_EDI; printf_dump(LOG_DEBUG, "%04d| %p: Calling libc syscall 0x%02X (%d) %p %p %p %p %p\n", GetTID(), (void*)R_RIP, s, s, (void*)R_RSI, (void*)R_RDX, (void*)R_RCX, (void*)R_R8, (void*)R_R9); // check wrapper first int cnt = sizeof(syscallwrap) / sizeof(scwrap_t); for (int i=0; iquit = 1; return 0; } } } switch (s) { case 0: // sys_read return (uint64_t)read(R_ESI, (void*)R_RDX, R_ECX); case 1: // sys_write return (uint64_t)write(R_ESI, (void*)R_RDX, R_ECX); case 2: // sys_open return my_open(emu, (char*)R_RSI, of_convert(R_EDX), R_ECX); case 3: // sys_close return (uint64_t)(int64_t)close(R_ESI); case 4: // sys_stat return (uint64_t)(int64_t)my_stat(emu, (void*)R_RSI, (void*)R_RDX); case 5: // sys_fstat return (uint64_t)(int64_t)my_fstat(emu, (int)R_ESI, (void*)R_RDX); case 6: // sys_lstat return (uint64_t)(int64_t)my_lstat(emu, (void*)R_RSI, (void*)R_RDX); #ifndef __NR_poll case 7: // sys_poll return (uint64_t)(int64_t)poll((struct pollfd*)R_RSI, (nfds_t)R_RDX, (int)R_ECX); break; #endif case 9: // sys_mmap return (uintptr_t)my_mmap64(emu, (void*)R_RSI, R_RDX, (int)R_RCX, (int)R_R8d, (int)R_R9, i64(0)); case 10: // sys_mprotect return (uint64_t)my_mprotect(emu, (void*)R_RSI, R_RDX, (int)R_ECX); case 11: // sys_munmap return (uint64_t)my_munmap(emu, (void*)R_RSI, R_RDX); case 13: // sys_rt_sigaction #if 1 return my_syscall_rt_sigaction(emu, (int)R_ESI, (const x64_sigaction_restorer_t *)R_RDX, (x64_sigaction_restorer_t *)R_RCX, (size_t)R_R8); #else { x64_sigaction_t n ={0}; x64_sigaction_t o = {0}; if(R_RDX) { x64_sigaction_restorer_t *p = (x64_sigaction_restorer_t*)R_RDX; n._u._sa_sigaction = p->_u._sa_sigaction; n.sa_flags = p->sa_flags; n.sa_restorer = p->sa_restorer; memcpy(&n.sa_mask, &p->sa_mask, R_R8); } uint64_t ret = (uint64_t)(int64_t)my_sigaction(emu, (int)R_ESI, R_RDX?&n:NULL, R_RCX?&o:NULL/*, (size_t)R_R8*/); if(R_RCX) { x64_sigaction_restorer_t *p = (x64_sigaction_restorer_t*)R_RCX; p->_u._sa_sigaction = o._u._sa_sigaction; p->sa_flags = o.sa_flags; p->sa_restorer = o.sa_restorer; memcpy(&p->sa_mask, &o.sa_mask, R_R8); } return ret; } #endif #ifndef __NR_access case 21: // sys_access return (uint64_t)(int64_t)access((void*)R_RSI, R_EDX); #endif #ifndef __NR_pipe case 22: return (uint64_t)(int64_t)pipe((void*)R_RSI); #endif #ifndef __NR_select case 23: // sys_select return (uint64_t)(int64_t)select(R_RSI, (void*)R_RDX, (void*)R_RCX, (void*)R_R8, (void*)R_R9); #endif case 25: // sys_mremap return (uintptr_t)my_mremap(emu, (void*)R_RSI, R_RDX, R_RCX, R_R8d, (void*)R_R9); case 56: // sys_clone // x86_64 raw syscall is long clone(unsigned long flags, void *stack, int *parent_tid, int *child_tid, unsigned long tls); // so flags=R_RSI, stack=R_RDX, parent_tid=R_RCX, child_tid=R_R8, tls=R_R9 if(R_RDX) { void* stack_base = (void*)R_RDX; int stack_size = 0; if(!stack_base) { // allocate a new stack... int currstack = 0; if((R_RSP>=(uintptr_t)emu->init_stack) && (R_RSP<=((uintptr_t)emu->init_stack+emu->size_stack))) currstack = 1; stack_size = (currstack)?emu->size_stack:(1024*1024); stack_base = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN, -1, 0); // copy value from old stack to new stack if(currstack) memcpy(stack_base, emu->init_stack, stack_size); else { int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_RSP); memcpy(stack_base+stack_size-size_to_copy, (void*)R_RSP, size_to_copy); } } x64emu_t * newemu = NewX64Emu(emu->context, R_RIP, (uintptr_t)stack_base, stack_size, (R_RDX)?0:1); SetupX64Emu(newemu, emu); //CloneEmu(newemu, emu); Push64(newemu, 0); PushExit(newemu); void* mystack = NULL; if(my_context->stack_clone_used) { mystack = box_malloc(1024*1024); // stack for own process... memory leak, but no practical way to remove it } else { if(!my_context->stack_clone) my_context->stack_clone = box_malloc(1024*1024); mystack = my_context->stack_clone; my_context->stack_clone_used = 1; } // x86_64 raw clone is long clone(unsigned long flags, void *stack, int *parent_tid, int *child_tid, unsigned long tls); int64_t ret = clone(clone_fn, (void*)((uintptr_t)mystack+1024*1024), R_ESI, newemu, R_RCX, R_R9, R_R8); return (uintptr_t)ret; } else #ifdef NOALIGN return (uintptr_t)syscall(__NR_clone, R_RSI, R_RDX, R_RCX, R_R8, R_R9); #else return (uintptr_t)syscall(__NR_clone, R_RSI, R_RDX, R_RCX, R_R9, R_R8); // invert R_R8/R_R9 on Aarch64 and most other #endif break; #ifndef __NR_dup2 case 33: return dup2((int)R_ESI, (int)R_EDX); #endif #ifndef __NR_fork case 57: return fork(); #endif case 58: // vfork return my_vfork(emu); case 59: // execve return my_execve(emu, (const char*)R_RSI, (char* const*)R_RDX, (char* const*)R_RCX); case 63: //uname { old_utsname_t *old = (old_utsname_t*)R_RSI; struct utsname uts; int64_t ret = uname(&uts); memcpy(old, &uts, sizeof(*old)); strcpy(old->machine, "x86_64"); return ret; } case 72: //fcntl R_RAX = (uint64_t)my_fcntl(emu, (int)R_ESI, (int)R_EDX, (void*)R_RCX); break; #ifndef __NR_getdents case 78: { size_t count = R_RCX; nat_linux_dirent64_t *d64 = (nat_linux_dirent64_t*)alloca(count); ssize_t ret = syscall(__NR_getdents64, R_ESI, d64, count); ret = DirentFromDirent64((void*)R_RDX, d64, ret); return (uint64_t)ret; } #endif #ifndef __NR_mkdir case 83: // sys_mkdir return (uint64_t)(int64_t)mkdir((void*)R_RSI, R_EDX); #endif #ifndef __NR_unlink case 87: //sys_unlink return (uint64_t)(int64_t)unlink((void*)R_RSI); #endif case 89: // sys_readlink return (uintptr_t)my_readlink(emu,(void*)R_RSI, (void*)R_RDX, (size_t)R_RCX); case 131: // sys_sigaltstack return (uint64_t)(int64_t)my_sigaltstack(emu, (void*)R_RSI, (void*)R_RDX); case 158: // sys_arch_prctl return (uint64_t)(int64_t)my_arch_prctl(emu, (int)R_ESI, (void*)R_RDX); #ifndef __NR_time case 201: // sys_time return (uintptr_t)time((void*)R_RSI); #endif #if !defined(__NR_epoll_wait) || !defined(NOALIGN) case 232: R_RAX = my_epoll_wait(emu, (int)R_ESI, (void*)R_RDX, (int)R_ECX, (int)R_R8d); break; #endif #if !defined(__NR_epoll_ctl) || !defined(NOALIGN) case 233: R_EAX = my_epoll_ctl(emu, (int)R_ESI, (int)R_EDX, (int)R_ECX, (void*)R_R8); break; #endif #ifndef __NR_inotify_init case 253: return (int)syscall(__NR_inotify_init1, 0); #endif #ifndef NOALIGN case 257: R_EAX = (int)syscall(__NR_openat, (int)R_ESI, (void*)R_RDX, of_convert((int)R_ECX), R_R8d); break; #endif case 262: return (uint64_t)(int64_t)my_fstatat(emu, (int)R_RSI, (char*)R_RDX, (void*)R_RCX, (int)R_R8d); #ifndef __NR_renameat case 264: return (uint64_t)(int64_t)renameat((int)R_RSI, (const char*)R_RDX, (int)R_ECX, (const char*)R_R8); #endif #ifndef NOALIGN case 281: // sys_epool_pwait return (uint64_t)(int64_t)my_epoll_pwait(emu, (int)R_ESI, (void*)R_RDX, (int)R_ECX, (int)R_R8d, (void*)R_R9); break; #endif case 282: // sys_signalfd // need to mask SIGSEGV { sigset_t * set = (sigset_t *)R_RDX; if(sigismember(set, SIGSEGV)) { sigdelset(set, SIGSEGV); printf_log(LOG_INFO, "Warning, signalfd on SIGSEGV unsuported\n"); } return signalfd((int)R_ESI, set, 0); } break; #ifndef _NR_eventfd case 284: // sys_eventfd return eventfd((int)R_ESI, 0); #endif case 317: // sys_seccomp return 0; // ignoring call #ifndef __NR_fchmodat4 case 434: return (int)fchmodat((int)R_ESI, (void*)R_RDX, (mode_t)R_RCX, (int)R_R8d); #endif default: if(!(warned&(1<