static int __open_proc (RIOW32Dbg *dbg, bool attach) { DEBUG_EVENT de; int ret = -1; HANDLE h_proc = OpenProcess (PROCESS_ALL_ACCESS, FALSE, dbg->pid); if (!h_proc) { r_sys_perror ("__open_proc/OpenProcess"); goto att_exit; } if (attach) { /* Attach to the process */ if (!DebugActiveProcess(dbg->pid)) { r_sys_perror ("__open_proc/DebugActiveProcess"); goto att_exit; } /* catch create process event */ if (!WaitForDebugEvent (&de, 10000)) { r_sys_perror ("__open_proc/WaitForDebugEvent"); goto att_exit; } if (de.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT) { eprintf ("exception code 0x%04x\n", (ut32)de.dwDebugEventCode); goto att_exit; } dbg->winbase = (ut64)de.u.CreateProcessInfo.lpBaseOfImage; } dbg->pi.hProcess = h_proc; dbg->tid = __w32_first_thread (dbg->pid); ret = dbg->pid; att_exit: if (ret == -1 && h_proc) { CloseHandle (h_proc); } return ret; }
static int setup_tokens() { HANDLE tok; TOKEN_PRIVILEGES tp; DWORD err; tok = NULL; err = -1; if (!OpenProcessToken (GetCurrentProcess (), TOKEN_ADJUST_PRIVILEGES, &tok)) goto err_enable; tp.PrivilegeCount = 1; if (!LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid)) goto err_enable; //tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0; tp.Privileges[0].Attributes = 0; //SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges (tok, 0, &tp, sizeof (tp), NULL, NULL)) goto err_enable; err = 0; err_enable: if (tok != NULL) CloseHandle (tok); if (err) r_sys_perror ("setup_tokens"); return err; }
R_API bool r_sys_create_child_proc_w32(const char *cmdline, HANDLE out) { PROCESS_INFORMATION pi = {0}; STARTUPINFO si = {0}; LPTSTR cmdline_; bool ret; // Set up members of the STARTUPINFO structure. // This structure specifies the STDIN and STDOUT handles for redirection. si.cb = sizeof (STARTUPINFO); si.hStdError = out; si.hStdOutput = out; si.hStdInput = NULL; si.dwFlags |= STARTF_USESTDHANDLES; cmdline_ = r_sys_conv_utf8_to_utf16 (cmdline); if ((ret = CreateProcess (NULL, cmdline_,// command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited 0, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &si, // STARTUPINFO pointer &pi))) { // receives PROCESS_INFORMATION ret = 1; CloseHandle (pi.hProcess); CloseHandle (pi.hThread); } else { r_sys_perror ("CreateProcess"); } free (cmdline_); return ret; }
// UNUSED 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) { r_sys_perror ("ptrace-traceme"); } #else if (ptrace (PTRACE_TRACEME, 0, NULL, NULL) != 0) { r_sys_perror ("ptrace-traceme"); exit (MAGIC_EXIT); } #endif }
static int iob_pipe_write(void *p, const uint8_t *buf, const uint64_t count, const int timeout) { int ret = send ((int) (size_t) p, buf, count, 0); if (ret < 1) { r_sys_perror ("iob_pipe_write, send"); if (errno == EPIPE) { exit (1); } } return ret; }
/* TODO: must return true/false */ static int r_debug_native_continue(RDebug *dbg, int pid, int tid, int sig) { #if __WINDOWS__ && !__CYGWIN__ /* Honor the Windows-specific signal that instructs threads to process exceptions */ DWORD continue_status = (sig == DBG_EXCEPTION_NOT_HANDLED) ? DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE; if (ContinueDebugEvent (pid, tid, continue_status) == 0) { r_sys_perror ("r_debug_native_continue/ContinueDebugEvent"); eprintf ("debug_contp: error\n"); return false; } return tid; #elif __APPLE__ bool ret; ret = xnu_continue (dbg, pid, tid, sig); if (!ret) { return -1; } return tid; #elif __BSD__ void *data = (void*)(size_t)((sig != -1) ? sig : dbg->reason.signum); ut64 pc = r_debug_reg_get (dbg, "PC"); return ptrace (PTRACE_CONT, pid, (void*)(size_t)pc, (int)(size_t)data) == 0; #elif __CYGWIN__ #warning "r_debug_native_continue not supported on this platform" return -1; #else int contsig = dbg->reason.signum; if (sig != -1) { contsig = sig; } /* SIGINT handler for attached processes: dbg.consbreak (disabled by default) */ if (dbg->consbreak) { r_cons_break_push ((RConsBreak)r_debug_native_stop, dbg); } int ret = ptrace (PTRACE_CONT, pid, NULL, contsig); if (ret) { perror ("PTRACE_CONT"); } if (dbg->continue_all_threads && dbg->n_threads) { RList *list = dbg->threads; RDebugPid *th; RListIter *it; if (list) { r_list_foreach (list, it, th) { if (th->pid && th->pid != pid) { ptrace (PTRACE_CONT, tid, NULL, contsig); } } } }
static int r_bin_te_init_hdr(struct r_bin_te_obj_t *bin) { if (!bin) return false; if (!(bin->header = malloc(sizeof(TE_image_file_header)))) { r_sys_perror ("malloc (header)"); return false; } if (r_buf_read_at (bin->b, 0, (ut8*)bin->header, sizeof(TE_image_file_header)) == -1) { eprintf("Error: read (header)\n"); return false; } if (!bin->kv) { eprintf("Error: sdb instance is empty\n"); return false; } sdb_set (bin->kv, "te_machine.cparse", "enum te_machine { TE_IMAGE_FILE_MACHINE_UNKNOWN=0x0, TE_IMAGE_FILE_MACHINE_ALPHA=0x184, " "TE_IMAGE_FILE_MACHINE_ALPHA64=0x284, TE_IMAGE_FILE_MACHINE_AM33=0x1d3, TE_IMAGE_FILE_MACHINE_AMD64=0x8664, " "TE_IMAGE_FILE_MACHINE_ARM=0x1c0, TE_IMAGE_FILE_MACHINE_AXP64=0x184, TE_IMAGE_FILE_MACHINE_CEE=0xc0ee, " "TE_IMAGE_FILE_MACHINE_CEF=0x0cef, TE_IMAGE_FILE_MACHINE_EBC=0x0ebc, TE_IMAGE_FILE_MACHINE_I386=0x014c, " "TE_IMAGE_FILE_MACHINE_IA64=0x0200, TE_IMAGE_FILE_MACHINE_M32R=0x9041, TE_IMAGE_FILE_MACHINE_M68K=0x0268, " "TE_IMAGE_FILE_MACHINE_MIPS16=0x0266, TE_IMAGE_FILE_MACHINE_MIPSFPU=0x0366, TE_IMAGE_FILE_MACHINE_MIPSFPU16=0x0466, " "TE_IMAGE_FILE_MACHINE_POWERPC=0x01f0, TE_IMAGE_FILE_MACHINE_POWERPCFP=0x01f1, TE_IMAGE_FILE_MACHINE_R10000=0x0168, " "TE_IMAGE_FILE_MACHINE_R3000=0x0162, TE_IMAGE_FILE_MACHINE_R4000=0x0166, TE_IMAGE_FILE_MACHINE_SH3=0x01a2, " "TE_IMAGE_FILE_MACHINE_SH3DSP=0x01a3, TE_IMAGE_FILE_MACHINE_SH3E=0x01a4, TE_IMAGE_FILE_MACHINE_SH4=0x01a6, " "TE_IMAGE_FILE_MACHINE_SH5=0x01a8, TE_IMAGE_FILE_MACHINE_THUMB=0x01c2, TE_IMAGE_FILE_MACHINE_TRICORE=0x0520, " "TE_IMAGE_FILE_MACHINE_WCEMIPSV2=0x0169};", 0); sdb_set (bin->kv, "te_subsystem.cparse", "enum te_subsystem { TE_IMAGE_SUBSYSTEM_UNKNOWN=0, TE_IMAGE_SUBSYSTEM_NATIVE=1, " "TE_IMAGE_SUBSYSTEM_WINDOWS_GUI=2, TE_IMAGE_SUBSYSTEM_WINDOWS_CUI=3, " "TE_IMAGE_SUBSYSTEM_POSIX_CUI=7, TE_IMAGE_SUBSYSTEM_WINDOWS_CE_GU=9, " "TE_IMAGE_SUBSYSTEM_EFI_APPLICATION=10, TE_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER=11, TE_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER=12, " "TE_IMAGE_SUBSYSTEM_EFI_ROM=13, TE_IMAGE_SUBSYSTEM_XBOX=14};", 0); sdb_num_set (bin->kv, "te_header.offset", 0, 0); sdb_set (bin->kv, "te_header.format", "[2]z[2]Eb[1]Ewxxq" " Signature (te_machine)Machine NumberOfSections (te_subsystem)Subsystem StrippedSize AddressOfEntryPoint BaseOfCode ImageBase", 0); sdb_num_set (bin->kv, "te_directory1_header.offset", 24, 0); sdb_set (bin->kv, "te_directory1_header.format", "xx" " VirtualAddress Size", 0); sdb_num_set (bin->kv, "te_directory2_header.offset", 32, 0); sdb_set (bin->kv, "te_directory2_header.format", "xx" " VirtualAddress Size", 0); if (strncmp ((char*)&bin->header->Signature, "VZ", 2)) return false; return true; }
R_API RSocket *r_socket_accept(RSocket *s) { RSocket *sock; socklen_t salen = sizeof (s->sa); if (!s) { return NULL; } sock = R_NEW0 (RSocket); if (!sock) { return NULL; } //signal (SIGPIPE, SIG_DFL); sock->fd = accept (s->fd, (struct sockaddr *)&s->sa, &salen); if (sock->fd == -1) { if (errno != EWOULDBLOCK) { // not just a timeout r_sys_perror ("accept"); } free (sock); return NULL; } #if HAVE_LIB_SSL sock->is_ssl = s->is_ssl; if (sock->is_ssl) { sock->sfd = NULL; sock->ctx = NULL; sock->bio = NULL; BIO *sbio = BIO_new_socket (sock->fd, BIO_NOCLOSE); sock->sfd = SSL_new (s->ctx); SSL_set_bio (sock->sfd, sbio, sbio); if (SSL_accept (sock->sfd) <= 0) { r_socket_free (sock); return NULL; } sock->bio = BIO_new (BIO_f_buffer ()); sbio = BIO_new (BIO_f_ssl ()); BIO_set_ssl (sbio, sock->sfd, BIO_CLOSE); BIO_push (sock->bio, sbio); } #else sock->is_ssl = 0; #endif return sock; }
static int __w32_first_thread(int pid) { HANDLE th; HANDLE thid; THREADENTRY32 te32; te32.dwSize = sizeof (THREADENTRY32); th = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, pid); if (th == INVALID_HANDLE_VALUE) { return -1; } if (!Thread32First (th, &te32)) { CloseHandle (th); return -1; } do { /* get all threads of process */ if (te32.th32OwnerProcessID == pid) { #if __MINGW32__ r2_OpenThread = r_lib_dl_sym (NULL, "OpenThread"); #else r2_OpenThread = OpenThread; #endif thid = r2_OpenThread ? r2_OpenThread (THREAD_ALL_ACCESS, 0, te32.th32ThreadID) : NULL; if (!thid) { r_sys_perror ("__w32_first_thread/OpenThread"); goto err_first_th; } CloseHandle (th); return te32.th32ThreadID; } } while (Thread32Next (th, &te32)); err_first_th: eprintf ("Could not find an active thread for pid %d\n", pid); CloseHandle (th); return pid; }
static RList *r_debug_native_pids (int pid) { RList *list = r_list_new (); if (!list) return NULL; #if __WINDOWS__ && !__CYGWIN__ return w32_pids (pid, list); #elif __APPLE__ if (pid) { RDebugPid *p = xnu_get_pid (pid); if (p) r_list_append (list, p); } else { int i; for (i = 1; i < MAXPID; i++) { RDebugPid *p = xnu_get_pid (i); if (p) r_list_append (list, p); } } #elif __linux__ int i; char *ptr, buf[1024]; list->free = (RListFree)&r_debug_pid_free; if (pid) { DIR *dh; struct dirent *de; /* add the requested pid. should we do this? we don't even know if it's valid still.. */ r_list_append (list, r_debug_pid_new ("(current)", pid, 's', 0)); /* list parents */ dh = opendir ("/proc"); if (!dh) { r_sys_perror ("opendir /proc"); r_list_free (list); return NULL; } while ((de = readdir (dh))) { /* for each existing pid file... */ i = atoi (de->d_name); if (i <= 0) { continue; } /* try to read the status */ buf[0] = 0; if (procfs_pid_slurp (i, "status", buf, sizeof (buf)) == -1) { continue; } buf[sizeof (buf) - 1] = 0; /* look for the parent process id */ ptr = strstr (buf, "PPid:"); if (ptr) { int ppid = atoi (ptr + 6); /* if this is the requested process... */ if (i == pid) { //eprintf ("PPid: %d\n", ppid); /* append it to the list with parent */ r_list_append (list, r_debug_pid_new ( "(ppid)", ppid, 's', 0)); } /* ignore it if it is not one of our children */ if (ppid != pid) { continue; } /* it's a child of the requested pid, read it's command line and add it */ if (procfs_pid_slurp (ppid, "cmdline", buf, sizeof(buf)) == -1) { continue; } r_list_append (list, r_debug_pid_new (buf, i, 's', 0)); } } closedir (dh); } else { /* try to bruteforce the processes * XXX(jjd): wouldn't listing the processes like before work better? */ for (i = 2; i < MAXPID; i++) { /* try to send signal 0, if it fails it must not be valid */ if (r_sandbox_kill (i, 0) == -1) continue; if (procfs_pid_slurp (i, "cmdline", buf, sizeof(buf)) == -1) continue; r_list_append (list, r_debug_pid_new (buf, i, 's', 0)); } } #else /* rest is BSD */ #ifdef __NetBSD__ # define KVM_OPEN_FLAG KVM_NO_FILES # define KVM_GETPROCS(kd, opt, arg, cntptr) \ kvm_getproc2 (kd, opt, arg, sizeof(struct kinfo_proc2), cntptr) # define KP_COMM(x) (x)->p_comm # define KP_PID(x) (x)->p_pid # define KP_PPID(x) (x)->p_ppid # define KINFO_PROC kinfo_proc2 #elif defined(__OpenBSD__) # define KVM_OPEN_FLAG KVM_NO_FILES # define KVM_GETPROCS(kd, opt, arg, cntptr) \ kvm_getprocs (kd, opt, arg, sizeof(struct kinfo_proc), cntptr) # define KP_COMM(x) (x)->p_comm # define KP_PID(x) (x)->p_pid # define KP_PPID(x) (x)->p_ppid # define KINFO_PROC kinfo_proc #else # define KVM_OPEN_FLAG O_RDONLY # define KVM_GETPROCS(kd, opt, arg, cntptr) \ kvm_getprocs (kd, opt, arg, cntptr) # define KP_COMM(x) (x)->ki_comm # define KP_PID(x) (x)->ki_pid # define KP_PPID(x) (x)->ki_ppid # define KINFO_PROC kinfo_proc #endif char errbuf[_POSIX2_LINE_MAX]; struct KINFO_PROC* kp; int cnt = 0; kvm_t* kd = kvm_openfiles (NULL, NULL, NULL, KVM_OPEN_FLAG, errbuf); if (!kd) { eprintf ("kvm_openfiles says %s\n", errbuf); return NULL; } if (pid) { kp = KVM_GETPROCS (kd, KERN_PROC_PID, pid, &cnt); if (cnt == 1) { RDebugPid *p = r_debug_pid_new (KP_COMM(kp), pid, 's', 0); if (p) r_list_append (list, p); /* we got our process, now fetch the parent process */ kp = KVM_GETPROCS (kd, KERN_PROC_PID, KP_PPID(kp), &cnt); if (cnt == 1) { RDebugPid *p = r_debug_pid_new (KP_COMM(kp), KP_PID(kp), 's', 0); if (p) r_list_append (list, p); } } } else { kp = KVM_GETPROCS (kd, KERN_PROC_UID, geteuid(), &cnt); int i; for (i = 0; i < cnt; i++) { RDebugPid *p = r_debug_pid_new (KP_COMM(kp + i), KP_PID(kp + i), 's', 0); if (p) r_list_append (list, p); } } kvm_close(kd); #endif return list; }
/* * wait for an event and start trying to figure out what to do with it. * * Returns R_DEBUG_REASON_* */ static RDebugReasonType r_debug_native_wait (RDebug *dbg, int pid) { int status = -1; RDebugReasonType reason = R_DEBUG_REASON_UNKNOWN; #if __WINDOWS__ && !__CYGWIN__ int mode = 0; reason = w32_dbg_wait (dbg, pid); if (reason == R_DEBUG_REASON_NEW_LIB) { mode = 'l'; } else if (reason == R_DEBUG_REASON_EXIT_LIB) { mode = 'u'; } else { mode = 0; } if (mode) { RDebugInfo *r = r_debug_native_info (dbg, ""); if (r && r->lib) { if (tracelib (dbg, mode=='l'? "load":"unload", r->lib)) reason = R_DEBUG_REASON_TRAP; } else { eprintf ("%soading unknown library.\n", mode?"L":"Unl"); } r_debug_info_free (r); } #else if (pid == -1) { eprintf ("r_debug_native_wait called with -1 pid!\n"); return R_DEBUG_REASON_ERROR; } #if __APPLE__ // eprintf ("No waitpid here :D\n"); reason = xnu_wait (dbg, pid); status = reason? 1: 0; #else // XXX: this is blocking, ^C will be ignored #ifdef WAIT_ON_ALL_CHILDREN //eprintf ("waiting on all children ...\n"); int ret = waitpid (-1, &status, WAITPID_FLAGS); #else //eprintf ("waiting on pid %d ...\n", pid); int ret = waitpid (pid, &status, WAITPID_FLAGS); #endif // WAIT_ON_ALL_CHILDREN if (ret == -1) { r_sys_perror ("waitpid"); return R_DEBUG_REASON_ERROR; } //eprintf ("r_debug_native_wait: status=%d (0x%x) (return=%d)\n", status, status, ret); #ifdef WAIT_ON_ALL_CHILDREN if (ret != pid) { reason = R_DEBUG_REASON_NEW_PID; eprintf ("switching to pid %d\n", ret); r_debug_select(dbg, ret, ret); } #endif // WAIT_ON_ALL_CHILDREN // TODO: switch status and handle reasons here #if __linux__ && defined(PT_GETEVENTMSG) reason = linux_ptrace_event (dbg, pid, status); #endif // __linux__ /* propagate errors */ if (reason == R_DEBUG_REASON_ERROR) { return reason; } /* we don't know what to do yet, let's try harder to figure it out. */ if (reason == R_DEBUG_REASON_UNKNOWN) { if (WIFEXITED (status)) { eprintf ("child exited with status %d\n", WEXITSTATUS (status)); reason = R_DEBUG_REASON_DEAD; } else if (WIFSIGNALED (status)) { eprintf ("child received signal %d\n", WTERMSIG (status)); reason = R_DEBUG_REASON_SIGNAL; } else if (WIFSTOPPED (status)) { if (WSTOPSIG (status) != SIGTRAP) { eprintf ("child stopped with signal %d\n", WSTOPSIG (status)); } /* this one might be good enough... */ dbg->reason.signum = WSTOPSIG (status); /* the ptrace documentation says GETSIGINFO is only necessary for * differentiating the various stops. * * this might modify dbg->reason.signum */ if (!r_debug_handle_signals (dbg)) return R_DEBUG_REASON_ERROR; reason = dbg->reason.type; } else if (WIFCONTINUED (status)) { eprintf ("child continued...\n"); reason = R_DEBUG_REASON_NONE; } else if (status == 1) { /* XXX(jjd): does this actually happen? */ eprintf ("EEK DEAD DEBUGEE!\n"); reason = R_DEBUG_REASON_DEAD; } else if (status == 0) { /* XXX(jjd): does this actually happen? */ eprintf ("STATUS=0?!?!?!?\n"); reason = R_DEBUG_REASON_DEAD; } else { if (ret != pid) { reason = R_DEBUG_REASON_NEW_PID; } else { /* ugh. still don't know :-/ */ eprintf ("CRAP. returning from wait without knowing why...\n"); } } } /* if we still don't know what to do, we have a problem... */ if (reason == R_DEBUG_REASON_UNKNOWN) { eprintf ("%s: no idea what happened... wtf?!?!\n", __func__); reason = R_DEBUG_REASON_ERROR; } #endif // __APPLE__ #endif // __WINDOWS__ && !__CYGWIN__ dbg->reason.tid = pid; dbg->reason.type = reason; return reason; }
R_API int r_socket_listen (RSocket *s, const char *port, const char *certfile) { #if __UNIX__ || defined(__CYGWIN__) int optval = 1; int ret; struct linger linger = { 0 }; #endif if (r_sandbox_enable (0)) return false; #if __WINDOWS__ && !defined(__CYGWIN__) && !defined(__MINGW64__) WSADATA wsadata; if (WSAStartup (MAKEWORD (1, 1), &wsadata) == SOCKET_ERROR) { eprintf ("Error creating socket."); return false; } #endif if ((s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP))<0) return false; #if __UNIX__ || defined(__CYGWIN__) linger.l_onoff = 1; linger.l_linger = 1; ret = setsockopt (s->fd, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof (linger)); if (ret < 0) return false; { // fix close after write bug // int x = 1500; // FORCE MTU ret = setsockopt (s->fd, SOL_SOCKET, SO_SNDBUF, (void*)&x, sizeof (int)); if (ret < 0) return false; } ret = setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof optval); if (ret < 0) return false; #endif memset (&s->sa, 0, sizeof (s->sa)); s->sa.sin_family = AF_INET; s->sa.sin_addr.s_addr = htonl (s->local? INADDR_LOOPBACK: INADDR_ANY); s->port = r_socket_port_by_name (port); if (s->port <1) return false; s->sa.sin_port = htons (s->port); // TODO honor etc/services if (bind (s->fd, (struct sockaddr *)&s->sa, sizeof(s->sa)) < 0) { r_sys_perror ("bind"); close (s->fd); return false; } #if __UNIX__ || defined(__CYGWIN__) signal (SIGPIPE, SIG_IGN); #endif if (listen (s->fd, 32) < 0) { close (s->fd); return false; } #if HAVE_LIB_SSL if (s->is_ssl) { s->ctx = SSL_CTX_new (SSLv23_method ()); if (s->ctx == NULL) { r_socket_free (s); return false; } if (!SSL_CTX_use_certificate_chain_file (s->ctx, certfile)) { r_socket_free (s); return false; } if (!SSL_CTX_use_PrivateKey_file (s->ctx, certfile, SSL_FILETYPE_PEM)) { r_socket_free (s); return false; } SSL_CTX_set_verify_depth (s->ctx, 1); } #endif return true; }
static int r_bin_mz_init_hdr(struct r_bin_mz_obj_t* bin) { int relocations_size, dos_file_size; if (!(bin->dos_header = R_NEW0 (MZ_image_dos_header))) { r_sys_perror ("malloc (MZ_image_dos_header)"); return false; } // TODO: read field by field to avoid endian and alignment issues if (r_buf_read_at (bin->b, 0, (ut8*)bin->dos_header, sizeof (*bin->dos_header)) == -1) { eprintf ("Error: read (MZ_image_dos_header)\n"); return false; } if (bin->dos_header->blocks_in_file < 1) { return false; } dos_file_size = ((bin->dos_header->blocks_in_file - 1) << 9) + \ bin->dos_header->bytes_in_last_block; bin->dos_file_size = dos_file_size; if (dos_file_size > bin->size) { return false; } relocations_size = bin->dos_header->num_relocs * sizeof (MZ_image_relocation_entry); if ((bin->dos_header->reloc_table_offset + relocations_size) > bin->size) { return false; } sdb_num_set (bin->kv, "mz.initial.cs", bin->dos_header->cs, 0); sdb_num_set (bin->kv, "mz.initial.ip", bin->dos_header->ip, 0); sdb_num_set (bin->kv, "mz.initial.ss", bin->dos_header->ss, 0); sdb_num_set (bin->kv, "mz.initial.sp", bin->dos_header->sp, 0); sdb_num_set (bin->kv, "mz.overlay_number", bin->dos_header->overlay_number, 0); sdb_num_set (bin->kv, "mz.dos_header.offset", 0, 0); sdb_set (bin->kv, "mz.dos_header.format", "[2]zwwwwwwwwwwwww" " signature bytes_in_last_block blocks_in_file num_relocs " " header_paragraphs min_extra_paragraphs max_extra_paragraphs " " ss sp checksum ip cs reloc_table_offset overlay_number ", 0); bin->dos_extended_header_size = bin->dos_header->reloc_table_offset - \ sizeof (MZ_image_dos_header); if (bin->dos_extended_header_size > 0) { if (!(bin->dos_extended_header = malloc (bin->dos_extended_header_size))) { r_sys_perror ("malloc (dos extended header)"); return false; } if (r_buf_read_at (bin->b, sizeof (MZ_image_dos_header), (ut8*)bin->dos_extended_header, bin->dos_extended_header_size) == -1) { eprintf ("Error: read (dos extended header)\n"); return false; } } if (relocations_size > 0) { if (!(bin->relocation_entries = malloc (relocations_size))) { r_sys_perror ("malloc (dos relocation entries)"); return false; } if (r_buf_read_at (bin->b, bin->dos_header->reloc_table_offset, (ut8*)bin->relocation_entries, relocations_size) == -1) { eprintf ("Error: read (dos relocation entries)\n"); R_FREE (bin->relocation_entries); return false; } } return true; }
// __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 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; }
static int cmd_meta_comment(RCore *core, const char *input) { ut64 addr = core->offset; switch (input[1]) { case '?': { const char* help_msg[] = { "Usage:", "CC[-+!*au] [base64:..|str] @ addr", "", "CC", "", "list all comments in human friendly form", "CC*", "", "list all comments in r2 commands", "CC.", "", "show comment at current offset", "CC,", " [file]", "show or set comment file", "CC", " or maybe not", "append comment at current address", "CC+", " same as above", "append comment at current address", "CC!", "", "edit comment using cfg.editor (vim, ..)", "CC-", " @ cmt_addr", "remove comment at given address", "CCu", " good boy @ addr", "add good boy comment at given address", "CCu", " base64:AA== @ addr", "add comment in base64", NULL}; r_core_cmd_help (core, help_msg); } break; case ',': // "CC," if (input[2]=='?') { eprintf ("Usage: CC, [file]\n"); } else if (input[2]==' ') { const char *fn = input+2; char *comment = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, addr); while (*fn== ' ')fn++; if (comment && *comment) { // append filename in current comment char *nc = r_str_newf ("%s ,(%s)", comment, fn); r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, nc); free (nc); } else { char *comment = r_str_newf (",(%s)", fn); r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, comment); free (comment); } } else { char *comment = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, addr); if (comment && *comment) { char *cmtfile = r_str_between (comment, ",(", ")"); if (cmtfile && *cmtfile) { char *getcommapath(RCore *core); char *cwd = getcommapath (core); r_cons_printf ("%s"R_SYS_DIR"%s\n", cwd, cmtfile); free (cwd); } free (cmtfile); } free (comment); } break; case '.': { char *comment = r_meta_get_string ( core->anal, R_META_TYPE_COMMENT, addr); if (comment) { r_cons_println (comment); free (comment); } } break; case 0: r_meta_list (core->anal, R_META_TYPE_COMMENT, 0); break; case 'j': r_meta_list (core->anal, R_META_TYPE_COMMENT, 'j'); break; case '!': { char *out, *comment = r_meta_get_string ( core->anal, R_META_TYPE_COMMENT, addr); out = r_core_editor (core, NULL, comment); if (out) { //r_meta_add (core->anal->meta, R_META_TYPE_COMMENT, addr, 0, out); r_core_cmdf (core, "CC-@0x%08"PFMT64x, addr); //r_meta_del (core->anal->meta, input[0], addr, addr+1, NULL); r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, out); free (out); } free (comment); } break; case '+': case ' ': { const char* newcomment = r_str_chop_ro (input + 2); char *text, *comment = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, addr); char *nc = strdup (newcomment); r_str_unescape (nc); if (comment) { text = malloc (strlen (comment)+strlen (newcomment)+2); if (text) { strcpy (text, comment); strcat (text, "\n"); strcat (text, nc); r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, text); free (text); } else { r_sys_perror ("malloc"); } } else { r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, nc); } free (nc); } break; case '*': r_meta_list (core->anal, R_META_TYPE_COMMENT, 1); break; case '-': // "CC-" r_meta_del (core->anal, R_META_TYPE_COMMENT, core->offset, 1, NULL); break; case 'u': // { char *newcomment; const char *arg = input + 2; while (*arg && *arg == ' ') arg++; if (!strncmp (arg, "base64:", 7)) { char *s = (char *)sdb_decode (arg+7, NULL); if (s) { newcomment = s; } else { newcomment = NULL; } } else { newcomment = strdup (arg); } if (newcomment) { char *comment = r_meta_get_string ( core->anal, R_META_TYPE_COMMENT, addr); if (!comment || (comment && !strstr (comment, newcomment))) { r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, newcomment); } free (comment); free (newcomment); } } break; case 'a': { char *s, *p; s = strchr (input, ' '); if (s) { s = strdup (s+1); } else { eprintf ("Usage\n"); return false; } p = strchr (s, ' '); if (p) *p++ = 0; ut64 addr; if (input[2]=='-') { if (input[3]) { addr = r_num_math (core->num, input+3); r_meta_del (core->anal, R_META_TYPE_COMMENT, addr, 1, NULL); } else eprintf ("Usage: CCa-[address]\n"); free (s); return true; } addr = r_num_math (core->num, s); // Comment at if (p) { if (input[2]=='+') { char *comment = r_meta_get_string ( core->anal, R_META_TYPE_COMMENT, addr); if (comment) { char* text = r_str_newf ("%s\n%s", comment, p); r_meta_add (core->anal, R_META_TYPE_COMMENT, addr, addr+1, text); free (text); } else { r_meta_add (core->anal, R_META_TYPE_COMMENT, addr, addr+1, p); } } else { r_meta_add (core->anal, R_META_TYPE_COMMENT, addr, addr+1, p); } } else eprintf ("Usage: CCa [address] [comment]\n"); free (s); return true; } } return true; }
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; }
static RList *r_debug_native_pids (int pid) { RList *list = r_list_new (); if (!list) return NULL; #if __WINDOWS__ && !__CYGWIN__ return w32_pids (pid, list); #elif __APPLE__ if (pid) { RDebugPid *p = xnu_get_pid (pid); if (p) r_list_append (list, p); } else { int i; for (i = 1; i < MAXPID; i++) { RDebugPid *p = xnu_get_pid (i); if (p) r_list_append (list, p); } } #else int i; char *ptr, buf[1024]; list->free = (RListFree)&r_debug_pid_free; if (pid) { DIR *dh; struct dirent *de; /* add the requested pid. should we do this? we don't even know if it's valid still.. */ r_list_append (list, r_debug_pid_new ("(current)", pid, 's', 0)); /* list parents */ dh = opendir ("/proc"); if (dh == NULL) { r_sys_perror ("opendir /proc"); r_list_free (list); return NULL; } while ((de = readdir (dh))) { /* for each existing pid file... */ i = atoi (de->d_name); if (i <= 0) { continue; } /* try to read the status */ buf[0] = 0; if (procfs_pid_slurp (i, "status", buf, sizeof (buf)) == -1) { continue; } buf[sizeof (buf) - 1] = 0; /* look for the parent process id */ ptr = strstr (buf, "PPid:"); if (ptr) { int ppid = atoi (ptr + 6); /* if this is the requested process... */ if (i == pid) { //eprintf ("PPid: %d\n", ppid); /* append it to the list with parent */ r_list_append (list, r_debug_pid_new ( "(ppid)", ppid, 's', 0)); } /* ignore it if it is not one of our children */ if (ppid != pid) { continue; } /* it's a child of the requested pid, read it's command line and add it */ if (procfs_pid_slurp (ppid, "cmdline", buf, sizeof(buf)) == -1) { continue; } r_list_append (list, r_debug_pid_new (buf, i, 's', 0)); } } closedir (dh); } else { /* try to bruteforce the processes * XXX(jjd): wouldn't listing the processes like before work better? */ for (i = 2; i < MAXPID; i++) { /* try to send signal 0, if it fails it must not be valid */ if (r_sandbox_kill (i, 0) == -1) continue; if (procfs_pid_slurp (i, "cmdline", buf, sizeof(buf)) == -1) continue; r_list_append (list, r_debug_pid_new (buf, i, 's', 0)); } } #endif return list; }
static int r_debug_native_wait (RDebug *dbg, int pid) { int status = -1; #if __WINDOWS__ && !__CYGWIN__ int mode = 0; status = w32_dbg_wait (dbg, pid); if (status == R_DEBUG_REASON_NEW_LIB) { mode = 'l'; } else if (status == R_DEBUG_REASON_EXIT_LIB) { mode = 'u'; } else { mode = 0; } if (mode) { RDebugInfo *r = r_debug_native_info (dbg, ""); if (r && r->lib) { if (tracelib (dbg, mode=='l'? "load":"unload", r->lib)) status=R_DEBUG_REASON_TRAP; } else { eprintf ("%soading unknown library.\n", mode?"L":"Unl"); } r_debug_info_free (r); } #else if (pid == -1) { status = R_DEBUG_REASON_UNKNOWN; } else { #if __APPLE__ // eprintf ("No waitpid here :D\n"); status = xnu_wait (dbg, pid); #else // XXX: this is blocking, ^C will be ignored int ret = waitpid (pid, &status, 0); if (ret == -1) { r_sys_perror ("waitpid"); status = R_DEBUG_REASON_ERROR; } else { //printf ("r_debug_native_wait: status=%d (return=%d)\n", status, ret); // TODO: switch status and handle reasons here #if __linux__ && defined(PT_GETEVENTMSG) // Handle PTRACE_EVENT_* if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP) { ut32 pt_evt = status >> 16; ut32 data; switch (pt_evt) { case 0: // Normal trap? break; case PTRACE_EVENT_FORK: if (dbg->trace_forks) { if (ptrace (PTRACE_GETEVENTMSG, pid, 0, &data) == -1) { r_sys_perror ("ptrace GETEVENTMSG"); } else { eprintf ("PTRACE_EVENT_FORK new_pid=%d\n", data); dbg->forked_pid = data; // TODO: more handling here? } } break; case PTRACE_EVENT_EXIT: if (ptrace (PTRACE_GETEVENTMSG, pid, 0, &data) == -1) { r_sys_perror ("ptrace GETEVENTMSG"); } else { eprintf ("PTRACE_EVENT_EXIT pid=%d, status=%d\n", pid, data); } break; default: eprintf ("Unknown PTRACE_EVENT encountered: %d\n", pt_evt); break; } } #endif r_debug_handle_signals (dbg); if (WIFSTOPPED (status)) { dbg->reason.signum = WSTOPSIG (status); status = R_DEBUG_REASON_SIGNAL; } else if (status == 0 || ret == -1) { status = R_DEBUG_REASON_DEAD; } else { if (ret != pid) status = R_DEBUG_REASON_NEW_PID; else status = R_DEBUG_REASON_UNKNOWN; } } #endif }
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); } } void handle_posix_error(int err) { switch (err) { case 0: // eprintf ("Success\n"); break; case 22: eprintf ("posix_spawnp: Invalid argument\n"); break; case 86: eprintf ("Unsupported architecture. Please specify -b 32\n"); break; default: eprintf ("posix_spawnp: unknown error %d\n", err); perror ("posix_spawnp"); break; } } static RRunProfile* _get_run_profile(RIO *io, int bits, char **argv) { char *expr = NULL; int i; RRunProfile *rp = r_run_new (NULL); if (!rp) { return NULL; } for (i = 0; argv[i]; i++) { rp->_args[i] = argv[i]; } rp->_args[i] = NULL; rp->_program = strdup (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); r_run_free (rp); return NULL; } if (strstr (io->runprofile, R_SYS_DIR ".rarun2.")) { (void)r_file_rm (io->runprofile); } } 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"); r_run_free (rp); return NULL; } return rp; }
R_API int r_run_config_env(RRunProfile *p) { int ret; if (!p->_program && !p->_system) { printf ("No program or system rule defined\n"); return 1; } // when IO is redirected to a process, handle them together if (handle_redirection (p->_stdio, true, true, false) != 0) { return 1; } if (handle_redirection (p->_stdin, true, false, false) != 0) { return 1; } if (handle_redirection (p->_stdout, false, true, false) != 0) { return 1; } if (handle_redirection (p->_stderr, false, false, true) != 0) { return 1; } if (p->_aslr != -1) setASLR (p->_aslr); #if __UNIX__ set_limit (p->_docore, RLIMIT_CORE, RLIM_INFINITY); if (p->_maxfd) set_limit (p->_maxfd, RLIMIT_NOFILE, p->_maxfd); #ifdef RLIMIT_NPROC if (p->_maxproc) set_limit (p->_maxproc, RLIMIT_NPROC, p->_maxproc); #endif if (p->_maxstack) set_limit (p->_maxstack, RLIMIT_STACK, p->_maxstack); #else if (p->_docore || p->_maxfd || p->_maxproc || p->_maxstack) eprintf ("Warning: setrlimits not supported for this platform\n"); #endif if (p->_connect) { char *q = strchr (p->_connect, ':'); if (q) { RSocket *fd = r_socket_new (0); *q = 0; if (!r_socket_connect_tcp (fd, p->_connect, q+1, 30)) { eprintf ("Cannot connect\n"); return 1; } eprintf ("connected\n"); close (0); close (1); close (2); dup2 (fd->fd, 0); dup2 (fd->fd, 1); dup2 (fd->fd, 2); } else { eprintf ("Invalid format for connect. missing ':'\n"); return 1; } } if (p->_listen) { RSocket *child, *fd = r_socket_new (0); bool is_child = false; if (!r_socket_listen (fd, p->_listen, NULL)) { eprintf ("rarun2: cannot listen\n"); r_socket_free (fd); return 1; } while (true) { child = r_socket_accept (fd); if (child) { is_child = true; if (p->_dofork && !p->_dodebug) { pid_t child_pid = r_sys_fork (); if (child_pid == -1) { eprintf("rarun2: cannot fork\n"); r_socket_free (child); r_socket_free (fd); return 1; } else if (child_pid != 0){ // parent code is_child = false; } } if (is_child) { r_socket_close_fd (fd); eprintf ("connected\n"); close (0); close (1); close (2); dup2 (child->fd, 0); dup2 (child->fd, 1); dup2 (child->fd, 2); break; } else { r_socket_close_fd (child); } } } if(!is_child) r_socket_free (child); r_socket_free (fd); } if (p->_r2sleep != 0) { r_sys_sleep (p->_r2sleep); } #if __UNIX__ if (p->_chroot) { if (chdir (p->_chroot) == -1) { eprintf ("Cannot chdir to chroot in %s\n", p->_chroot); return 1; } else { if (chroot (".") == -1) { eprintf ("Cannot chroot to %s\n", p->_chroot); return 1; } else { if (p->_chgdir) { if (chdir (p->_chgdir) == -1) { eprintf ("Cannot chdir after chroot to %s\n", p->_chgdir); return 1; } } } } } else if (p->_chgdir) { if (chdir (p->_chgdir) == -1) { eprintf ("Cannot chdir after chroot to %s\n", p->_chgdir); return 1; } } #endif if (p->_chgdir) { ret = chdir (p->_chgdir); if (ret < 0) { return 1; } } if (p->_chroot) { ret = chdir (p->_chroot); if (ret < 0) { return 1; } } #if __UNIX__ if (p->_chroot) { if (chroot (p->_chroot) == 0) { chdir ("/"); } else { eprintf ("rarun2: cannot chroot\n"); r_sys_perror ("chroot"); return 1; } } if (p->_setuid) { ret = setgroups (0, NULL); if (ret < 0) return 1; ret = setuid (atoi (p->_setuid)); if (ret < 0) return 1; } if (p->_seteuid) { ret = seteuid (atoi (p->_seteuid)); if (ret < 0) return 1; } if (p->_setgid) { ret = setgid (atoi (p->_setgid)); if (ret < 0) return 1; } if (p->_input) { char *inp; int f2[2]; pipe (f2); close (0); dup2 (f2[0], 0); inp = getstr (p->_input); if (inp) { write (f2[1], inp, strlen (inp)); close (f2[1]); free (inp); } else { eprintf ("Invalid input\n"); } } #endif if (p->_r2preload) { if (p->_preload) { eprintf ("WARNING: Only one library can be opened at a time\n"); } p->_preload = R2_LIBDIR"/libr2."R_LIB_EXT; } if (p->_libpath) { #if __WINDOWS__ eprintf ("rarun2: libpath unsupported for this platform\n"); #elif __HAIKU__ r_sys_setenv ("LIBRARY_PATH", p->_libpath); #elif __APPLE__ r_sys_setenv ("DYLD_LIBRARY_PATH", p->_libpath); #else r_sys_setenv ("LD_LIBRARY_PATH", p->_libpath); #endif } if (p->_preload) { #if __APPLE__ // 10.6 r_sys_setenv ("DYLD_PRELOAD", p->_preload); r_sys_setenv ("DYLD_INSERT_LIBRARIES", p->_preload); // 10.8 r_sys_setenv ("DYLD_FORCE_FLAT_NAMESPACE", "1"); #else r_sys_setenv ("LD_PRELOAD", p->_preload); #endif } if (p->_timeout) { #if __UNIX__ int mypid = getpid (); if (!r_sys_fork ()) { int use_signal = p->_timeout_sig; if (use_signal < 1) { use_signal = SIGKILL; } sleep (p->_timeout); if (!kill (mypid, 0)) { eprintf ("\nrarun2: Interrupted by timeout\n"); } kill (mypid, use_signal); exit (0); } #else eprintf ("timeout not supported for this platform\n"); #endif } return 0; }
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(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 (); /* TODO: with args */ if (!CreateProcess (cmd, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi)) { r_sys_perror ("CreateProcess"); return -1; } /* 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; }
static int r_bin_mz_init_hdr(struct r_bin_mz_obj_t* bin) { int relocations_size, dos_file_size; if (!(bin->dos_header = malloc (sizeof(MZ_image_dos_header)))) { r_sys_perror ("malloc (MZ_image_dos_header)"); return R_FALSE; } if (r_buf_read_at (bin->b, 0, (ut8*)bin->dos_header, sizeof(*bin->dos_header)) == -1) { eprintf ("Error: read (MZ_image_dos_header)\n"); return R_FALSE; } if (bin->dos_header->blocks_in_file < 1) return R_FALSE; dos_file_size = ((bin->dos_header->blocks_in_file - 1) << 9) + \ bin->dos_header->bytes_in_last_block; bin->dos_file_size = dos_file_size; if (dos_file_size > bin->size) return R_FALSE; relocations_size = bin->dos_header->num_relocs * \ sizeof(MZ_image_relocation_entry); /* Check if relocation table doesn't exceed dos binary size */ if ((bin->dos_header->reloc_table_offset + relocations_size) > \ dos_file_size) return R_FALSE; sdb_num_set (bin->kv, "mz.initial.cs", bin->dos_header->cs, 0); sdb_num_set (bin->kv, "mz.initial.ip", bin->dos_header->ip, 0); sdb_num_set (bin->kv, "mz.initial.ss", bin->dos_header->ss, 0); sdb_num_set (bin->kv, "mz.initial.sp", bin->dos_header->sp, 0); sdb_num_set (bin->kv, "mz.overlay_number", bin->dos_header->overlay_number, 0); sdb_num_set (bin->kv, "mz.dos_header.offset", 0, 0); sdb_set (bin->kv, "mz.dos_header.format", "[2]zwwwwwwwwwwwww" " signature bytes_in_last_block blocks_in_file num_relocs " " header_paragraphs min_extra_paragraphs max_extra_paragraphs " " ss sp checksum ip cs reloc_table_offset overlay_number ", 0); bin->dos_extended_header_size = bin->dos_header->reloc_table_offset - \ sizeof(MZ_image_dos_header); if (bin->dos_extended_header_size > 0) { if (!(bin->dos_extended_header = \ malloc (bin->dos_extended_header_size))) { r_sys_perror ("malloc (dos extended header)"); return R_FALSE; } if (r_buf_read_at (bin->b, sizeof(MZ_image_dos_header), (ut8*)bin->dos_extended_header, bin->dos_extended_header_size) == -1) { eprintf ("Error: read (dos extended header)\n"); return R_FALSE; } } if (relocations_size > 0) { if (!(bin->relocation_entries = malloc (relocations_size))) { r_sys_perror ("malloc (dos relocation entries)"); return R_FALSE; } if (r_buf_read_at (bin->b, bin->dos_header->reloc_table_offset, (ut8*)bin->relocation_entries, relocations_size) == -1) { eprintf ("Error: read (dos relocation entries)\n"); return R_FALSE; } } return R_TRUE; }