RList *xnu_thread_list (RDebug *dbg, int pid, RList *list) { #if __arm__ #define OSX_PC state.__pc #elif __arm64__ #define OSX_PC state.__pc #elif __POWERPC__ #define OSX_PC state.srr0 #elif __x86_64__ #define OSX_PC state.__rip #undef OSX_PC #define OSX_PC state.x64[REG_PC] #else #define OSX_PC state.__eip #undef OSX_PC #define OSX_PC state.x32[REG_PC] #endif int i, tid; //, err; //unsigned int gp_count; static thread_array_t inferior_threads = NULL; static unsigned int inferior_thread_count = 0; R_DEBUG_REG_T state; if (task_threads (pid_to_task (pid), &inferior_threads, &inferior_thread_count) != KERN_SUCCESS) { eprintf ("Failed to get list of task's threads.\n"); return list; } for (i = 0; i < inferior_thread_count; i++) { tid = inferior_threads[i]; /* XXX overflow here gp_count = R_DEBUG_STATE_SZ; //sizeof (R_DEBUG_REG_T); if ((err = thread_get_state (tid, R_DEBUG_STATE_T, (thread_state_t) &state, &gp_count)) != KERN_SUCCESS) { // eprintf ("debug_list_threads: %s\n", MACH_ERROR_STRING(err)); OSX_PC = 0; } */ r_list_append (list, r_debug_pid_new ("???", tid, 's', OSX_PC)); } return list; }
static RList *r_debug_native_pids (int pid) { RList *list = r_list_new (); #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, fd; char *ptr, cmdline[1024]; list->free = (RListFree)&r_debug_pid_free; /* TODO */ if (pid) { r_list_append (list, r_debug_pid_new ("(current)", pid, 's', 0)); /* list parents */ DIR *dh; struct dirent *de; dh = opendir ("/proc"); if (dh == NULL) { r_list_free (list); return NULL; } //for (i=2; i<39999; i++) { while ((de = readdir (dh))) { i = atoi (de->d_name); if (!i) continue; snprintf (cmdline, sizeof (cmdline), "/proc/%d/status", i); fd = open (cmdline, O_RDONLY); if (fd == -1) continue; if (read (fd, cmdline, sizeof(cmdline)) == -1) { close (fd); continue; } cmdline[sizeof(cmdline) - 1] = '\0'; ptr = strstr (cmdline, "PPid:"); if (ptr) { int ret, ppid = atoi (ptr + 6); close (fd); if (i == pid) { //eprintf ("PPid: %d\n", ppid); r_list_append (list, r_debug_pid_new ( "(ppid)", ppid, 's', 0)); } if (ppid != pid) continue; snprintf (cmdline, sizeof(cmdline) - 1, "/proc/%d/cmdline", ppid); fd = open (cmdline, O_RDONLY); if (fd == -1) continue; ret = read (fd, cmdline, sizeof(cmdline)); if (ret > 0) { cmdline[ret - 1] = '\0'; r_list_append (list, r_debug_pid_new ( cmdline, i, 's', 0)); } } close (fd); } closedir (dh); } else for (i = 2; i < MAXPID; i++) { if (!r_sandbox_kill (i, 0)) { int ret; // TODO: Use slurp! snprintf (cmdline, sizeof(cmdline), "/proc/%d/cmdline", i); fd = open (cmdline, O_RDONLY); if (fd == -1) continue; cmdline[0] = '\0'; ret = read (fd, cmdline, sizeof(cmdline)); if (ret > 0) { cmdline[ret - 1] = '\0'; r_list_append (list, r_debug_pid_new ( cmdline, i, 's', 0)); } close (fd); } } #endif return list; }
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; }
RDebugPid *xnu_get_pid (int pid) { int psnamelen, foo, nargs, mib[3]; size_t size, argmax = 2048; char *curr_arg, *start_args, *iter_args, *end_args; char *procargs = NULL; char psname[4096]; #if 0 /* Get the maximum process arguments size. */ mib[0] = CTL_KERN; mib[1] = KERN_ARGMAX; size = sizeof(argmax); if (sysctl (mib, 2, &argmax, &size, NULL, 0) == -1) { eprintf ("sysctl() error on getting argmax\n"); return NULL; } #endif /* Allocate space for the arguments. */ procargs = (char *)malloc (argmax); if (procargs == NULL) { eprintf ("getcmdargs(): insufficient memory for procargs %d\n", (int)(size_t)argmax); return NULL; } /* * Make a sysctl() call to get the raw argument space of the process. */ mib[0] = CTL_KERN; mib[1] = KERN_PROCARGS2; mib[2] = pid; size = argmax; procargs[0] = 0; if (sysctl (mib, 3, procargs, &size, NULL, 0) == -1) { if (EINVAL == errno) { // invalid == access denied for some reason //eprintf("EINVAL returned fetching argument space\n"); free (procargs); return NULL; } eprintf ("sysctl(): unspecified sysctl error - %i\n", errno); free (procargs); return NULL; } // copy the number of argument to nargs memcpy (&nargs, procargs, sizeof(nargs)); iter_args = procargs + sizeof(nargs); end_args = &procargs[size-30]; // end of the argument space if (iter_args >= end_args) { eprintf ("getcmdargs(): argument length mismatch"); free (procargs); return NULL; } //TODO: save the environment variables to envlist as well // Skip over the exec_path and '\0' characters. // XXX: fix parsing #if 0 while (iter_args < end_args && *iter_args != '\0') { iter_args++; } while (iter_args < end_args && *iter_args == '\0') { iter_args++; } #endif if (iter_args == end_args) { free (procargs); return NULL; } /* Iterate through the '\0'-terminated strings and add each string * to the Python List arglist as a Python string. * Stop when nargs strings have been extracted. That should be all * the arguments. The rest of the strings will be environment * strings for the command. */ curr_arg = iter_args; start_args = iter_args; //reset start position to beginning of cmdline foo = 1; *psname = 0; psnamelen = 0; while (iter_args < end_args && nargs > 0) { if (*iter_args++ == '\0') { int alen = strlen (curr_arg); if (foo) { memcpy (psname, curr_arg, alen+1); foo = 0; } else { psname[psnamelen] = ' '; memcpy (psname+psnamelen+1, curr_arg, alen+1); } psnamelen += alen; //printf("arg[%i]: %s\n", iter_args, curr_arg); /* Fetch next argument */ curr_arg = iter_args; nargs--; } } #if 1 /* * curr_arg position should be further than the start of the argspace * and number of arguments should be 0 after iterating above. Otherwise * we had an empty argument space or a missing terminating \0 etc. */ if (curr_arg == start_args || nargs > 0) { psname[0] = 0; // eprintf ("getcmdargs(): argument parsing failed"); free (procargs); return NULL; } #endif return r_debug_pid_new (psname, pid, 's', 0); // XXX 's' ??, 0?? must set correct values }
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; }