static void fork_child_callback(void *user) { fork_child_data *data = user; if (data->runprofile) { char **argv = r_str_argv (data->cmd, NULL); if (!argv) { exit (1); } RRunProfile *rp = _get_run_profile (data->io, data->bits, argv); if (!rp) { r_str_argv_free (argv); exit (1); } trace_me (); r_run_start (rp); r_run_free (rp); r_str_argv_free (argv); exit (1); } else { char *_cmd = data->io->args ? r_str_appendf (strdup (data->cmd), " %s", data->io->args) : strdup (data->cmd); trace_me (); char **argv = r_str_argv (_cmd, NULL); if (!argv) { free (_cmd); return; } if (argv && *argv) { int i; for (i = 3; i < 1024; i++) { (void)close (i); } for (i = 0; argv[i]; i++) { r_str_arg_unescape (argv[i]); } if (execvp (argv[0], argv) == -1) { eprintf ("Could not execvp: %s\n", strerror (errno)); exit (MAGIC_EXIT); } } else { eprintf ("Invalid execvp\n"); } r_str_argv_free (argv); free (_cmd); } }
R_API int r_sandbox_system (const char *x, int n) { if (enabled) { eprintf ("sandbox: system call disabled\n"); return -1; } #if LIBC_HAVE_FORK #if LIBC_HAVE_SYSTEM if (n) return system (x); return execl ("/bin/sh", "sh", "-c", x, (const char*)NULL); #else #include <spawn.h> if (n && !strchr (x, '|')) { char **argv, *cmd = strdup (x); int rc, pid, argc; char *isbg = strchr (cmd, '&'); // XXX this is hacky if (isbg) { *isbg = 0; } argv = r_str_argv (cmd, &argc); if (argv) { char *argv0 = r_file_path (argv[0]); if (!argv0) { eprintf ("Cannot find '%s'\n", argv[0]); return -1; } pid = 0; posix_spawn (&pid, argv0, NULL, NULL, argv, NULL); if (isbg) { // XXX. wait for children rc = 0; } else { rc = waitpid (pid, NULL, 0); } r_str_argv_free (argv); free (argv0); return rc; } eprintf ("Error parsing command arguments\n"); return -1; } int child = fork(); if (child == -1) return -1; if (child) { return waitpid (child, NULL, 0); } execl ("/bin/sh", "sh", "-c", x, (const char*)NULL); exit (1); #endif #endif return -1; }
static int fork_and_ptraceme(const char *cmd) { char **argv; int ret, status, pid = vfork (); switch (pid) { case -1: perror ("fork_and_ptraceme"); break; case 0: #if __APPLE__ signal (SIGTRAP, SIG_IGN); //NEED BY STEP #endif #if __APPLE__ || __BSD__ /* we can probably remove this #if..as long as PT_TRACE_ME is redefined for OSX in r_debug.h */ signal (SIGABRT, inferior_abort_handler); if (ptrace (PT_TRACE_ME, 0, 0, 0) != 0) { #else if (ptrace (PTRACE_TRACEME, 0, NULL, NULL) != 0) { #endif eprintf ("ptrace-traceme failed\n"); exit (MAGIC_EXIT); } // TODO: Add support to redirect filedescriptors // TODO: Configure process environment argv = r_str_argv (cmd, NULL); execvp (argv[0], argv); r_str_argv_free (argv); perror ("fork_and_attach: execv"); //printf(stderr, "[%d] %s execv failed.\n", getpid(), ps.filename); exit (MAGIC_EXIT); /* error */ return 0; // invalid pid // if exit is overriden.. :) default: /* XXX: clean this dirty code */ ret = wait (&status); if (ret != pid) eprintf ("Wait event received by different pid %d\n", ret); if (WIFSTOPPED (status)) eprintf ("Process with PID %d started...\n", (int)pid); if (WEXITSTATUS (status) == MAGIC_EXIT) pid = -1; // XXX kill (pid, SIGSTOP); break; } eprintf ("PID = %d\n", pid); return pid; } #endif static int __plugin_open(struct r_io_t *io, const char *file) { if (!memcmp (file, "dbg://", 6) && file[6]) return R_TRUE; return R_FALSE; } static RIODesc *__open(RIO *io, const char *file, int rw, int mode) { char uri[128]; if (__plugin_open (io, file)) { int pid = atoi (file+6); if (pid == 0) { pid = fork_and_ptraceme (file+6); if (pid==-1) return NULL; #if __WINDOWS__ sprintf (uri, "w32dbg://%d", pid); #elif __APPLE__ sprintf (uri, "mach://%d", pid); #else // TODO: use io_procpid here? faster or what? sprintf (uri, "ptrace://%d", pid); #endif eprintf ("io_redirect: %s\n", uri); r_io_redirect (io, uri); return NULL; } else { sprintf (uri, "attach://%d", pid); r_io_redirect (io, uri); return NULL; } } r_io_redirect (io, NULL); return NULL; }
// __UNIX__ (not windows) static int fork_and_ptraceme_for_mac(RIO *io, int bits, const char *cmd) { bool runprofile = io->runprofile && *(io->runprofile); pid_t p = -1; char **argv; posix_spawn_file_actions_t fileActions; ut32 ps_flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; sigset_t no_signals; sigset_t all_signals; size_t copied = 1; cpu_type_t cpu = CPU_TYPE_ANY; posix_spawnattr_t attr = {0}; posix_spawnattr_init (&attr); sigemptyset (&no_signals); sigfillset (&all_signals); posix_spawnattr_setsigmask (&attr, &no_signals); posix_spawnattr_setsigdefault (&attr, &all_signals); posix_spawn_file_actions_init (&fileActions); posix_spawn_file_actions_addinherit_np (&fileActions, STDIN_FILENO); posix_spawn_file_actions_addinherit_np (&fileActions, STDOUT_FILENO); posix_spawn_file_actions_addinherit_np (&fileActions, STDERR_FILENO); ps_flags |= POSIX_SPAWN_CLOEXEC_DEFAULT; ps_flags |= POSIX_SPAWN_START_SUSPENDED; #define _POSIX_SPAWN_DISABLE_ASLR 0x0100 if (!runprofile) { int ret, useASLR = io->aslr; char *_cmd = io->args ? r_str_appendf (strdup (cmd), " %s", io->args) : strdup (cmd); argv = r_str_argv (_cmd, NULL); if (!argv) { free (_cmd); return -1; } if (!*argv) { r_str_argv_free (argv); free (_cmd); eprintf ("Invalid execvp\n"); return -1; } if (useASLR != -1) { if (!useASLR) { ps_flags |= _POSIX_SPAWN_DISABLE_ASLR; } } (void)posix_spawnattr_setflags (&attr, ps_flags); #if __x86_64__ if (bits == 32) { cpu = CPU_TYPE_I386; // cpu |= CPU_ARCH_ABI64; } #endif posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &copied); { char *dst = r_file_readlink (argv[0]); if (dst) { argv[0] = dst; } } // XXX: this is a workaround to fix spawning programs with spaces in path if (strstr (argv[0], "\\ ")) { argv[0] = r_str_replace (argv[0], "\\ ", " ", true); } ret = posix_spawnp (&p, argv[0], &fileActions, &attr, argv, NULL); handle_posix_error (ret); posix_spawn_file_actions_destroy (&fileActions); r_str_argv_free (argv); free (_cmd); return p; } int ret; argv = r_str_argv (cmd, NULL); if (!argv) { posix_spawn_file_actions_destroy (&fileActions); return -1; } RRunProfile *rp = _get_run_profile (io, bits, argv); if (!rp) { r_str_argv_free (argv); posix_spawn_file_actions_destroy (&fileActions); return -1; } handle_posix_redirection (rp, &fileActions); if (rp->_args[0]) { if (!rp->_aslr) { ps_flags |= _POSIX_SPAWN_DISABLE_ASLR; } #if __x86_64__ if (rp->_bits == 32) { cpu = CPU_TYPE_I386; } #endif (void)posix_spawnattr_setflags (&attr, ps_flags); posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &copied); ret = posix_spawnp (&p, rp->_args[0], &fileActions, &attr, rp->_args, NULL); handle_posix_error (ret); } r_str_argv_free (argv); r_run_free (rp); posix_spawn_file_actions_destroy (&fileActions); return p; // -1 ? }
static int fork_and_ptraceme(RIO *io, int bits, const char *cmd) { PROCESS_INFORMATION pi; STARTUPINFO si = { 0 } ; DEBUG_EVENT de; int pid, tid; HANDLE th = INVALID_HANDLE_VALUE; if (!*cmd) { return -1; } setup_tokens (); char *_cmd = io->args ? r_str_appendf (strdup (cmd), " %s", io->args) : strdup (cmd); char **argv = r_str_argv (_cmd, NULL); // We need to build a command line with quoted argument and escaped quotes int cmd_len = 0; int i = 0; si.cb = sizeof (si); while (argv[i]) { char *current = argv[i]; int quote_count = 0; while ((current = strchr (current, '"'))) { quote_count ++; } cmd_len += strlen (argv[i]); cmd_len += quote_count; // The quotes will add one backslash each cmd_len += 2; // Add two enclosing quotes; i++; } cmd_len += i-1; // Add argc-1 spaces char *cmdline = malloc ((cmd_len + 1) * sizeof (char)); int cmd_i = 0; // Next character to write in cmdline i = 0; while (argv[i]) { if (i != 0) { cmdline[cmd_i++] = ' '; } cmdline[cmd_i++] = '"'; int arg_i = 0; // Index of current character in orginal argument while (argv[i][arg_i]) { char c = argv[i][arg_i]; if (c == '"') { cmdline[cmd_i++] = '\\'; } cmdline[cmd_i++] = c; arg_i++; } cmdline[cmd_i++] = '"'; i++; } cmdline[cmd_i] = '\0'; LPTSTR appname_ = r_sys_conv_utf8_to_utf16 (argv[0]); LPTSTR cmdline_ = r_sys_conv_utf8_to_utf16 (cmdline); if (!CreateProcess (appname_, cmdline_, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi)) { r_sys_perror ("fork_and_ptraceme/CreateProcess"); free (appname_); free (cmdline_); return -1; } free (appname_); free (cmdline_); free (cmdline); r_str_argv_free (argv); /* get process id and thread id */ pid = pi.dwProcessId; tid = pi.dwThreadId; /* catch create process event */ if (!WaitForDebugEvent (&de, 10000)) goto err_fork; /* check if is a create process debug event */ if (de.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT) { eprintf ("exception code 0x%04x\n", (ut32)de.dwDebugEventCode); goto err_fork; } if (th != INVALID_HANDLE_VALUE) { CloseHandle (th); } eprintf ("Spawned new process with pid %d, tid = %d\n", pid, tid); winbase = (ut64)de.u.CreateProcessInfo.lpBaseOfImage; wintid = tid; return pid; err_fork: eprintf ("ERRFORK\n"); TerminateProcess (pi.hProcess, 1); if (th != INVALID_HANDLE_VALUE) CloseHandle (th); return -1; }
static int fork_and_ptraceme(RIO *io, int bits, const char *cmd) { PROCESS_INFORMATION pi; STARTUPINFO si = { sizeof (si) }; DEBUG_EVENT de; int pid, tid; HANDLE th = INVALID_HANDLE_VALUE; if (!*cmd) return -1; setup_tokens (); char **argv = r_str_argv (cmd, NULL); // We need to build a command line with quoted argument and escaped quotes int cmd_len = 0; int i = 0; while (argv[i]) { char *current = argv[i]; int quote_count = 0; while ((current = strchr (current, '"'))) quote_count ++; cmd_len += strlen (argv[i]); cmd_len += quote_count; // The quotes will add one backslash each cmd_len += 2; // Add two enclosing quotes; i++; } cmd_len += i-1; // Add argc-1 spaces char *cmdline = malloc ((cmd_len + 1) * sizeof (char)); int cmd_i = 0; // Next character to write in cmdline i = 0; while (argv[i]) { if (i != 0) cmdline[cmd_i++] = ' '; cmdline[cmd_i++] = '"'; int arg_i = 0; // Index of current character in orginal argument while (argv[i][arg_i]) { char c = argv[i][arg_i]; if (c == '"') { cmdline[cmd_i++] = '\\'; } cmdline[cmd_i++] = c; arg_i++; } cmdline[cmd_i++] = '"'; i++; } cmdline[cmd_i] = '\0'; if (!CreateProcess (argv[0], cmdline, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi)) { r_sys_perror ("CreateProcess"); return -1; } free (cmdline); r_str_argv_free (argv); /* get process id and thread id */ pid = pi.dwProcessId; tid = pi.dwThreadId; #if 0 /* load thread list */ { HANDLE h; THREADENTRY32 te32; HANDLE WINAPI (*win32_openthread)(DWORD, BOOL, DWORD) = NULL; win32_openthread = (HANDLE WINAPI (*)(DWORD, BOOL, DWORD)) GetProcAddress (GetModuleHandle ("kernel32"), "OpenThread"); th = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, pid); if (th == INVALID_HANDLE_VALUE || !Thread32First(th, &te32)) r_sys_perror ("CreateToolhelp32Snapshot"); do { if (te32.th32OwnerProcessID == pid) { h = win32_openthread (THREAD_ALL_ACCESS, 0, te32.th32ThreadID); if (h == NULL) r_sys_perror ("OpenThread"); else eprintf ("HANDLE=%p\n", h); } } while (Thread32Next (th, &te32)); } #endif #if 0 // Access denied here :? if (ContinueDebugEvent (pid, tid, DBG_CONTINUE) == 0) { r_sys_perror ("ContinueDebugEvent"); goto err_fork; } #endif /* catch create process event */ if (!WaitForDebugEvent (&de, 10000)) goto err_fork; /* check if is a create process debug event */ if (de.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT) { eprintf ("exception code 0x%04x\n", (ut32)de.dwDebugEventCode); goto err_fork; } if (th != INVALID_HANDLE_VALUE) CloseHandle (th); eprintf ("PID=%d\n", pid); eprintf ("TID=%d\n", tid); return pid; err_fork: eprintf ("ERRFORK\n"); TerminateProcess (pi.hProcess, 1); if (th != INVALID_HANDLE_VALUE) CloseHandle (th); return -1; }
// __UNIX__ (not windows) static int fork_and_ptraceme(RIO *io, int bits, const char *cmd) { char **argv; int ret, status, pid = r_sys_fork (); switch (pid) { case -1: perror ("fork_and_ptraceme"); break; case 0: #if __APPLE__ signal (SIGTRAP, SIG_IGN); //NEED BY STEP #endif #if __APPLE__ || __BSD__ /* we can probably remove this #if..as long as PT_TRACE_ME is redefined for OSX in r_debug.h */ signal (SIGABRT, inferior_abort_handler); if (ptrace (PT_TRACE_ME, 0, 0, 0) != 0) { #else if (ptrace (PTRACE_TRACEME, 0, NULL, NULL) != 0) { #endif r_sys_perror ("ptrace-traceme"); exit (MAGIC_EXIT); } if (io->runprofile && *(io->runprofile)) { char *expr = NULL; int i; RRunProfile *rp = r_run_new (NULL); argv = r_str_argv (cmd, NULL); for (i=0; argv[i]; i++) { rp->_args[i] = argv[i]; } rp->_args[i] = NULL; rp->_program = argv[0]; if (io->runprofile && *io->runprofile) { if (!r_run_parsefile (rp, io->runprofile)) { eprintf ("Can't find profile '%s'\n", io->runprofile); exit (MAGIC_EXIT); } } if (bits==64) r_run_parseline (rp, expr=strdup ("bits=64")); else if (bits==32) r_run_parseline (rp, expr=strdup ("bits=32")); free (expr); r_run_start (rp); r_run_free (rp); // double free wtf // r_str_argv_free (argv); exit (1); } else { // TODO: Add support to redirect filedescriptors // TODO: Configure process environment char *_cmd = strdup (cmd); argv = r_str_argv (_cmd, NULL); if (!argv) { free (_cmd); return -1; } #if __APPLE__ { #define _POSIX_SPAWN_DISABLE_ASLR 0x0100 ut32 ps_flags = POSIX_SPAWN_SETEXEC; posix_spawnattr_t attr = {0}; size_t copied = 1; cpu_type_t cpu; pid_t p = -1; int ret; int useASLR = 1; posix_spawnattr_init (&attr); if (useASLR != -1) { if (useASLR) { // enable aslr if not enabled? really? } else { ps_flags |= _POSIX_SPAWN_DISABLE_ASLR; } } (void)posix_spawnattr_setflags (&attr, ps_flags); #if __i386__ || __x86_64__ cpu = CPU_TYPE_I386; if (bits == 64) cpu |= CPU_ARCH_ABI64; #else cpu = CPU_TYPE_ANY; #endif posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &copied); ret = posix_spawnp (&p, argv[0], NULL, &attr, argv, NULL); switch (ret) { case 0: eprintf ("Success\n"); break; case 22: eprintf ("posix_spawnp: Invalid argument\n"); break; case 86: eprintf ("Unsupported architecture\n"); break; default: eprintf ("posix_spawnp: unknown error %d\n", ret); perror ("posix_spawnp"); break; } /* only required if no SETEXEC called if (p != -1) wait (p); */ exit (MAGIC_EXIT); /* error */ } #else if (argv && *argv) { execvp (argv[0], argv); } else { eprintf ("Invalid execvp\n"); } #endif free (_cmd); } perror ("fork_and_attach: execv"); //printf(stderr, "[%d] %s execv failed.\n", getpid(), ps.filename); exit (MAGIC_EXIT); /* error */ return 0; // invalid pid // if exit is overriden.. :) default: /* XXX: clean this dirty code */ do { ret = wait (&status); if (ret == -1) return -1; if (ret != pid) eprintf ("Wait event received by different pid %d\n", ret); } while (ret!=pid); if (WIFSTOPPED (status)) eprintf ("Process with PID %d started...\n", (int)pid); if (WEXITSTATUS (status) == MAGIC_EXIT) pid = -1; // XXX kill (pid, SIGSTOP); break; } eprintf ("PID = %d\n", pid); return pid; } #endif static int __plugin_open(RIO *io, const char *file, ut8 many) { if (!strncmp (file, "dbg://", 6) && file[6]) return R_TRUE; return R_FALSE; } static RIODesc *__open(RIO *io, const char *file, int rw, int mode) { char uri[128]; if (__plugin_open (io, file, 0)) { const char *pidfile = file + 6; char *endptr; int pid = (int)strtol (pidfile, &endptr, 10); if (endptr == pidfile || pid < 0) pid = -1; if (pid == -1) { pid = fork_and_ptraceme (io, io->bits, file+6); if (pid == -1) return NULL; #if __WINDOWS__ sprintf (uri, "w32dbg://%d", pid); #elif __APPLE__ sprintf (uri, "mach://%d", pid); #else // TODO: use io_procpid here? faster or what? sprintf (uri, "ptrace://%d", pid); #endif my_io_redirect (io, file, uri); } else { sprintf (uri, "attach://%d", pid); my_io_redirect (io, file, uri); } return NULL; } my_io_redirect (io, file, NULL); return NULL; }
// __UNIX__ (not windows) static int fork_and_ptraceme(RIO *io, int bits, const char *cmd) { bool runprofile = io->runprofile && *(io->runprofile); char **argv; #if __APPLE__ && !__POWERPC__ pid_t p = -1; posix_spawn_file_actions_t fileActions; ut32 ps_flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; sigset_t no_signals; sigset_t all_signals; size_t copied = 1; cpu_type_t cpu = CPU_TYPE_ANY; posix_spawnattr_t attr = {0}; posix_spawnattr_init (&attr); sigemptyset (&no_signals); sigfillset (&all_signals); posix_spawnattr_setsigmask (&attr, &no_signals); posix_spawnattr_setsigdefault (&attr, &all_signals); posix_spawn_file_actions_init (&fileActions); posix_spawn_file_actions_addinherit_np (&fileActions, STDIN_FILENO); posix_spawn_file_actions_addinherit_np (&fileActions, STDOUT_FILENO); posix_spawn_file_actions_addinherit_np (&fileActions, STDERR_FILENO); ps_flags |= POSIX_SPAWN_CLOEXEC_DEFAULT; ps_flags |= POSIX_SPAWN_START_SUSPENDED; #define _POSIX_SPAWN_DISABLE_ASLR 0x0100 if (!runprofile) { int ret, useASLR = io->aslr; char *_cmd = io->args ? r_str_appendf (strdup (cmd), " %s", io->args) : strdup (cmd); argv = r_str_argv (_cmd, NULL); if (!argv) { free (_cmd); return -1; } if (!*argv) { r_str_argv_free (argv); free (_cmd); eprintf ("Invalid execvp\n"); return -1; } if (useASLR != -1) { if (!useASLR) { ps_flags |= _POSIX_SPAWN_DISABLE_ASLR; } } (void)posix_spawnattr_setflags (&attr, ps_flags); #if __x86_64__ if (bits == 32) { cpu = CPU_TYPE_I386; // cpu |= CPU_ARCH_ABI64; } #endif posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &copied); { char *dst = r_file_readlink (argv[0]); if (dst) { argv[0] = dst; } } ret = posix_spawnp (&p, argv[0], NULL, &attr, argv, NULL); handle_posix_error (ret); posix_spawn_file_actions_destroy (&fileActions); r_str_argv_free (argv); free (_cmd); return p; } else { int ret; argv = r_str_argv (cmd, NULL); if (!argv) { posix_spawn_file_actions_destroy (&fileActions); return -1; } RRunProfile *rp = _get_run_profile (io, bits, argv); if (!rp) { r_str_argv_free (argv); posix_spawn_file_actions_destroy (&fileActions); return -1; } handle_posix_redirection (rp, &fileActions); if (rp->_args[0]) { if (!rp->_aslr) { ps_flags |= _POSIX_SPAWN_DISABLE_ASLR; } #if __x86_64__ if (rp->_bits == 32) { cpu = CPU_TYPE_I386; } #endif (void)posix_spawnattr_setflags (&attr, ps_flags); posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &copied); ret = posix_spawnp (&p, rp->_args[0], &fileActions, &attr, rp->_args, NULL); handle_posix_error (ret); } r_str_argv_free (argv); r_run_free (rp); posix_spawn_file_actions_destroy (&fileActions); return p; } posix_spawn_file_actions_destroy (&fileActions); return -1; #endif int ret, status, child_pid; child_pid = r_sys_fork (); switch (child_pid) { case -1: perror ("fork_and_ptraceme"); break; case 0: if (runprofile) { argv = r_str_argv (cmd, NULL); if (!argv) { exit(1); } RRunProfile *rp = _get_run_profile (io, bits, argv); if (!rp) { r_str_argv_free (argv); exit (1); } trace_me (); r_run_start (rp); r_run_free (rp); r_str_argv_free (argv); exit (1); } else { char *_cmd = io->args ? r_str_appendf (strdup (cmd), " %s", io->args) : strdup (cmd); trace_me (); argv = r_str_argv (_cmd, NULL); if (!argv) { free (_cmd); return -1; } if (argv && *argv) { int i; for (i = 3; i < 1024; i++) (void)close (i); execvp (argv[0], argv); } else { eprintf ("Invalid execvp\n"); } r_str_argv_free (argv); free (_cmd); } perror ("fork_and_attach: execv"); //printf(stderr, "[%d] %s execv failed.\n", getpid(), ps.filename); exit (MAGIC_EXIT); /* error */ return 0; // invalid pid // if exit is overriden.. :) default: /* XXX: clean this dirty code */ do { ret = wait (&status); if (ret == -1) return -1; if (ret != child_pid) { eprintf ("Wait event received by " "different pid %d\n", ret); } } while (ret != child_pid); if (WIFSTOPPED (status)) { eprintf ("Process with PID %d started...\n", (int)child_pid); } if (WEXITSTATUS (status) == MAGIC_EXIT) { child_pid = -1; } // XXX kill (pid, SIGSTOP); break; } return child_pid; }
static void trace_me () { #if __APPLE__ signal (SIGTRAP, SIG_IGN); //NEED BY STEP #endif #if __APPLE__ || __BSD__ /* we can probably remove this #if..as long as PT_TRACE_ME is redefined for OSX in r_debug.h */ signal (SIGABRT, inferior_abort_handler); if (ptrace (PT_TRACE_ME, 0, 0, 0) != 0) { #else if (ptrace (PTRACE_TRACEME, 0, NULL, NULL) != 0) { #endif r_sys_perror ("ptrace-traceme"); exit (MAGIC_EXIT); } } // __UNIX__ (not windows) static int fork_and_ptraceme(RIO *io, int bits, const char *cmd) { bool runprofile = io->runprofile && *(io->runprofile); char **argv; #if __APPLE__ && !__POWERPC__ if (!runprofile) { #define _POSIX_SPAWN_DISABLE_ASLR 0x0100 posix_spawn_file_actions_t fileActions; ut32 ps_flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; sigset_t no_signals; sigset_t all_signals; sigemptyset (&no_signals); sigfillset (&all_signals); posix_spawnattr_t attr = {0}; size_t copied = 1; cpu_type_t cpu; pid_t p = -1; int ret, useASLR = io->aslr; char *_cmd = io->args ? r_str_concatf (strdup (cmd), " %s", io->args) : strdup (cmd); argv = r_str_argv (_cmd, NULL); if (!argv) { free (_cmd); return -1; } if (!*argv) { r_str_argv_free (argv); free (_cmd); eprintf ("Invalid execvp\n"); return -1; } posix_spawnattr_init (&attr); if (useASLR != -1) { if (!useASLR) ps_flags |= _POSIX_SPAWN_DISABLE_ASLR; } posix_spawn_file_actions_init (&fileActions); posix_spawn_file_actions_addinherit_np (&fileActions, STDIN_FILENO); posix_spawn_file_actions_addinherit_np (&fileActions, STDOUT_FILENO); posix_spawn_file_actions_addinherit_np (&fileActions, STDERR_FILENO); ps_flags |= POSIX_SPAWN_CLOEXEC_DEFAULT; ps_flags |= POSIX_SPAWN_START_SUSPENDED; posix_spawnattr_setsigmask(&attr, &no_signals); posix_spawnattr_setsigdefault(&attr, &all_signals); (void)posix_spawnattr_setflags (&attr, ps_flags); #if __i386__ || __x86_64__ cpu = CPU_TYPE_I386; if (bits == 64) cpu |= CPU_ARCH_ABI64; #else cpu = CPU_TYPE_ANY; #endif posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &copied); { char *dst = r_file_readlink (argv[0]); if (dst) { argv[0] = dst; } } ret = posix_spawnp (&p, argv[0], &fileActions, &attr, argv, NULL); switch (ret) { case 0: // eprintf ("Success\n"); break; case 22: eprintf ("posix_spawnp: Invalid argument\n"); break; case 86: eprintf ("Unsupported architecture\n"); break; default: eprintf ("posix_spawnp: unknown error %d\n", ret); perror ("posix_spawnp"); break; } posix_spawn_file_actions_destroy (&fileActions); r_str_argv_free (argv); free (_cmd); return p; } #endif int ret, status, child_pid; child_pid = r_sys_fork (); switch (child_pid) { case -1: perror ("fork_and_ptraceme"); break; case 0: if (runprofile) { char *expr = NULL; int i; RRunProfile *rp = r_run_new (NULL); argv = r_str_argv (cmd, NULL); for (i = 0; argv[i]; i++) { rp->_args[i] = argv[i]; } rp->_args[i] = NULL; rp->_program = argv[0]; rp->_dodebug = true; if (io->runprofile && *io->runprofile) { if (!r_run_parsefile (rp, io->runprofile)) { eprintf ("Can't find profile '%s'\n", io->runprofile); exit (MAGIC_EXIT); } } if (bits == 64) r_run_parseline (rp, expr=strdup ("bits=64")); else if (bits == 32) r_run_parseline (rp, expr=strdup ("bits=32")); free (expr); if (r_run_config_env (rp)) { eprintf ("Can't config the environment.\n"); exit (1); } trace_me (); r_run_start (rp); r_run_free (rp); r_str_argv_free (argv); exit (1); } else { char *_cmd = io->args ? r_str_concatf (strdup (cmd), " %s", io->args) : strdup (cmd); trace_me (); argv = r_str_argv (_cmd, NULL); if (!argv) { free (_cmd); return -1; } if (argv && *argv) { int i; for (i = 3; i < 1024; i++) (void)close (i); execvp (argv[0], argv); } else { eprintf ("Invalid execvp\n"); } r_str_argv_free (argv); free (_cmd); } perror ("fork_and_attach: execv"); //printf(stderr, "[%d] %s execv failed.\n", getpid(), ps.filename); exit (MAGIC_EXIT); /* error */ return 0; // invalid pid // if exit is overriden.. :) default: /* XXX: clean this dirty code */ do { ret = wait (&status); if (ret == -1) return -1; if (ret != child_pid) { eprintf ("Wait event received by " "different pid %d\n", ret); } } while (ret != child_pid); if (WIFSTOPPED (status)) eprintf ("Process with PID %d started...\n", (int)child_pid); if (WEXITSTATUS (status) == MAGIC_EXIT) child_pid = -1; // XXX kill (pid, SIGSTOP); break; } return child_pid; }
// __UNIX__ (not windows) static int fork_and_ptraceme(RIO *io, int bits, const char *cmd) { char **argv; int ret, status, pid = fork (); switch (pid) { case -1: perror ("fork_and_ptraceme"); break; case 0: #if __APPLE__ signal (SIGTRAP, SIG_IGN); //NEED BY STEP #endif #if __APPLE__ || __BSD__ /* we can probably remove this #if..as long as PT_TRACE_ME is redefined for OSX in r_debug.h */ signal (SIGABRT, inferior_abort_handler); if (ptrace (PT_TRACE_ME, 0, 0, 0) != 0) { #else if (ptrace (PTRACE_TRACEME, 0, NULL, NULL) != 0) { #endif r_sys_perror ("ptrace-traceme"); exit (MAGIC_EXIT); } { char *expr = NULL; int i; RRunProfile *rp = r_run_new (NULL); argv = r_str_argv (cmd, NULL); for (i=0; argv[i]; i++) { rp->_args[i] = argv[i]; } rp->_args[i] = NULL; rp->_program = argv[0]; if (io->runprofile && *io->runprofile) { if (!r_run_parsefile (rp, io->runprofile)) { eprintf ("Can't find profile '%s'\n", io->runprofile); exit (MAGIC_EXIT); } } if (bits==64) r_run_parseline (rp, expr=strdup ("bits=64")); else if (bits==32) r_run_parseline (rp, expr=strdup ("bits=32")); free (expr); r_run_start (rp); r_run_free (rp); // double free wtf // r_str_argv_free (argv); exit (1); } perror ("fork_and_attach: execv"); //printf(stderr, "[%d] %s execv failed.\n", getpid(), ps.filename); exit (MAGIC_EXIT); /* error */ return 0; // invalid pid // if exit is overriden.. :) default: /* XXX: clean this dirty code */ ret = wait (&status); if (ret != pid) eprintf ("Wait event received by different pid %d\n", ret); if (WIFSTOPPED (status)) eprintf ("Process with PID %d started...\n", (int)pid); if (WEXITSTATUS (status) == MAGIC_EXIT) pid = -1; // XXX kill (pid, SIGSTOP); break; } eprintf ("PID = %d\n", pid); return pid; } #endif static int __plugin_open(RIO *io, const char *file, ut8 many) { if (!strncmp (file, "dbg://", 6) && file[6]) return R_TRUE; return R_FALSE; } static RIODesc *__open(RIO *io, const char *file, int rw, int mode) { char uri[128]; if (__plugin_open (io, file, 0)) { int pid = atoi (file+6); if (pid == 0) { pid = fork_and_ptraceme (io, io->bits, file+6); if (pid==-1) return NULL; #if __WINDOWS__ sprintf (uri, "w32dbg://%d", pid); #elif __APPLE__ sprintf (uri, "mach://%d", pid); #else // TODO: use io_procpid here? faster or what? sprintf (uri, "ptrace://%d", pid); #endif my_io_redirect (io, uri); } else { sprintf (uri, "attach://%d", pid); my_io_redirect (io, uri); } return NULL; } my_io_redirect (io, NULL); return NULL; }
static int cmd_eval(void *data, const char *input) { char *p; RCore *core = (RCore *)data; switch (input[0]) { case 't': // env if (input[1] == 'a') { r_cons_printf ("%s\n", (r_num_rand (10) % 2)? "wen": "son"); } else if (input[1]==' ' && input[2]) { RConfigNode *node = r_config_node_get (core->config, input+2); if (node) { const char *type = r_config_node_type (node); if (type && *type) { r_cons_println (type); } } } else { eprintf ("Usage: et [varname] ; show type of eval var\n"); } break; case 'n': // env if (!strchr (input, '=')) { char *var, *p; var = strchr (input, ' '); if (var) while (*var==' ') var++; p = r_sys_getenv (var); if (p) { r_cons_println (p); free (p); } else { char **e = r_sys_get_environ (); while (e && *e) { r_cons_println (*e); e++; } } } else if (strlen (input)>3) { char *v, *k = strdup (input+3); if (!k) break; v = strchr (k, '='); if (v) { *v++ = 0; r_sys_setenv (k, v); } free (k); } return true; case 'x': // exit // XXX we need headers for the cmd_xxx files. return cmd_quit (data, ""); case 'j': // json r_config_list (core->config, NULL, 'j'); break; case 'v': // verbose r_config_list (core->config, input + 1, 'v'); break; case 'q': // quiet list of eval keys r_config_list (core->config, NULL, 'q'); break; case '\0': // "e" r_config_list (core->config, NULL, 0); break; case 'c': // "ec" switch (input[1]) { case 'd': r_cons_pal_init (NULL); break; case '?': { const char *helpmsg[] = { "Usage ec[s?] [key][[=| ]fg] [bg]","","", "ec","","list all color keys", "ec*","","same as above, but using r2 commands", "ecd","","set default palette", "ecr","","set random palette (see also scr.randpal)", "ecs","","show a colorful palette", "ecj","","show palette in JSON", "ecc"," [prefix]","show palette in CSS", "eco"," dark|white","load white color scheme template", "ecp","","load previous color theme", "ecn","","load next color theme", "ecH","[?]","highlight word or instruction", "ec"," prompt red","change color of prompt", "ec"," prompt red blue","change color and background of prompt", ""," ","", "colors:","","rgb:000, red, green, blue, ...", "e scr.rgbcolor","=1|0","for 256 color cube (boolean)", "e scr.truecolor","=1|0","for 256*256*256 colors (boolean)", "$DATADIR/radare2/cons","","~/.config/radare2/cons ./", NULL}; r_core_cmd_help (core, helpmsg); } break; case 'o': // "eco" if (input[2] == 'j') { nextpal (core, 'j'); } else if (input[2] == ' ') { bool failed = false; char *home, path[512]; snprintf (path, sizeof (path), ".config/radare2/cons/%s", input + 3); home = r_str_home (path); snprintf (path, sizeof (path), R2_DATDIR"/radare2/" R2_VERSION"/cons/%s", input + 3); if (!load_theme (core, home)) { if (load_theme (core, path)) { //curtheme = r_str_dup (curtheme, path); curtheme = r_str_dup (curtheme, input + 3); } else { if (load_theme (core, input + 3)) { curtheme = r_str_dup (curtheme, input + 3); } else { char *absfile = r_file_abspath (input + 3); eprintf ("eco: cannot open colorscheme profile (%s)\n", absfile); free (absfile); failed = true; } } } free (home); if (failed) { eprintf ("Something went wrong\n"); } } else if (input[2] == '?') { eprintf ("Usage: eco [themename] ;load theme from "R2_DATDIR"/radare2/"R2_VERSION"/cons/\n"); } else { nextpal (core, 'l'); } break; case 's': r_cons_pal_show (); break; // "ecs" case '*': r_cons_pal_list (1, NULL); break; // "ec*" case 'h': // echo if (( p = strchr (input, ' ') )) { r_cons_strcat (p+1); r_cons_newline (); } else { // "ech" r_cons_pal_list ('h', NULL); } break; case 'j': // "ecj" r_cons_pal_list ('j', NULL); break; case 'c': // "ecc" r_cons_pal_list ('c', input + 2); break; case '\0': // "ec" r_cons_pal_list (0, NULL); break; case 'r': // "ecr" r_cons_pal_random (); break; case 'n': // "ecn" nextpal (core, 'n'); break; case 'p': // "ecp" nextpal (core, 'p'); break; case 'H': { // "ecH" char *color_code = NULL; char *word = NULL; int argc = 0; char** argv = r_str_argv (input + 4, &argc); switch (input[2]) { case '?': { const char *helpmsg[] = { "Usage ecH[iw-?]","","", "ecHi","[color]","highlight current instruction with 'color' background", "ecHw","[word] [color]","highlight 'word ' in current instruction with 'color' background", "ecH-","","remove all highlights on current instruction", NULL }; r_core_cmd_help (core, helpmsg); } break; case '-': r_meta_set_string (core->anal, R_META_TYPE_HIGHLIGHT, core->offset, ""); return false; case '\0': case 'i': // "ecHi if (argc) { char *dup = r_str_newf ("bgonly %s", argv[0]); color_code = r_cons_pal_parse (dup); R_FREE (dup); } break; case 'w': // "ecHw" if (!argc) { eprintf ("Usage: echw word [color]\n"); r_str_argv_free (argv); return true; } word = strdup (argv[0]); if (argc > 1) { char *dup = r_str_newf ("bgonly %s", argv[1]); color_code = r_cons_pal_parse (dup); if (!color_code) { eprintf ("Unknown color %s\n", argv[1]); r_str_argv_free (argv); free (dup); free (word); return true; } R_FREE (dup); } break; default: eprintf ("See ecH?\n"); r_str_argv_free (argv); return true; } char *str = r_meta_get_string (core->anal, R_META_TYPE_HIGHLIGHT, core->offset); char *dup = r_str_newf ("%s \"%s%s\"", str?str:"", word?word:"", color_code?color_code:r_cons_pal_get ("highlight")); r_meta_set_string (core->anal, R_META_TYPE_HIGHLIGHT, core->offset, dup); r_str_argv_free (argv); R_FREE (word); R_FREE (dup); break; } default: { char *p = strdup (input + 2); char *q = strchr (p, '='); if (!q) { q = strchr (p, ' '); } if (q) { // set *q++ = 0; r_cons_pal_set (p, q); } else { const char *k = r_cons_pal_get (p); if (k) { eprintf ("(%s)(%sCOLOR"Color_RESET")\n", p, k); } } free (p); } } break; case 'e': if (input[1] == ' ') { char *p; const char *val, *input2 = strchr (input+2, ' '); if (input2) input2++; else input2 = input+2; val = r_config_get (core->config, input2); p = r_core_editor (core, NULL, val); if (p) { r_str_replace_char (p, '\n', ';'); r_config_set (core->config, input2, p); } } else { eprintf ("Usage: ee varname\n"); } break; case '!': input = r_str_chop_ro (input+1); if (!r_config_toggle (core->config, input)) eprintf ("r_config: '%s' is not a boolean variable.\n", input); break; case 's': r_config_list (core->config, (input[1])? input + 1: NULL, 's'); break; case '-': r_core_config_init (core); //eprintf ("BUG: 'e-' command locks the eval hashtable. patches are welcome :)\n"); break; case '*': r_config_list (core->config, NULL, 1); break; case '?': switch (input[1]) { case '?': r_config_list (core->config, input+2, 2); break; default: r_config_list (core->config, input+1, 2); break; case 0: r_core_cmd_help (core, help_msg_e); } break; case 'r': if (input[1]) { const char *key = input+((input[1]==' ')?2:1); if (!r_config_readonly (core->config, key)) { eprintf ("cannot find key '%s'\n", key); } } else { eprintf ("Usage: er [key]\n"); } break; case ' ': r_config_eval (core->config, input+1); break; default: r_config_eval (core->config, input); break; } return 0; }
static int fork_and_ptraceme(int bits, const char *cmd) { char **argv; int ret, status, pid = fork (); switch (pid) { case -1: perror ("fork_and_ptraceme"); break; case 0: #if __APPLE__ signal (SIGTRAP, SIG_IGN); //NEED BY STEP #endif #if __APPLE__ || __BSD__ /* we can probably remove this #if..as long as PT_TRACE_ME is redefined for OSX in r_debug.h */ signal (SIGABRT, inferior_abort_handler); if (ptrace (PT_TRACE_ME, 0, 0, 0) != 0) { #else if (ptrace (PTRACE_TRACEME, 0, NULL, NULL) != 0) { #endif eprintf ("ptrace-traceme failed\n"); exit (MAGIC_EXIT); } // TODO: Add support to redirect filedescriptors // TODO: Configure process environment argv = r_str_argv (cmd, NULL); #if __APPLE__ #include <spawn.h> { posix_spawnattr_t attr = {0}; size_t copied = 1; cpu_type_t cpu; int ret; pid_t p = -1; posix_spawnattr_init (&attr); posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETEXEC); #if __i386__ || __x86_64__ cpu = CPU_TYPE_I386; if (bits == 64) cpu |= CPU_ARCH_ABI64; #else cpu = CPU_TYPE_ANY; #endif posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &copied); //ret = posix_spawnp (NULL, argv[0], NULL, &attr, argv, NULL); ret = posix_spawnp (&p, argv[0], NULL, &attr, argv, NULL); switch (ret) { case 0: eprintf ("Success\n"); break; case 22: eprintf ("posix_spawnp: Invalid argument\n"); break; case 86: eprintf ("Unsupported architecture\n"); break; default: eprintf ("posix_spawnp: unknown error %d\n", ret); perror ("posix_spawnp"); break; } /* only required if no SETEXEC called if (p != -1) wait (p); */ exit (MAGIC_EXIT); /* error */ } #else execvp (argv[0], argv); #endif r_str_argv_free (argv); perror ("fork_and_attach: execv"); //printf(stderr, "[%d] %s execv failed.\n", getpid(), ps.filename); exit (MAGIC_EXIT); /* error */ return 0; // invalid pid // if exit is overriden.. :) default: /* XXX: clean this dirty code */ ret = wait (&status); if (ret != pid) eprintf ("Wait event received by different pid %d\n", ret); if (WIFSTOPPED (status)) eprintf ("Process with PID %d started...\n", (int)pid); if (WEXITSTATUS (status) == MAGIC_EXIT) pid = -1; // XXX kill (pid, SIGSTOP); break; } eprintf ("PID = %d\n", pid); return pid; } #endif static int __plugin_open(RIO *io, const char *file) { if (!memcmp (file, "dbg://", 6) && file[6]) return R_TRUE; return R_FALSE; } static RIODesc *__open(RIO *io, const char *file, int rw, int mode) { char uri[128]; if (__plugin_open (io, file)) { int pid = atoi (file+6); if (pid == 0) { // TODO: get bits from ELF? pid = fork_and_ptraceme (io->bits, file+6); if (pid==-1) return NULL; #if __WINDOWS__ sprintf (uri, "w32dbg://%d", pid); #elif __APPLE__ sprintf (uri, "mach://%d", pid); #else // TODO: use io_procpid here? faster or what? sprintf (uri, "ptrace://%d", pid); #endif eprintf ("io_redirect: %s\n", uri); r_io_redirect (io, uri); return NULL; } else { sprintf (uri, "attach://%d", pid); r_io_redirect (io, uri); return NULL; } } r_io_redirect (io, NULL); return NULL; }
static int fork_and_ptraceme(RIO *io, int bits, const char *cmd) { #if __APPLE__ && !__POWERPC__ return fork_and_ptraceme_for_mac(io, bits, cmd); #else int ret, status, child_pid; bool runprofile = io->runprofile && *(io->runprofile); char **argv; child_pid = r_sys_fork (); switch (child_pid) { case -1: perror ("fork_and_ptraceme"); break; case 0: if (runprofile) { argv = r_str_argv (cmd, NULL); if (!argv) { exit(1); } RRunProfile *rp = _get_run_profile (io, bits, argv); if (!rp) { r_str_argv_free (argv); exit (1); } trace_me (); r_run_start (rp); r_run_free (rp); r_str_argv_free (argv); exit (1); } else { char *_cmd = io->args ? r_str_appendf (strdup (cmd), " %s", io->args) : strdup (cmd); trace_me (); argv = r_str_argv (_cmd, NULL); if (!argv) { free (_cmd); return -1; } if (argv && *argv) { int i; for (i = 3; i < 1024; i++) { (void)close (i); } if (execvp (argv[0], argv) == -1) { eprintf ("Could not execvp: %s\n", strerror (errno)); exit (MAGIC_EXIT); } } else { eprintf ("Invalid execvp\n"); } r_str_argv_free (argv); free (_cmd); } perror ("fork_and_attach: execv"); //printf(stderr, "[%d] %s execv failed.\n", getpid(), ps.filename); exit (MAGIC_EXIT); /* error */ return 0; // invalid pid // if exit is overriden.. :) default: /* XXX: clean this dirty code */ do { ret = wait (&status); if (ret == -1) return -1; if (ret != child_pid) { eprintf ("Wait event received by " "different pid %d\n", ret); } } while (ret != child_pid); if (WIFSTOPPED (status)) { eprintf ("Process with PID %d started...\n", (int)child_pid); } if (WEXITSTATUS (status) == MAGIC_EXIT) { child_pid = -1; } // XXX kill (pid, SIGSTOP); break; } return child_pid; #endif }