gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/native/proc_darwin.c (about) 1 //+build darwin,macnative 2 3 #include "proc_darwin.h" 4 5 static const unsigned char info_plist[] 6 __attribute__ ((section ("__TEXT,__info_plist"),used)) = 7 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 8 "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\"" 9 " \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 10 "<plist version=\"1.0\">\n" 11 "<dict>\n" 12 " <key>CFBundleIdentifier</key>\n" 13 " <string>org.dlv</string>\n" 14 " <key>CFBundleName</key>\n" 15 " <string>delve</string>\n" 16 " <key>CFBundleVersion</key>\n" 17 " <string>1.0</string>\n" 18 " <key>SecTaskAccess</key>\n" 19 " <array>\n" 20 " <string>allowed</string>\n" 21 " <string>debug</string>\n" 22 " </array>\n" 23 "</dict>\n" 24 "</plist>\n"; 25 26 kern_return_t 27 acquire_mach_task(int tid, 28 task_t *task, 29 mach_port_t *port_set, 30 mach_port_t *exception_port, 31 mach_port_t *notification_port) 32 { 33 kern_return_t kret; 34 mach_port_t prev_not; 35 mach_port_t self = mach_task_self(); 36 37 kret = task_for_pid(self, tid, task); 38 if (kret != KERN_SUCCESS) return kret; 39 40 // Allocate exception port. 41 kret = mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, exception_port); 42 if (kret != KERN_SUCCESS) return kret; 43 44 kret = mach_port_insert_right(self, *exception_port, *exception_port, MACH_MSG_TYPE_MAKE_SEND); 45 if (kret != KERN_SUCCESS) return kret; 46 47 kret = task_set_exception_ports(*task, EXC_MASK_BREAKPOINT|EXC_MASK_SOFTWARE, *exception_port, 48 EXCEPTION_DEFAULT, THREAD_STATE_NONE); 49 if (kret != KERN_SUCCESS) return kret; 50 51 // Allocate notification port to alert of when the process dies. 52 kret = mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, notification_port); 53 if (kret != KERN_SUCCESS) return kret; 54 55 kret = mach_port_insert_right(self, *notification_port, *notification_port, MACH_MSG_TYPE_MAKE_SEND); 56 if (kret != KERN_SUCCESS) return kret; 57 58 kret = mach_port_request_notification(self, *task, MACH_NOTIFY_DEAD_NAME, 0, *notification_port, 59 MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev_not); 60 if (kret != KERN_SUCCESS) return kret; 61 62 // Create port set. 63 kret = mach_port_allocate(self, MACH_PORT_RIGHT_PORT_SET, port_set); 64 if (kret != KERN_SUCCESS) return kret; 65 66 // Move exception and notification ports to port set. 67 kret = mach_port_move_member(self, *exception_port, *port_set); 68 if (kret != KERN_SUCCESS) return kret; 69 70 return mach_port_move_member(self, *notification_port, *port_set); 71 } 72 73 kern_return_t 74 reset_exception_ports(task_t task, mach_port_t *exception_port, mach_port_t *notification_port) { 75 kern_return_t kret; 76 mach_port_t prev_not; 77 mach_port_t self = mach_task_self(); 78 79 kret = task_set_exception_ports(task, EXC_MASK_BREAKPOINT|EXC_MASK_SOFTWARE, *exception_port, 80 EXCEPTION_DEFAULT, THREAD_STATE_NONE); 81 if (kret != KERN_SUCCESS) return kret; 82 83 kret = mach_port_request_notification(self, task, MACH_NOTIFY_DEAD_NAME, 0, *notification_port, 84 MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev_not); 85 if (kret != KERN_SUCCESS) return kret; 86 87 return KERN_SUCCESS; 88 } 89 90 char * 91 find_executable(int pid) { 92 static char pathbuf[PATH_MAX]; 93 proc_pidpath(pid, pathbuf, PATH_MAX); 94 return pathbuf; 95 } 96 97 kern_return_t 98 get_threads(task_t task, void *slice, int limit) { 99 kern_return_t kret; 100 thread_act_array_t list; 101 mach_msg_type_number_t count; 102 103 kret = task_threads(task, &list, &count); 104 if (kret != KERN_SUCCESS) { 105 return kret; 106 } 107 108 if (count > limit) { 109 vm_deallocate(mach_task_self(), (vm_address_t) list, count * sizeof(list[0])); 110 return -2; 111 } 112 113 memcpy(slice, (void*)list, count*sizeof(list[0])); 114 115 kret = vm_deallocate(mach_task_self(), (vm_address_t) list, count * sizeof(list[0])); 116 if (kret != KERN_SUCCESS) return kret; 117 118 return (kern_return_t)0; 119 } 120 121 int 122 thread_count(task_t task) { 123 kern_return_t kret; 124 thread_act_array_t list; 125 mach_msg_type_number_t count; 126 127 kret = task_threads(task, &list, &count); 128 if (kret != KERN_SUCCESS) return -1; 129 130 kret = vm_deallocate(mach_task_self(), (vm_address_t) list, count * sizeof(list[0])); 131 if (kret != KERN_SUCCESS) return -1; 132 133 return count; 134 } 135 136 mach_port_t 137 mach_port_wait(mach_port_t port_set, task_t *task, int nonblocking) { 138 kern_return_t kret; 139 thread_act_t thread; 140 NDR_record_t *ndr; 141 integer_t *data; 142 union 143 { 144 mach_msg_header_t hdr; 145 char data[256]; 146 } msg; 147 mach_msg_option_t opts = MACH_RCV_MSG|MACH_RCV_INTERRUPT; 148 if (nonblocking) { 149 opts |= MACH_RCV_TIMEOUT; 150 } 151 152 // Wait for mach msg. 153 kret = mach_msg(&msg.hdr, opts, 154 0, sizeof(msg.data), port_set, 10, MACH_PORT_NULL); 155 if (kret == MACH_RCV_INTERRUPTED) return kret; 156 if (kret != MACH_MSG_SUCCESS) return 0; 157 158 159 switch (msg.hdr.msgh_id) { 160 case 2401: { // Exception 161 // 2401 is the exception_raise event, defined in: 162 // http://opensource.apple.com/source/xnu/xnu-2422.1.72/osfmk/mach/exc.defs?txt 163 // compile this file with mig to get the C version of the description 164 165 mach_msg_body_t *bod = (mach_msg_body_t*)(&msg.hdr + 1); 166 mach_msg_port_descriptor_t *desc = (mach_msg_port_descriptor_t *)(bod + 1); 167 thread = desc[0].name; 168 *task = desc[1].name; 169 ndr = (NDR_record_t *)(desc + 2); 170 data = (integer_t *)(ndr + 1); 171 172 if (thread_suspend(thread) != KERN_SUCCESS) return 0; 173 // Send our reply back so the kernel knows this exception has been handled. 174 kret = mach_send_reply(msg.hdr); 175 if (kret != MACH_MSG_SUCCESS) return 0; 176 if (data[2] == EXC_SOFT_SIGNAL) { 177 if (data[3] != SIGTRAP) { 178 if (thread_resume(thread) != KERN_SUCCESS) return 0; 179 return mach_port_wait(port_set, task, nonblocking); 180 } 181 } 182 return thread; 183 } 184 185 case 72: { // Death 186 // 72 is mach_notify_dead_name, defined in: 187 // https://opensource.apple.com/source/xnu/xnu-1228.7.58/osfmk/mach/notify.defs?txt 188 // compile this file with mig to get the C version of the description 189 ndr = (NDR_record_t *)(&msg.hdr + 1); 190 *task = *((mach_port_name_t *)(ndr + 1)); 191 return msg.hdr.msgh_local_port; 192 } 193 } 194 return 0; 195 } 196 197 kern_return_t 198 mach_send_reply(mach_msg_header_t hdr) { 199 mig_reply_error_t reply; 200 mach_msg_header_t *rh = &reply.Head; 201 rh->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(hdr.msgh_bits), 0); 202 rh->msgh_remote_port = hdr.msgh_remote_port; 203 rh->msgh_size = (mach_msg_size_t) sizeof(mig_reply_error_t); 204 rh->msgh_local_port = MACH_PORT_NULL; 205 rh->msgh_id = hdr.msgh_id + 100; 206 207 reply.NDR = NDR_record; 208 reply.RetCode = KERN_SUCCESS; 209 210 return mach_msg(&reply.Head, MACH_SEND_MSG|MACH_SEND_INTERRUPT, rh->msgh_size, 0, 211 MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 212 } 213 214 kern_return_t 215 raise_exception(mach_port_t task, mach_port_t thread, mach_port_t exception_port, exception_type_t exception) { 216 return exception_raise(exception_port, thread, task, exception, 0, 0); 217 } 218 219 task_t 220 get_task_for_pid(int pid) { 221 task_t task = 0; 222 mach_port_t self = mach_task_self(); 223 224 task_for_pid(self, pid, &task); 225 return task; 226 } 227 228 int 229 task_is_valid(task_t task) { 230 struct task_basic_info info; 231 mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; 232 return task_info(task, TASK_BASIC_INFO, (task_info_t)&info, &count) == KERN_SUCCESS; 233 }