diff --git a/ios_mcp/source/imports.h b/ios_mcp/source/imports.h index 3d486b8..6ce0b9a 100644 --- a/ios_mcp/source/imports.h +++ b/ios_mcp/source/imports.h @@ -34,6 +34,7 @@ typedef struct __attribute__((__packed__)) { // thumb functions can't just be provided to the linker #define setDefaultTitleId ((int (*)(uint64_t tid)) (0x0510d984 | 1)) +#define encryptPrsh ((int (*)(uint32_t, uint32_t, void *, uint32_t)) (0x0500a610 | 1)) typedef enum BSPHardwareVersions { BSP_HARDWARE_VERSION_UNKNOWN = 0x00000000, diff --git a/ios_mcp/source/menu.c b/ios_mcp/source/menu.c index e40cb78..6f6374f 100644 --- a/ios_mcp/source/menu.c +++ b/ios_mcp/source/menu.c @@ -49,6 +49,7 @@ static void option_DumpOtpAndSeeprom(void); static void option_LoadNetConf(void); static void option_EditParental(void); static void option_SetInitialLaunch(void); +static void option_LoadBoot1Payload(void); static void option_Shutdown(void); static void option_checkMLC(void); static void option_checkSLC(void); @@ -83,6 +84,7 @@ static const Menu mainMenuOptions[] = { {"Debug System Region", {.callback = option_DebugSystemRegion}}, {"System Information", {.callback = option_SystemInformation}}, {"Submit System Data", {.callback = option_SubmitSystemData}}, + {"Load BOOT1 payload", {.callback = option_LoadBoot1Payload}}, {"Shutdown", {.callback = option_Shutdown}}, }; @@ -894,6 +896,164 @@ int read_otp_seeprom(void *buf, int index) return 0; } +static int preparePrshHax(void) +{ + // RAM vars + uint32_t ram_start_addr = 0x10000000; + uint32_t ram_test_buf_size = 0x400; + + // PRSH vars + uint32_t prsh_hdr_offset = ram_start_addr + ram_test_buf_size + 0x5654; + uint32_t prsh_hdr_size = 0x1C; + + // boot_info vars + uint32_t boot_info_name_addr = prsh_hdr_offset + prsh_hdr_size; + uint32_t boot_info_name_size = 0x100; + uint32_t boot_info_ptr_addr = boot_info_name_addr + boot_info_name_size; + + // Calculate PRSH checksum + uint32_t checksum_old = 0; + uint32_t word_counter = 0; + + while (word_counter < 0x20D) { + checksum_old ^= *(uint32_t *) (prsh_hdr_offset + 0x04 + word_counter * 0x04); + word_counter++; + } + + // Change boot_info to point inside boot1 memory + *(uint32_t *) boot_info_ptr_addr = 0x0D40AC6D; + + // Re-calculate PRSH checksum + uint32_t checksum = 0; + word_counter = 0; + + while (word_counter < 0x20D) { + checksum ^= *(uint32_t *) (prsh_hdr_offset + 0x04 + word_counter * 0x04); + word_counter++; + } + + // Update checksum + *(uint32_t *) prsh_hdr_offset = checksum; + + // Copy PRSH IV from IOS-MCP + void *prsh_iv_buf = IOS_HeapAlloc(CROSS_PROCESS_HEAP_ID, 0x10); + if (!prsh_iv_buf) { + return -1; + } + + memcpy(prsh_iv_buf, (void*) 0x050677C0, 0x10); + + // Encrypt PRSH + int res = encryptPrsh(0x10000400, 0x7C00, prsh_iv_buf, 0x10); + + // Free PRSH IV buffer + IOS_HeapFree(CROSS_PROCESS_HEAP_ID, prsh_iv_buf); + + // Flush cache + IOS_FlushDCache((void*) 0x10000400, 0x7C00); + + return res; +} + +static void option_LoadBoot1Payload(void) +{ + static const Menu boot1ControlOptions[] = { + {"Back", {0} }, + {"Load", {0} }, + }; + + gfx_clear(COLOR_BACKGROUND); + + uint32_t index = 16 + 8 + 2 + 8; + gfx_set_font_color(COLOR_PRIMARY); + + index = gfx_printf(16, index, GfxPrintFlag_ClearBG, "This will load a payload from within boot1\n" + "from the SD Card named boot1.img.\n\n" + "Do you want to continue?\n\n\n"); + + int selected = drawMenu("Load BOOT1 Payload", + boot1ControlOptions, ARRAY_SIZE(boot1ControlOptions), 0, + MenuFlag_NoClearScreen, 16, index); + index += (CHAR_SIZE_DRC_Y + 4) * (ARRAY_SIZE(boot1ControlOptions) + 1); + + if (selected == 0) + return; + + int fileHandle; + int res = FSA_OpenFile(fsaHandle, "/vol/storage_recovsd/boot1.img", "r", &fileHandle); + if (res < 0) { + gfx_set_font_color(COLOR_ERROR); + gfx_printf(16, index, 0, "Failed to open boot1.img: %x", res); + waitButtonInput(); + return; + } + + uint32_t* dataBuffer = (uint32_t*) IOS_HeapAllocAligned(CROSS_PROCESS_HEAP_ID, 0x40, 0x40); + if (!dataBuffer) { + gfx_set_font_color(COLOR_ERROR); + gfx_printf(16, index, 0, "Failed to allocate data buffer!"); + waitButtonInput(); + FSA_CloseFile(fsaHandle, fileHandle); + return; + } + + // // skip the ancast header + // res = FSA_SetPosFile(fsaHandle, fileHandle, 0x200); + // if (res < 0) { + // gfx_set_font_color(COLOR_ERROR); + // gfx_printf(16, index, 0, "Failed to set boot1.img pos: %x", res); + // waitButtonInput(); + // IOS_HeapFree(CROSS_PROCESS_HEAP_ID, dataBuffer); + // FSA_CloseFile(fsaHandle, fileHandle); + // return; + // } + + // TODO verify that this is actually a valid ancast image, maybe do that before writing it to MEM1 actually + // read ancast header first and then the rest + + // read and write payload to mem1 + uint32_t payloadOffset = 0x00000050; + int bytesRead = 0; + while ((res = FSA_ReadFile(fsaHandle, dataBuffer, 1, 0x40, fileHandle, 0)) > 0) { + bytesRead += res; + for (int i = 0; i < res; i += 4) { + kernWrite32(payloadOffset, dataBuffer[i/4]); + payloadOffset += 4; + } + } + + gfx_printf(16, index, 0, "Read %d bytes", bytesRead); + + IOS_HeapFree(CROSS_PROCESS_HEAP_ID, dataBuffer); + FSA_CloseFile(fsaHandle, fileHandle); + + if (res < 0) { + gfx_set_font_color(COLOR_ERROR); + gfx_printf(16, index, 0, "Failed to read boot1.img: %x", res); + waitButtonInput(); + return; + } + + res = preparePrshHax(); + if (res < 0) { + gfx_set_font_color(COLOR_ERROR); + gfx_printf(16, index, 0, "Failed to prepare prshhax: %x", res); + waitButtonInput(); + return; + } + + // Setup branch to MEM1 payload (skip ancast + loader header) TODO we probably won't have to skip the loader header, boot1 usually doesn't come with one + kernWrite32(0x00000000, 0xEA000096); // b #0x260 + //kernWrite32(0x00000000, 0xEA000012); // b #0x50 + kernWrite32(0x00000004, 0xDEADC0DE); + kernWrite32(0x00000008, 0xDEADC0DE); + + IOS_Shutdown(1); + + // we're at the point of no return + while(1); +} + static void option_SetInitialLaunch(void) { static const Menu initialLaunchOptions[] = { diff --git a/ios_mcp/source/pm.c b/ios_mcp/source/pm.c new file mode 100644 index 0000000..e57a9fd --- /dev/null +++ b/ios_mcp/source/pm.c @@ -0,0 +1,15 @@ +#include "pm.h" +#include "imports.h" + +int PM_Restart(void) +{ + int fd = IOS_Open("/dev/pm",0); + if (fd < 0) { + return fd; + } + + int res = IOS_Ioctl(fd, 0xe3, NULL, 0, NULL, 0); + IOS_Close(fd); + + return res; +} diff --git a/ios_mcp/source/pm.h b/ios_mcp/source/pm.h new file mode 100644 index 0000000..49b62ba --- /dev/null +++ b/ios_mcp/source/pm.h @@ -0,0 +1,3 @@ +#pragma once + +int PM_Restart(void);