diff --git a/src/m8/run.c b/src/m8/run.c index 7475480..b8a4d09 100644 --- a/src/m8/run.c +++ b/src/m8/run.c @@ -9,19 +9,27 @@ #include "../utils.h" #include "../usb/shim.h" -#include "../pongo/pongo_helper.h" +#include "../usb/pongo_helper.h" #include "checkm8.h" #include "dfu.h" #include "payload.h" +#include "../gen/payloads/checkra1n-kpf-pongo.h" +#include "../gen/payloads/ramdisk.h" +#include "../gen/payloads/binpack.h" + typedef struct { - atomic_bool stop; atomic_int result; + atomic_bool stop; + + atomic_bool exploit_done; + atomic_bool pongo_done; } shared_t; static void *exploit_thread(void *arg) { + LOG("Waiting for DFU devices..."); shared_t *s = (shared_t *)arg; usb_handle_t handle; @@ -45,14 +53,14 @@ static void *exploit_thread(void *arg) char *sn = get_usb_serial_number(&handle); if (!sn) goto fail; - if (!checkm8_find_device_configuration_for_cpid( - dfu_serial_number_get_cpid(sn), &deviceConfig)) { + uint64_t cpid = dfu_serial_number_get_cpid(sn); + + if (!checkm8_find_device_configuration_for_cpid(cpid, &deviceConfig)) { free(sn); goto fail; } - if (!checkm8_find_payload_configuration_for_cpid( - dfu_serial_number_get_cpid(sn), &payloadConfig)) { + if (!checkm8_find_payload_configuration_for_cpid(cpid, &payloadConfig)) { free(sn); goto fail; } @@ -66,10 +74,12 @@ static void *exploit_thread(void *arg) stage = STAGE_RESET; break; } + case STAGE_RESET: ret = checkm8_stage_reset(&handle); stage = ret ? STAGE_SETUP : STAGE_RESET; break; + case STAGE_SETUP: LOG("Setting up the device for exploitation"); ret = checkm8_stage_setup(&handle, &deviceConfig); @@ -81,19 +91,23 @@ static void *exploit_thread(void *arg) stage = ret ? STAGE_PATCH : STAGE_RESET; break; case STAGE_PATCH: - LOG("Right before trigger (this is the real bug setup)"); + LOG("Right before trigger (bug setup)"); ret = checkm8_stage_patch(&handle, &deviceConfig, &payloadConfig); if (!ret) goto fail; stage = STAGE_PONGO; break; case STAGE_PONGO: LOG("Booting pongoOS"); + close_usb_handle(&handle); sleep_ms(3000); + checkm8_boot_pongo(&handle); - stage = STAGE_DONE; + atomic_store(&s->result, 1); - atomic_store(&s->stop, true); + atomic_store(&s->exploit_done, true); + + stage = STAGE_DONE; break; default: goto fail; @@ -101,18 +115,19 @@ static void *exploit_thread(void *arg) reset_usb_handle(&handle); continue; - - fail: - atomic_store(&s->result, -1); - atomic_store(&s->stop, true); - break; } return NULL; + +fail: + atomic_store(&s->result, -1); + atomic_store(&s->stop, true); + return NULL; } static void *pongo_thread(void *arg) { + LOG("Waiting for Pongo devices..."); shared_t *s = (shared_t *)arg; usb_handle_t handle; @@ -129,31 +144,39 @@ static void *pongo_thread(void *arg) if (!seen) { LOG("Pongo device detected!"); - seen = true; + char paleinfo[64]; snprintf(paleinfo, sizeof(paleinfo), "palera1n_flags 0x%" PRIx64, palerain_flags); - issue_pongo_command(&handle, "fuse lock", NULL); - issue_pongo_command(&handle, "sep auto", NULL); - // issue_pongo_command(&handle, paleinfo, NULL); - // issue_pongo_command(&handle, "bootx", NULL); + issue_pongo_command(&handle, "fuse lock"); + issue_pongo_command(&handle, "sep auto"); + upload_buffer_to_pongo(&handle, payloads_checkra1n_kpf_pongo, payloads_checkra1n_kpf_pongo_len); + issue_pongo_command(&handle, "modload"); + issue_pongo_command(&handle, paleinfo); + upload_buffer_to_pongo(&handle, payloads_ramdisk_dmg, payloads_ramdisk_dmg_len); + issue_pongo_command(&handle, "ramdisk"); + upload_buffer_to_pongo(&handle, payloads_binpack_dmg, payloads_binpack_dmg_len); + issue_pongo_command(&handle, "overlay"); + issue_pongo_command(&handle, "bootx"); atomic_store(&s->result, 1); - atomic_store(&s->stop, true); break; } - - reset_usb_handle(&handle); } close_usb_handle(&handle); return NULL; } -bool exploit(void) { +bool exploit(void) +{ pthread_t t1, t2; - shared_t state; + shared_t state = {0}; + atomic_init(&state.result, 0); + atomic_init(&state.stop, false); + atomic_init(&state.exploit_done, false); + atomic_init(&state.pongo_done, false); pthread_create(&t1, NULL, exploit_thread, &state); pthread_create(&t2, NULL, pongo_thread, &state); @@ -161,5 +184,7 @@ bool exploit(void) { pthread_join(t1, NULL); pthread_join(t2, NULL); - return atomic_load(&state.result) == 1; + return atomic_load(&state.result) == 1 && + atomic_load(&state.exploit_done) && + atomic_load(&state.pongo_done); } diff --git a/src/usb/iokit/usb_iokit.c b/src/usb/iokit/usb_iokit.c index eceb563..400c8e7 100644 --- a/src/usb/iokit/usb_iokit.c +++ b/src/usb/iokit/usb_iokit.c @@ -22,22 +22,83 @@ static void cf_dictionary_set_int16(CFMutableDictionaryRef dict, const void *key bool query_usb_interface(io_service_t serv, CFUUIDRef plugin_type, CFUUIDRef interface_type, LPVOID *interface) { IOCFPlugInInterface **plugin_interface; - bool ret = false; SInt32 score; + bool ret = false; if(IOCreatePlugInInterfaceForService(serv, plugin_type, kIOCFPlugInInterfaceID, &plugin_interface, &score) == kIOReturnSuccess) { ret = (*plugin_interface)->QueryInterface(plugin_interface, CFUUIDGetUUIDBytes(interface_type), interface) == kIOReturnSuccess; IODestroyPlugInInterface(plugin_interface); } + IOObjectRelease(serv); return ret; } +static bool open_usb_interface(usb_handle_t *handle) { + IOUSBFindInterfaceRequest req; + io_iterator_t iter; + io_service_t intfServ; + IOReturn kr; + + req.bInterfaceClass = kIOUSBFindInterfaceDontCare; + req.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; + req.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; + req.bAlternateSetting = kIOUSBFindInterfaceDontCare; + + kr = (*handle->device)->CreateInterfaceIterator(handle->device, &req, &iter); + if(kr != kIOReturnSuccess) return false; + + while((intfServ = IOIteratorNext(iter)) != IO_OBJECT_NULL) { + IOCFPlugInInterface **plugin = NULL; + IOUSBInterfaceInterface245 **intf = NULL; + SInt32 score = 0; + HRESULT res; + + kr = IOCreatePlugInInterfaceForService(intfServ, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score); + + IOObjectRelease(intfServ); + + if(kr != kIOReturnSuccess || !plugin) continue; + + res = (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID245), (LPVOID *)&intf); + + (*plugin)->Release(plugin); + + if(res != S_OK || !intf) continue; + + kr = (*intf)->USBInterfaceOpen(intf); + if(kr != kIOReturnSuccess) { + (*intf)->Release(intf); + continue; + } + + handle->interface = intf; + IOObjectRelease(iter); + return true; + } + + IOObjectRelease(iter); + return false; +} + void close_usb_device(usb_handle_t *handle) { - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), handle->async_event_source, kCFRunLoopDefaultMode); - CFRelease(handle->async_event_source); - (*handle->device)->USBDeviceClose(handle->device); - (*handle->device)->Release(handle->device); + if(handle->async_event_source) { + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), handle->async_event_source, kCFRunLoopDefaultMode); + CFRelease(handle->async_event_source); + handle->async_event_source = NULL; + } + + if(handle->interface) { + (*handle->interface)->USBInterfaceClose(handle->interface); + (*handle->interface)->Release(handle->interface); + handle->interface = NULL; + } + + if(handle->device) { + (*handle->device)->USBDeviceClose(handle->device); + (*handle->device)->Release(handle->device); + handle->device = NULL; + } } void close_usb_handle(usb_handle_t *handle) { @@ -51,15 +112,23 @@ bool open_usb_device(io_service_t serv, usb_handle_t *handle) { if((*handle->device)->USBDeviceOpen(handle->device) == kIOReturnSuccess) { if((*handle->device)->SetConfiguration(handle->device, 1) == kIOReturnSuccess && (*handle->device)->CreateDeviceAsyncEventSource(handle->device, &handle->async_event_source) == kIOReturnSuccess) { CFRunLoopAddSource(CFRunLoopGetCurrent(), handle->async_event_source, kCFRunLoopDefaultMode); - ret = true; + + if(open_usb_interface(handle)) { + ret = true; + } else { + (*handle->device)->USBDeviceClose(handle->device); + } } else { (*handle->device)->USBDeviceClose(handle->device); } } + if(!ret) { (*handle->device)->Release(handle->device); + handle->device = NULL; } } + return ret; } @@ -72,6 +141,7 @@ bool wait_usb_handle(usb_handle_t *handle) { while((matching_dict = IOServiceMatching(kUSBDeviceClassName)) != NULL) { cf_dictionary_set_int16(matching_dict, CFSTR(kUSBVendorID), handle->vid); cf_dictionary_set_int16(matching_dict, CFSTR(kUSBProductID), handle->pid); + if(IOServiceGetMatchingServices(0, matching_dict, &iter) == kIOReturnSuccess) { while((serv = IOIteratorNext(iter)) != IO_OBJECT_NULL) { if(open_usb_device(serv, handle)) { @@ -79,19 +149,23 @@ bool wait_usb_handle(usb_handle_t *handle) { break; } } + IOObjectRelease(iter); - if(ret) { - break; - } + + if(ret) break; + sleep_ms(USB_TIMEOUT); } } + return ret; } void reset_usb_handle(usb_handle_t *handle) { - (*handle->device)->ResetDevice(handle->device); - (*handle->device)->USBDeviceReEnumerate(handle->device, 0); + if(handle->device) { + (*handle->device)->ResetDevice(handle->device); + (*handle->device)->USBDeviceReEnumerate(handle->device, 0); + } } static void usb_async_cb(void *refcon, IOReturn ret, void *arg) { @@ -99,6 +173,7 @@ static void usb_async_cb(void *refcon, IOReturn ret, void *arg) { if(transfer_ret != NULL) { memcpy(&transfer_ret->sz, &arg, sizeof(transfer_ret->sz)); + if(ret == kIOReturnSuccess) { transfer_ret->ret = USB_TRANSFER_OK; } else if(ret == kUSBPipeStalled) { @@ -107,6 +182,7 @@ static void usb_async_cb(void *refcon, IOReturn ret, void *arg) { transfer_ret->ret = USB_TRANSFER_ERROR; } } + CFRunLoopStop(CFRunLoopGetCurrent()); } @@ -122,7 +198,9 @@ bool send_usb_control_request(const usb_handle_t *handle, uint8_t bm_request_typ req.wValue = OSSwapLittleToHostInt16(w_value); req.wIndex = OSSwapLittleToHostInt16(w_index); req.completionTimeout = req.noDataTimeout = USB_TIMEOUT; + ret = (*handle->device)->DeviceRequestTO(handle->device, &req); + if(transfer_ret != NULL) { if(ret == kIOReturnSuccess) { transfer_ret->sz = req.wLenDone; @@ -133,6 +211,7 @@ bool send_usb_control_request(const usb_handle_t *handle, uint8_t bm_request_typ transfer_ret->ret = USB_TRANSFER_ERROR; } } + return true; } @@ -150,6 +229,7 @@ bool send_usb_control_request_async(const usb_handle_t *handle, uint8_t bm_reque if((*handle->device)->DeviceRequestAsyncTO(handle->device, &req, usb_async_cb, transfer_ret) == kIOReturnSuccess) { sleep_ms(usb_abort_timeout); + if((*handle->device)->USBDeviceAbortPipeZero(handle->device) == kIOReturnSuccess) { CFRunLoopRun(); return true; @@ -159,10 +239,42 @@ bool send_usb_control_request_async(const usb_handle_t *handle, uint8_t bm_reque return false; } +bool send_interface_control_request(const usb_handle_t *handle, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, void *p_data, size_t w_len, transfer_ret_t *transfer_ret) { + if(!handle || !handle->interface) return false; + + IOUSBDevRequest req = { + .bmRequestType = bm_request_type, + .bRequest = b_request, + .wValue = w_value, + .wIndex = w_index, + .wLength = (UInt16)w_len, + .pData = p_data, + }; + + IOReturn ret = (*handle->interface)->ControlRequest(handle->interface, 0, &req); + + if(transfer_ret) { + transfer_ret->ret = (ret == kIOReturnSuccess) + ? USB_TRANSFER_OK + : USB_TRANSFER_ERROR; + transfer_ret->sz = req.wLenDone; + } + + return ret == kIOReturnSuccess; +} + +bool send_interface_bulk_transfer(const usb_handle_t *handle, void *data, uint32_t len) { + if(!handle || !handle->interface) return false; + IOReturn ret = (*handle->interface)->WritePipe(handle->interface, 2, data, len); + return ret == kIOReturnSuccess; +} + void init_usb_handle(usb_handle_t *handle, uint16_t vid, uint16_t pid) { handle->vid = vid; handle->pid = pid; handle->device = NULL; + handle->interface = NULL; + handle->async_event_source = NULL; } -#endif // __APPLE__ +#endif diff --git a/src/usb/iokit/usb_iokit.h b/src/usb/iokit/usb_iokit.h index 03f3617..fd50c11 100644 --- a/src/usb/iokit/usb_iokit.h +++ b/src/usb/iokit/usb_iokit.h @@ -41,6 +41,7 @@ typedef struct { uint16_t vid, pid; io_service_t serv; IOUSBDeviceInterface320 **device; + IOUSBInterfaceInterface245 **interface; CFRunLoopSourceRef async_event_source; } usb_handle_t; @@ -52,6 +53,8 @@ bool wait_usb_handle(usb_handle_t *handle); void reset_usb_handle(usb_handle_t *handle); bool send_usb_control_request(const usb_handle_t *handle, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, void *p_data, size_t w_len, transfer_ret_t *transfer_ret); bool send_usb_control_request_async(const usb_handle_t *handle, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, void *p_data, size_t w_len, unsigned usb_abort_timeout, transfer_ret_t *transfer_ret); +bool send_interface_control_request(const usb_handle_t *handle, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, void *p_data, size_t w_len, transfer_ret_t *transfer_ret); +bool send_interface_bulk_transfer(const usb_handle_t *handle, void *data, uint32_t len); void init_usb_handle(usb_handle_t *handle, uint16_t vid, uint16_t pid); #endif // IOKIT_BACKEND_H diff --git a/src/pongo/pongo_helper.c b/src/usb/pongo_helper.c similarity index 51% rename from src/pongo/pongo_helper.c rename to src/usb/pongo_helper.c index fb1ce36..dbbb27a 100644 --- a/src/pongo/pongo_helper.c +++ b/src/usb/pongo_helper.c @@ -6,7 +6,7 @@ #include #include -#include "../usb/shim.h" +#include "shim.h" #include "../utils.h" #include "../m8/dfu.h" @@ -66,62 +66,75 @@ void checkm8_boot_pongo(usb_handle_t *handle) { LOG("pongoOS sent, should be booting"); } -int issue_pongo_command(usb_handle_t *handle, char *command, char *outBuffer) { - bool ret; - uint8_t inProgress = 1; - uint32_t outPosition = 0; - uint32_t outLength = 0; - transfer_ret_t transferRet; - char stdoutBuffer[0x2000]; - if (command == NULL) goto fetch_output; - size_t length = strlen(command); - char commandBuffer[0x200]; - if (length > (CMD_LENGTH_MAX - 2)) - { - LOG("Pongo command %s too long (max %d)", command, CMD_LENGTH_MAX - 2); - return -1; - } - LOG("Executing PongoOS command: '%s'", command); - snprintf(commandBuffer, 512, "%s\n", command); - length = strlen(commandBuffer); - ret = send_usb_control_request_no_data(handle, 0x21, 4, 1, 0, 0, NULL); - if (!ret) - goto bad; - ret = send_usb_control_request(handle, 0x21, 3, 0, 0, commandBuffer, (uint32_t)length, NULL); -fetch_output: - while (inProgress) { - ret = send_usb_control_request(handle, 0xA1, 2, 0, 0, &inProgress, (uint32_t)sizeof(inProgress), NULL); - if (ret) { - ret = send_usb_control_request(handle, 0xA1, 1, 0, 0, stdoutBuffer + outPosition, 0x1000, &transferRet); - outLength = transferRet.sz; - if (transferRet.ret == USB_TRANSFER_OK) { - outPosition += outLength; - if (outPosition > 0x1000) { - memmove(stdoutBuffer, stdoutBuffer + outPosition - 0x1000, 0x1000); - outPosition = 0x1000; - } - } - } - if (transferRet.ret != USB_TRANSFER_OK) { - goto bad; - } - } -bad: - if (transferRet.ret != USB_TRANSFER_OK) - { - if (!strncmp("boot", command, 4)) { - return 0; - } else if (command != NULL) { - LOG("USB transfer error: 0x%x, wLength out 0x%x.", transferRet.ret, transferRet.sz); - return transferRet.ret; - } else { +int issue_pongo_command(const usb_handle_t *handle, const char *command) { + uint32_t outpos = 0; + uint32_t outlen = 0; + transfer_ret_t tx_status; + uint8_t in_progress = 1; + + char command_buf[512]; + char stdout_buf[0x2000]; + + memset(stdout_buf, 0, sizeof(stdout_buf)); + + if (command != NULL) { + size_t len = strlen(command); + + if (len > 510) { + LOG("Pongo command too long: %s", command); return -1; } + + LOG("Executing PongoOS command: '%s'", command); + + snprintf(command_buf, sizeof(command_buf), "%s\n", command); + len = strlen(command_buf); + + if (!send_interface_control_request(handle, 0x21, 4, 1, 0, NULL, 0, &tx_status)) return -1; + if (!send_interface_control_request(handle, 0x21, 3, 0, 0, command_buf, len, &tx_status)) return -1; } - else { - if (outBuffer) { - memcpy(outBuffer, stdoutBuffer, outPosition); + fetch_output: + while (in_progress) { + if (!send_interface_control_request(handle, 0xA1, 2, 0, 0, &in_progress, sizeof(in_progress), &tx_status)) goto bad; + + if (in_progress == 0) break; + + if (outpos + 0x1000 >= sizeof(stdout_buf)) { + memmove(stdout_buf, stdout_buf + 0x1000, sizeof(stdout_buf) - 0x1000); + outpos -= 0x1000; } - return ret; + + if (!send_interface_control_request(handle, 0xA1, 1, 0, 0, stdout_buf + outpos, 0x1000, &tx_status)) goto bad; + + outlen = 0x1000; + outpos += outlen; } + bad: + if (tx_status.ret != USB_TRANSFER_OK) { + if (command != NULL && strncmp(command,"boot",4) == 0) { + return 0; + } + + LOG("Pongo USB error: %d", tx_status.ret); + return -1; + } + + return 0; +} + +bool upload_buffer_to_pongo(usb_handle_t *handle, const void *data, size_t length) { + if (data == NULL || length == 0) { + LOG("Invalid data buffer or length.\n"); + return false; + } + + LOG("Uploading %zu bytes to PongoOS...\n", length); + + bool ret = false; + transfer_ret_t tx_status = {0}; + + ret = send_interface_control_request(handle, 0x21, DFU_DNLOAD, 0, 0, (void *)&length, 4, &tx_status); + ret = send_interface_bulk_transfer(handle, (void *)data, (uint32_t)length); + + return ret; } diff --git a/src/pongo/pongo_helper.h b/src/usb/pongo_helper.h similarity index 51% rename from src/pongo/pongo_helper.h rename to src/usb/pongo_helper.h index aad1316..1cd7faf 100644 --- a/src/pongo/pongo_helper.h +++ b/src/usb/pongo_helper.h @@ -1,12 +1,13 @@ #ifndef USB_PONGO_H #define USB_PONGO_H -#include "../usb/shim.h" +#include "shim.h" #define CMD_LENGTH_MAX 512 void compress_pongo(void *out, size_t *out_len); void checkm8_boot_pongo(usb_handle_t *handle); -int issue_pongo_command(usb_handle_t *handle, char *command, char *outBuffer); +int issue_pongo_command(const usb_handle_t *handle, const char *command); +bool upload_buffer_to_pongo(usb_handle_t *handle, const void *data, size_t length); #endif // USB_PONGO_H diff --git a/src/wx/ExploitPanel.cpp b/src/wx/ExploitPanel.cpp index d68a8b8..9f207b0 100644 --- a/src/wx/ExploitPanel.cpp +++ b/src/wx/ExploitPanel.cpp @@ -10,6 +10,7 @@ #include "DevicePanel.hpp" #include "../state.hpp" #include "../utils.h" +#include "../m8/run.h" ExploitPanel::ExploitPanel(MainFrame* frame, wxWindow* parent) : DevicePanel(frame, parent) @@ -64,7 +65,7 @@ void ExploitPanel::StartExploit() const auto state = GetDeviceState(); if (!state.connected || state.mode != DeviceMode::DFU) return; - // TODO: EXPLOOT + exploit(); }).detach(); }