feat(usb): pongoOS booting

This commit is contained in:
CLARATION committed 2026-06-26 18:46:13 -07:00
1 parent 28e002259e
commit 87c1a98230
6 files changed
+249 -94

No files matched your search

+50 -25
View File
@@ -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);
}
+124 -12
View File
@@ -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
+3
View File
@@ -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
@@ -6,7 +6,7 @@
#include <lz4.h>
#include <lz4hc.h>
#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;
}
@@ -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
+2 -1
View File
@@ -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();
}