diff --git a/src/events/device_info.cpp b/src/events/device_info.cpp index b37ee7b..ce24319 100644 --- a/src/events/device_info.cpp +++ b/src/events/device_info.cpp @@ -45,12 +45,14 @@ static uint64_t get_hex_field(const char *serial, const char *field) { return p ? strtoull(p + strlen(field), nullptr, 16) : 0; } +// get device info from a recovery mode serial number void get_recovery_info(char *sn, const char **ecid, const char **product_model, const char **product_name) { static char cpid_buf[16]; static char ecid_buf[32]; static char bdid_buf[16]; + // we can get the model based on cpid and bdid uint16_t cpid_val = (uint16_t)get_hex_field(sn, "CPID:"); uint32_t bdid_val = (uint32_t)get_hex_field(sn, "BDID:"); uint64_t ecid_val = get_hex_field(sn, "ECID:"); @@ -64,6 +66,7 @@ void get_recovery_info(char *sn, const char **ecid, const char **product_model, *product_model = nullptr; *product_name = nullptr; + // cpid+bdid -> product type & product name for (int i = 0; irecv_devices[i].product_type; i++) { if (irecv_devices[i].cpid == cpid_val && irecv_devices[i].bdid == bdid_val) { @@ -74,6 +77,7 @@ void get_recovery_info(char *sn, const char **ecid, const char **product_model, } } +// iPhone9,3 -> iPhone 7 (GSM) void get_name_from_product_type(const char *product_type, const char **name) { *name = nullptr; for (int i = 0; irecv_devices[i].product_type; i++) { diff --git a/src/events/device_info.hpp b/src/events/device_info.hpp index 6fee038..469fef1 100644 --- a/src/events/device_info.hpp +++ b/src/events/device_info.hpp @@ -30,6 +30,8 @@ #ifndef MAIN__DEVICE_INFO_H #define MAIN__DEVICE_INFO_H +// stolen from irecovery, I dont think an array +// of devices can be copyrighted? struct irecv_device { const char *product_type; const char *board; diff --git a/src/exploit.c b/src/exploit.c index e24400b..cfabb63 100644 --- a/src/exploit.c +++ b/src/exploit.c @@ -85,6 +85,7 @@ int stage_to_progress(int stage) } const char* err_to_string(int err) { + // error codes should be the same between both checkm8 backends switch (err) { case 0: return ""; case 1: return "-p1_client_err_abort_success"; @@ -112,6 +113,14 @@ const char* err_to_string(int err) { #if WITH_CIDERRAIN +// MARK: exploit (libciderra1n) +// NOTE: this backend is NOT publicly available + +// ciderra1n is based on the checkra1n 1337 implementation +// of the checkm8 exploit using DFU aborts instead of usb resets +// this supports Linux (liteusb), and Darwin (IOKit) +// this also supports A7 devices. + int exploit(int *stage) { LOG("Waiting for devices..."); @@ -142,6 +151,7 @@ int exploit(int *stage) if (flag & kDeviceDFUModeFlag) { if (flag & kDeviceStandardPwnedDFUModeFlag) { + // we cant do shit sorry LOG_ERROR("Found an unknown pwned DFU mode device"); usb_close(client); *stage = STAGE_ERROR; @@ -149,6 +159,7 @@ int exploit(int *stage) } if (flag & kDevicePwnedDFUModeFlag) { + // we cant do shit sorry LOG_ERROR("Detected pwned DFU mode device, please enter normal DFU mode."); usb_close(client); *stage = STAGE_ERROR; @@ -156,6 +167,7 @@ int exploit(int *stage) } if (!(flag & kDeviceNotSoftDFUModeFlag)) { + // we cant do shit sorry LOG_ERROR("Found soft-DFU mode device"); usb_close(client); *stage = STAGE_ERROR; @@ -240,6 +252,11 @@ int exploit(int *stage) *stage = STAGE_ERROR; break; // err } + + // assume everything went well, though + // depending on the components sent to + // the device, the device may not even + // boot at all (not our fault xD) *stage = STAGE_DONE; break; // success } @@ -262,6 +279,15 @@ int exploit(int *stage) #else // WITH_CIDERRAIN +// MARK: exploit (libopenra1n) +// NOTE: this backend is publicly available + +// openra1n is based on the gaster implementation of the exploit +// which is the more well-known implementation of checkm8 +// this supports Windows (Libusb), Linux (Libusb), and Darwin (IOKit) +// on the contrary while gaster *does* support A7, openra1n does not. +// (yet to be implemented, cc @Mineek) + int exploit(int *stage) { LOG("Waiting for devices..."); @@ -279,10 +305,14 @@ int exploit(int *stage) init_usb_handle(&pongoHandle, VID_APPLE, PID_PONGO); for (;;) { + // pongoOS is checked first if (wait_usb_handle(&pongoHandle)) { LOG("Found pongo mode device"); *stage = STAGE_PONGO; + if (palera1n_flags & palerain_option_pongo_exit) + goto pongo_done; + cr = send_full_pongo_jailbreak(&pongoHandle); if (cr != CHECKM8_ERR_NONE) { LOG_ERROR("Failed to boot device (rv=%d, reason=%s)", cr, err_to_string(cr)); @@ -290,10 +320,16 @@ int exploit(int *stage) goto cleanup; } + // assume everything went well, though + // depending on the components sent to + // the device, the device may not even + // boot at all (not our fault xD) + pongo_done: *stage = STAGE_DONE; goto cleanup; } + // DFU is checked second if (wait_usb_handle(&dfuHandle)) { char *sn = get_usb_serial_number(&dfuHandle); if (!sn) goto reloop; @@ -307,6 +343,7 @@ int exploit(int *stage) } if (dfu_serial_number_is_pwned(sn)) { + // we cant do shit sorry LOG_ERROR("Detected pwned DFU mode device, please enter normal DFU mode."); free(sn); *stage = STAGE_ERROR; @@ -343,6 +380,7 @@ int exploit(int *stage) *stage = STAGE_RESET; goto reloop; } + *stage = STAGE_SPRAY; goto reloop; case STAGE_SPRAY: diff --git a/src/pongo_helper.c b/src/pongo_helper.c index 25bee53..4c352d1 100644 --- a/src/pongo_helper.c +++ b/src/pongo_helper.c @@ -44,6 +44,8 @@ #include "globals.h" #include "paleinfo.h" +#define CMD_LENGTH_MAX 512 + p1_transfer_ret_t issue_pongo_command(const p1_usb_handle_t *handle, const char *command) { p1_transfer_ret_t result; @@ -52,7 +54,7 @@ p1_transfer_ret_t issue_pongo_command(const p1_usb_handle_t *handle, const char uint32_t outlen = 0; uint8_t in_progress = 1; - char command_buf[512]; + char command_buf[CMD_LENGTH_MAX]; char stdout_buf[0x2000]; memset(stdout_buf, 0, sizeof(stdout_buf)); @@ -60,7 +62,9 @@ p1_transfer_ret_t issue_pongo_command(const p1_usb_handle_t *handle, const char if (command != NULL) { size_t len = strlen(command); - if (len > 510) { + // unlikely to happen, unless we add support for pongoterm + // TODO: discuss on adding a pongoterm + if (len > CMD_LENGTH_MAX) { LOG_ERROR("Pongo command too long: %s", command); result.ret = 1; return result; @@ -87,6 +91,7 @@ p1_transfer_ret_t issue_pongo_command(const p1_usb_handle_t *handle, const char if (strncmp(command,"boot",4) == 0) goto result; } + // TODO: does this work correctly? while (in_progress) { #if WITH_CIDERRAIN result = usb_ctrl_transfer(handle, 0xA1, 2, 0, 0, &in_progress, sizeof(in_progress)); @@ -194,6 +199,8 @@ p1_checkm8_err_t send_compressed_pongo(p1_usb_handle_t *handle, const uint8_t *p return cr; } +// TODO: support early-exit but with all embedded artifacts already loaded + p1_checkm8_err_t send_full_pongo_jailbreak(p1_usb_handle_t *handle) { p1_transfer_ret_t result; @@ -217,6 +224,7 @@ p1_checkm8_err_t send_full_pongo_jailbreak(p1_usb_handle_t *handle) result = upload_buffer_to_pongo(handle, g_payload_kpf.data, g_payload_kpf.data_len); if (result.ret != 0) goto bad; + // TODO: discuss on adding support for compressed artifacts // embedded artifacts are lzma compressed, mostly for binary size // this tells pongo to decompress after sending the KPF // overwritten artifacts should not be compressed, so we always @@ -241,6 +249,7 @@ p1_checkm8_err_t send_full_pongo_jailbreak(p1_usb_handle_t *handle) result = upload_buffer_to_pongo(handle, g_payload_ramdisk.data, g_payload_ramdisk.data_len); if (result.ret != 0) goto bad; + // TODO: discuss on adding support for compressed artifacts // embedded artifacts are lzma compressed, mostly for binary size // this tells pongo to decompress after sending the ramdisk // overwritten artifacts should not be compressed, so we always @@ -269,6 +278,7 @@ p1_checkm8_err_t send_full_pongo_jailbreak(p1_usb_handle_t *handle) if (result.ret != 0) goto bad; } + // TODO: why do we check results result = issue_pongo_command(handle, "bootx"); if (result.ret != 0) goto bad; diff --git a/src/pongo_helper.h b/src/pongo_helper.h index 2ef3d33..b5d8bf5 100644 --- a/src/pongo_helper.h +++ b/src/pongo_helper.h @@ -47,9 +47,9 @@ typedef checkm8_err_t p1_checkm8_err_t; #endif #define PONGO_MAX_SZ (0x7fe00) +// used for checking overridden files (KPF mainly) #define MACHO_MAGIC_32 (const unsigned char[]){ 0xCE, 0xFA, 0xED, 0xFE } #define MACHO_MAGIC_64 (const unsigned char[]){ 0xCF, 0xFA, 0xED, 0xFE } -#define CMD_LENGTH_MAX 512 p1_checkm8_err_t send_compressed_pongo(p1_usb_handle_t *handle, const uint8_t *pongo_bin, const size_t pongo_bin_length); p1_checkm8_err_t send_full_pongo_jailbreak(p1_usb_handle_t *handle);