// // xpc_crash.c // Pocket Poster // // Ported from Cowabunga / TrollTools helpers.m // (xpc w00t technique: https://googleprojectzero.blogspot.com/2019/04/splitting-atoms-in-xnu.html) // #include "xpc_crash.h" #include #include #include // bootstrap_look_up is in libsystem_kernel / libxpc but not always in public headers extern kern_return_t bootstrap_look_up(mach_port_t bp, const char *service_name, mach_port_t *sp); extern mach_port_t bootstrap_port; struct xpc_w00t { mach_msg_header_t hdr; mach_msg_body_t body; mach_msg_port_descriptor_t client_port; mach_msg_port_descriptor_t reply_port; }; static mach_port_t get_send_once(mach_port_t recv) { mach_port_t so = MACH_PORT_NULL; mach_msg_type_name_t type = 0; kern_return_t err = mach_port_extract_right(mach_task_self(), recv, MACH_MSG_TYPE_MAKE_SEND_ONCE, &so, &type); if (err != KERN_SUCCESS) { return MACH_PORT_NULL; } return so; } void xpc_crasher(char *service_name) { mach_port_t client_port = MACH_PORT_NULL; mach_port_t reply_port = MACH_PORT_NULL; mach_port_t service_port = MACH_PORT_NULL; kern_return_t err = bootstrap_look_up(bootstrap_port, service_name, &service_port); if (err != KERN_SUCCESS) { printf("xpc_crasher: unable to look up %s\n", service_name); return; } if (service_port == MACH_PORT_NULL) { printf("xpc_crasher: bad service port for %s\n", service_name); return; } err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &client_port); if (err != KERN_SUCCESS) { return; } mach_port_t so0 = get_send_once(client_port); mach_port_t so1 = get_send_once(client_port); err = mach_port_insert_right(mach_task_self(), client_port, client_port, MACH_MSG_TYPE_MAKE_SEND); if (err != KERN_SUCCESS) { return; } err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &reply_port); if (err != KERN_SUCCESS) { return; } struct xpc_w00t msg; memset(&msg.hdr, 0, sizeof(msg)); msg.hdr.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, 0, 0, MACH_MSGH_BITS_COMPLEX); msg.hdr.msgh_size = sizeof(msg); msg.hdr.msgh_remote_port = service_port; msg.hdr.msgh_id = 'w00t'; msg.body.msgh_descriptor_count = 2; msg.client_port.name = client_port; msg.client_port.disposition = MACH_MSG_TYPE_MOVE_RECEIVE; msg.client_port.type = MACH_MSG_PORT_DESCRIPTOR; msg.reply_port.name = reply_port; msg.reply_port.disposition = MACH_MSG_TYPE_MAKE_SEND; msg.reply_port.type = MACH_MSG_PORT_DESCRIPTOR; err = mach_msg(&msg.hdr, MACH_SEND_MSG | MACH_MSG_OPTION_NONE, msg.hdr.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (err != KERN_SUCCESS) { printf("xpc_crasher: w00t send failed for %s: %s\n", service_name, mach_error_string(err)); } else { printf("xpc_crasher: sent w00t to %s\n", service_name); } if (so0 != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), so0); if (so1 != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), so1); } void restartBackboard(void) { xpc_crasher("com.apple.backboard.TouchDeliveryPolicyServer"); } void restartFrontboard(void) { // May not kill the calling app on some versions — caller should exit(0) after. xpc_crasher("com.apple.frontboard.systemappservices"); }