void getEmuRW(void *pos, u32 size, u32 *readOff, u32 *writeOff){ //Look for read/write code unsigned char pattern[] = {0x04, 0x00, 0x0D, 0x00, 0x17, 0x00, 0x1E, 0x00, 0xC8, 0x05}; *writeOff = memsearch(pos, pattern, size, 10); *readOff = memsearch((void *)(*writeOff - 0x1000), pattern, 0x1000, 10); }
void getEmuCode(void *pos, u32 *off, u32 size){ void *proc9 = memsearch(pos, "Process9", size, 8); unsigned char pattern[] = {0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF}; //Looking for the last spot before Process9 *off = memsearch(pos, pattern, size - (size - (u32)(proc9 - pos)), 6) + 0xF; }
void patchFirm(void){ //Part1: Add emunand parsing code u32 offset = 0; u32 header = 0; if(getEmunand(&offset, &header) == 1){ fileRead((u8*)emuCode, "/rei/emunand/emunand.bin", 0); u32 *pos_offset = memsearch((u8*)emuCode, "NAND", 0x218, 4); u32 *pos_header = memsearch((u8*)emuCode, "NCSD", 0x218, 4); memcpy((void *)pos_offset, (void *)offset, 4); memcpy((void *)pos_header, (void *)header, 4); } //Part2: Add emunand hooks memcpy((u8*)emuHook1, eh1, sizeof(eh1)); memcpy((u8*)emuHook2, eh2, sizeof(eh2)); memcpy((u8*)emuHook3, eh3, sizeof(eh3)); memcpy((u8*)emuHook4, eh4, sizeof(eh4)); //Part3: Disable signature checks memcpy((u8*)patch1, p1, sizeof(p1)); memcpy((u8*)patch2, p2, sizeof(p2)); //Part4: Create arm9 thread fileRead((u8*)threadCode, "/rei/thread/arm9.bin", 0); memcpy((u8*)threadHook1, th1, sizeof(th1)); memcpy((u8*)threadHook2, th2, sizeof(th2)); }
void getFIRMWrite(void *pos, u32 size, u32 *off){ //Look for FIRM writing code void *firmwrite = memsearch(pos, "exe:", size, 4); unsigned char pattern[] = {0x00, 0x28, 0x01, 0xDA}; *off = (u32)memsearch(firmwrite - 0x100, pattern, 0x100, 4); }
/* ** This patch will fix the error 022-2812 ** Adapted from the post of PF2M ** https://gbatemp.net/threads/release-miiverse-custom-image-tool.415505/page-69#post-6787736 */ static inline void antibanPatch(u8 *code, u32 size) { static const char *deviceID = "X-Nintendo-Device-ID"; static const char *fpdVersion = "X-Nintendo-FPD-Version"; static const char *apiVersion = "X-Nintendo-API-Version"; static const char *deviceIDPatched = "X-Nintendo-ZZZZZZ-ID"; static const char *apiVersionPatched = "1234"; char *position; u32 patternSize; patternSize = strnlen(deviceID, 30); position = (char *)memsearch(code, deviceID, size, patternSize); if (position == NULL) goto error; strcpy(position, deviceIDPatched); patternSize = strnlen(fpdVersion, 30); position = (char *)memsearch(code, fpdVersion, size, patternSize); if (position == NULL) goto error; strcpy(position, deviceID); patternSize = strnlen(apiVersion, 30); position = (char *)memsearch(code, apiVersion, size, patternSize); if (position == NULL) goto error; position += patternSize; position += 2; strcpy(position, apiVersionPatched); error: return; }
void getEmuRW(void *pos, u32 size, u32 *readOff, u32 *writeOff){ //Look for read/write code const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05}; *writeOff = (u32)memsearch(pos, pattern, size, 4) - 6; *readOff = (u32)memsearch((void *)(*writeOff - 0x1000), pattern, 0x1000, 4) - 6; }
u16 *getFirmWrite(u8 *pos, u32 size){ //Look for FIRM writing code u8 *const off = memsearch(pos, "exe:", size, 4); const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA}; return (u16 *)memsearch(off - 0x100, pattern, 0x100, 4); }
int memsearch(int array[][MAX], int mem[][MAX], int r, int c, int a, int b){ if (mem[a][b]!=0) return mem[a][b]; int max=1; if (a-1>=0&&a-1<r&&b>=0&&b<c&&array[a-1][b]<array[a][b]){ int temp=memsearch(array,mem,r,c,a-1,b); if (1+temp>max) max=1+temp; } if (a+1>=0&&a+1<r&&b>=0&&b<c&&array[a+1][b]<array[a][b]){ int temp=memsearch(array,mem,r,c,a+1,b); if (1+temp>max) max=1+temp; } if (a>=0&&a<r&&b+1>=0&&b+1<c&&array[a][b+1]<array[a][b]){ int temp=memsearch(array,mem,r,c,a,b+1); if (1+temp>max) max=1+temp; } if (a>=0&&a<r&&b-1>=0&&b-1<c&&array[a][b-1]<array[a][b]){ int temp=memsearch(array,mem,r,c,a,b-1); if (1+temp>max) max=1+temp; } mem[a][b]=max; return max; }
//Nand redirection void loadEmu(void){ //Dont boot emu if AGB game was just played, or if START was held. if((HID & 0xFFF) == (1 << 3) || CFG_BOOTENV == 0x7) return; //Read emunand code from SD fopen("/rei/emunand/emunand.bin"); Size emuSize = fsize(); getEmuCode(firmLocation, firmSize, &emuCodeOffset); fread(emuCodeOffset, 1, emuSize); fclose(); //Setup Emunand code uPtr *pos_sdmmc = memsearch(emuCodeOffset, "SDMC", emuSize, 4); uPtr *pos_offset = memsearch(emuCodeOffset, "NAND", emuSize, 4); uPtr *pos_header = memsearch(emuCodeOffset, "NCSD", emuSize, 4); getSDMMC(firmLocation, firmSize, &sdmmcOffset); getEmuRW(firmLocation, firmSize, &emuRead, &emuWrite); *pos_sdmmc = sdmmcOffset; *pos_offset = emuOffset; *pos_header = emuHeader; //Add Emunand hooks memcpy((u8*)emuRead, nandRedir, sizeof(nandRedir)); memcpy((u8*)emuWrite, nandRedir, sizeof(nandRedir)); //Set MPU for emu code region getMPU(firmLocation, firmSize, &mpuOffset); memcpy((u8*)mpuOffset, mpu, sizeof(mpu)); }
//Offsets to redirect to thread code void getSigChecks(void *pos, u32 size, u32 *off, u32 *off2){ const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7}; const u8 pattern2[] = {0xB5, 0x22, 0x4D, 0x0C}; *off = (u32)memsearch(pos, (void*)pattern, size, 4); *off2 = (u32)memsearch(pos, (void*)pattern2, size, 4) - 1; }
void getEmuRW(u8 *pos, u32 size, u16 **readOffset, u16 **writeOffset) { //Look for read/write code const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05}; *readOffset = (u16 *)memsearch(pos, pattern, size, 4) - 3; *writeOffset = (u16 *)memsearch((u8 *)(*readOffset + 5), pattern, 0x100, 4) - 3; }
void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2){ //Look for signature checks const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7}, pattern2[] = {0xB5, 0x22, 0x4D, 0x0C}; *off = (u32)memsearch(pos, pattern, size, 4); *off2 = (u32)memsearch(pos, pattern2, size, 4) - 1; }
void getSignatures(void *pos, u32 size, u32 *off, u32 *off2){ //Look for signature checks unsigned char pattern[] = {0xC0, 0x1C, 0x76, 0xE7}; unsigned char pattern2[] = {0xB5, 0x22, 0x4D, 0x0C}; *off = (u32)memsearch(pos, pattern, size, 4); *off2 = (u32)memsearch(pos, pattern2, size, 4) - 1; }
int patch_options(void *address, uint32_t size, uint8_t options, enum types type) { if (options & patch_option_keyx) { print("Patch option: Adding keyX"); if (read_file(fcram_temp, PATH_SLOT0X25KEYX, AES_BLOCK_SIZE) != 0) { print("Failed to load keyX"); draw_message("Failed to load keyX", "Make sure the keyX is\n located at /slot0x25keyX.bin"); return 1; } void *pos = memsearch(address, "slot0x25keyXhere", size, AES_BLOCK_SIZE); if (pos) { memcpy32(pos, fcram_temp, AES_BLOCK_SIZE); } else { print("I don't know where to add keyX.\n Ignoring..."); } } if (options & patch_option_emunand) { print("Patch option: Setting emuNAND offsets"); uint32_t offset = 0; uint32_t header = 0; if (get_emunand_offsets(config->emunand_location, &offset, &header)) { print("Failed to get the emuNAND offsets"); draw_message("Failed to get the emuNAND offsets", "There's 3 possible causes for this error:\n" " - You don't even have an emuNAND installed\n" " - Your SD card can't be read\n" " - You're using an unsupported emuNAND format"); return 1; } uint32_t *pos_offset = memsearch(address, "NAND", size, 4); uint32_t *pos_header = memsearch(address, "NCSD", size, 4); if (pos_offset && pos_header) { *pos_offset = offset; *pos_header = header; } else { print("I don't know where to set the offsets.\n" " Ignoring..."); } } if (options & patch_option_save && type == NATIVE_FIRM) { print("Patch option: Save firm"); save_firm = 1; // This absolutely requires the -fshort-wchar option to be enabled. char *offset = address + size; memcpy(offset, L"sdmc:", 10); memcpy(offset + 10, L"" PATH_PATCHED_FIRMWARE, sizeof(PATH_PATCHED_FIRMWARE) * 2); } return 0; }
void getfOpen(void *pos, u32 size, u32 *off){ //Calculate fOpen u32 p9addr = *(u32*)(memsearch(pos, "ess9", size, 4) + 0xC); u32 p9off = (u32)(memsearch(pos, "code", size, 4) + 0x1FF); unsigned char pattern[] = {0xB0, 0x04, 0x98, 0x0D}; *off = (u32)memsearch(pos, pattern, size, 4) - 2 - p9off + p9addr; }
void patchFirmWrites(u8 *pos, u32 size) { const u16 writeBlock[2] = {0x2000, 0x46C0}; //Look for FIRM writing code u8 *const off1 = memsearch(pos, "exe:", size, 4); const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA}; u16 *off2 = (u16 *)memsearch(off1 - 0x100, pattern, 0x100, 4); off2[0] = writeBlock[0]; off2[1] = writeBlock[1]; }
void MPG::searchPackets(){ packets = (packet *)malloc(buf_size / 12); packets_size = 0; const BYTE *j; const BYTE *last_j; const BYTE *last_packet; pack p; long z; for (int i=0; i < packs_size; i++) { p = packs[i]; last_j = memsearch(p.start, p.size, CODE_PACKET, 3); last_packet = last_j; while (true) { j = memsearch(last_j+1, (p.end - last_j), CODE_PACKET, 3); if (j == NULL) break; if (j + 3 - p.end > 0) { break; last_j = j; continue; } z = (long)j[3]; if (z < 0xBD || z > 0xFF) { last_j = j; continue; } packet pp = {last_packet + 4, j-1, j-(last_packet + 4), PACKET_TYPE[(z & 0xF0) >> 4]}; packets[packets_size++] = pp; last_packet = j; last_j = j; } if (p.end - last_j > 30) { // for last packet z = (long)last_j[3]; if (z < 0xBD || z > 0xFF) continue; packet pp = {last_packet + 4, p.end, p.end-(last_packet+4)+1, PACKET_TYPE[(z & 0xF0) >> 4]}; packets[packets_size++] = pp; } }
void patchSignatureChecks(u8 *pos, u32 size) { const u16 sigPatch[2] = {0x2000, 0x4770}; //Look for signature checks const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7}, pattern2[] = {0xB5, 0x22, 0x4D, 0x0C}; u16 *off = (u16 *)memsearch(pos, pattern, size, 4), *off2 = (u16 *)(memsearch(pos, pattern2, size, 4) - 1); *off = sigPatch[0]; off2[0] = sigPatch[0]; off2[1] = sigPatch[1]; }
static Result ProcessPatchesMenu_DoPatchUnpatchFS(u32 textTotalRoundedSize) { static bool patched = false; static u16 *off; static u16 origData[2]; static const u16 pattern[2] = { 0x7401, // strb r1, [r0, #16] 0x2000, // movs r0, #0 }; if(patched) { memcpy(off, &origData, sizeof(origData)); patched = false; } else { off = (u16 *)memsearch((u8 *)0x00100000, &pattern, textTotalRoundedSize, sizeof(pattern)); if(off == NULL) return -1; for(; (*off & 0xFF00) != 0xB500; off++); // Find function start memcpy(origData, off, 4); off[0] = 0x2001; // mov r0, #1 off[1] = 0x4770; // bx lr patched = true; } processPatchesMenu.items[1].title = patched ? "Unpatch FS for the archive checks" : "Patch FS for the archive checks"; return 0; }
void reimplementSvcBackdoor(u8 *pos, u32 size) { //Official implementation of svcBackdoor const u8 svcBackdoor[40] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff 0x0F, 0x1C, 0x81, 0xE3, //orr r1, r1, #0xf00 0x28, 0x10, 0x81, 0xE2, //add r1, r1, #0x28 0x00, 0x20, 0x91, 0xE5, //ldr r2, [r1] 0x00, 0x60, 0x22, 0xE9, //stmdb r2!, {sp, lr} 0x02, 0xD0, 0xA0, 0xE1, //mov sp, r2 0x30, 0xFF, 0x2F, 0xE1, //blx r0 0x03, 0x00, 0xBD, 0xE8, //pop {r0, r1} 0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0 0x11, 0xFF, 0x2F, 0xE1}; //bx r1 const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif u32 *exceptionsPage = (u32 *)memsearch(pos, pattern, size, 4) - 0xB; u32 svcOffset = (-((exceptionsPage[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch u32 *svcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address while(*svcTable) svcTable++; //Look for SVC0 (NULL) if(svcTable[0x7B] == 0) { u32 *freeSpace; for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++); memcpy(freeSpace, svcBackdoor, 40); svcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)exceptionsPage); } }
u32 *getMPU(u8 *pos, u32 size) { //Look for MPU pattern const u8 pattern[] = {0x03, 0x00, 0x24, 0x00}; return (u32 *)memsearch(pos, pattern, size, 4); }
u32 getSDMMC(void *pos, u32 size){ //Look for struct code const u8 pattern[] = {0x21, 0x20, 0x18, 0x20}; const u8 *off = (u8 *)memsearch(pos, pattern, size, 4) - 1; return *(u32 *)(off + 0x0A) + *(u32 *)(off + 0x0E); }
void *getEmuCode(u8 *pos) { const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; //Looking for the last free space before Process9 return memsearch(pos + 0x13500, pattern, 0x1000, 6) + 0x455; }
u16 *getFirmWriteSafe(u8 *pos, u32 size) { //Look for FIRM writing code const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB}; return (u16 *)memsearch(pos, pattern, size, 4); }
void *getEmuCode(u8 *proc9Offset) { const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; //Looking for the last free space before Process9 return memsearch(proc9Offset - 0x3000, pattern, 0x3000, 6) + 0x455; }
//Nand redirection void loadEmu(void){ //Read emunand code from SD u32 code = emuCode(); fileRead(code, "/rei/emunand/emunand.bin", 0); u32 *pos_offset = memsearch(code, "NAND", 0x218, 4); u32 *pos_header = memsearch(code, "NCSD", 0x218, 4); if (pos_offset && pos_header) { *pos_offset = emuOffset; *pos_header = emuHeader; } //Add emunand hooks memcpy((u8*)emuHook(1), nandRedir, sizeof(nandRedir)); memcpy((u8*)emuHook(2), nandRedir, sizeof(nandRedir)); }
void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr) { //Look for firmlaunch code const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2}; u8 *off = memsearch(pos, pattern, size, 4) - 0x10; //Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1 u32 fOpenOffset = (u32)(off + 9 - (-((*(u32 *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - pos + process9MemAddr); //Copy firmlaunch code memcpy(off, reboot, reboot_size); //Put the fOpen offset in the right location u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_size, 4); *pos_fopen = fOpenOffset; }
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size) { const u8 pattern[] = {0x0A, 0x81, 0x42, 0x02}; u8 *off = memsearch(pos, pattern, size, 4); if(off != NULL) off[4] = 0xE0; }
u32 getSDMMC(u8 *pos, u32 size) { //Look for struct code const u8 pattern[] = {0x21, 0x20, 0x18, 0x20}; const u8 *off = memsearch(pos, pattern, size, 4); return *(u32 *)(off + 9) + *(u32 *)(off + 0xD); }
void MPG::searchPacks(){ packs = (pack *)malloc(buf_size / 128); packs_size = 0; const BYTE *i; BYTE z1[10]; BYTE z2[10]; const BYTE *last = memsearch(buf, buf_size, CODE_PACK, 4); std::cout << "first pack : " << (last - buf) << std::endl; while (1) { i = memsearch(last+1, (buf_end-last) + 1, CODE_PACK, 4); if (i == NULL) break; // classify pack bitAnd(last+4, (const BYTE *)MPG1_PACK_MASK, z1, 10); bitAnd(last+4, (const BYTE *)MPG2_PACK_MASK, z2, 10); if(memcmp(z1, MPG1_PACK_HEAD, 10)==0){ pack p = {last+12, i-1, i-(last+12)}; packs[packs_size++] = p; } else if(memcmp(z2,MPG2_PACK_HEAD, 10)==0){ pack p = {last+14, i-1, i-(last+14)}; packs[packs_size++] = p; } last = i; } // for last pack (bigger than 30bytes) if (buf_end - last > 30) { bitAnd(last+4, (const BYTE *)MPG1_PACK_MASK, z1, 10); bitAnd(last+4, (const BYTE *)MPG2_PACK_MASK, z2, 10); if(memcmp(z1, MPG1_PACK_HEAD, 10) == 0){ pack p = {last+12, buf_end, buf_end-(last+12) + 1}; packs[packs_size++] = p; } else if(memcmp(z2, MPG2_PACK_HEAD, 10) == 0){ pack p = {last+14, buf_end, buf_end-(last+14) + 1}; packs[packs_size++] = p; } } std::cout << "packs num : " << packs_size << std::endl; }