diff --git a/README.md b/README.md index 7d4f3d1..6a8f87c 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Pre-compiled version can still be found on my [pastebin](http://pastebin.com/c5A **Credits:** - Cakes team for teaching me a few things and just being helpful in general! And for ROP/mset related code. + Cakes team for teaching me a few things and just being helpful in general! And for ROP/mset related code, and crypto libs. 3DBREW for saving me plenty of reverse engineering time. diff --git a/source/crypto.c b/source/crypto.c new file mode 100644 index 0000000..5eb479d --- /dev/null +++ b/source/crypto.c @@ -0,0 +1,402 @@ +// From http://github.com/b1l1s/ctr + +#include "crypto.h" + +#include +#include "memory.h" +#include "fatfs/sdmmc/sdmmc.h" +#include "fatfs/ff.h" + +/**************************************************************** +* Crypto Libs +****************************************************************/ + +/* original version by megazig */ + +#ifndef __thumb__ +#define BSWAP32(x) {\ + __asm__\ + (\ + "eor r1, %1, %1, ror #16\n\t"\ + "bic r1, r1, #0xFF0000\n\t"\ + "mov %0, %1, ror #8\n\t"\ + "eor %0, %0, r1, lsr #8\n\t"\ + :"=r"(x)\ + :"0"(x)\ + :"r1"\ + );\ +}; + +#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\ +__asm__\ + (\ + "adds %0, %4\n\t"\ + "addcss %1, %1, #1\n\t"\ + "addcss %2, %2, #1\n\t"\ + "addcs %3, %3, #1\n\t"\ + : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\ + : "r"(u32_0)\ + : "cc"\ + );\ +} +#else +#define BSWAP32(x) {x = __builtin_bswap32(x);} + +#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\ +__asm__\ + (\ + "mov r4, #0\n\t"\ + "add %0, %0, %4\n\t"\ + "adc %1, %1, r4\n\t"\ + "adc %2, %2, r4\n\t"\ + "adc %3, %3, r4\n\t"\ + : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\ + : "r"(u32_0)\ + : "cc", "r4"\ + );\ +} +#endif /*__thumb__*/ + +void aes_setkey(u8 keyslot, const void* key, u32 keyType, u32 mode) +{ + if(keyslot <= 0x03) return; // Ignore TWL keys for now + + u32* key32 = (u32*)key; + *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode; + *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE; + + REG_AESKEYFIFO[keyType] = key32[0]; + REG_AESKEYFIFO[keyType] = key32[1]; + REG_AESKEYFIFO[keyType] = key32[2]; + REG_AESKEYFIFO[keyType] = key32[3]; +} + +void aes_use_keyslot(u8 keyslot) +{ + if(keyslot > 0x3F) + return; + + *REG_AESKEYSEL = keyslot; + *REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */ +} + +void aes_setiv(const void* iv, u32 mode) +{ + const u32* iv32 = (const u32*)iv; + *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode; + + // Word order for IV can't be changed in REG_AESCNT and always default to reversed + if(mode & AES_INPUT_NORMAL) + { + REG_AESCTR[0] = iv32[3]; + REG_AESCTR[1] = iv32[2]; + REG_AESCTR[2] = iv32[1]; + REG_AESCTR[3] = iv32[0]; + } + else + { + REG_AESCTR[0] = iv32[0]; + REG_AESCTR[1] = iv32[1]; + REG_AESCTR[2] = iv32[2]; + REG_AESCTR[3] = iv32[3]; + } +} + +void aes_advctr(void* ctr, u32 val, u32 mode) +{ + u32* ctr32 = (u32*)ctr; + + int i; + if(mode & AES_INPUT_BE) + { + for(i = 0; i < 4; ++i) // Endian swap + BSWAP32(ctr32[i]); + } + + if(mode & AES_INPUT_NORMAL) + { + ADD_u128_u32(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val); + } + else + { + ADD_u128_u32(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val); + } + + if(mode & AES_INPUT_BE) + { + for(i = 0; i < 4; ++i) // Endian swap + BSWAP32(ctr32[i]); + } +} + +void aes_change_ctrmode(void* ctr, u32 fromMode, u32 toMode) +{ + u32* ctr32 = (u32*)ctr; + int i; + if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN) + { + for(i = 0; i < 4; ++i) + BSWAP32(ctr32[i]); + } + + if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER) + { + u32 temp = ctr32[0]; + ctr32[0] = ctr32[3]; + ctr32[3] = temp; + + temp = ctr32[1]; + ctr32[1] = ctr32[2]; + ctr32[2] = temp; + } +} + +void aes_batch(void* dst, const void* src, u32 blockCount) +{ + *REG_AESBLKCNT = blockCount << 16; + *REG_AESCNT |= AES_CNT_START; + + const u32* src32 = (const u32*)src; + u32* dst32 = (u32*)dst; + + u32 wbc = blockCount; + u32 rbc = blockCount; + + while(rbc) + { + if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints + { + *REG_AESWRFIFO = *src32++; + *REG_AESWRFIFO = *src32++; + *REG_AESWRFIFO = *src32++; + *REG_AESWRFIFO = *src32++; + wbc--; + } + + if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read + { + *dst32++ = *REG_AESRDFIFO; + *dst32++ = *REG_AESRDFIFO; + *dst32++ = *REG_AESRDFIFO; + *dst32++ = *REG_AESRDFIFO; + rbc--; + } + } +} + +void aes(void* dst, const void* src, u32 blockCount, void* iv, u32 mode, u32 ivMode) +{ + *REG_AESCNT = mode | + AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | + AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN | + AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE; + + u32 blocks; + while(blockCount != 0) + { + if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE + && (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE) + aes_setiv(iv, ivMode); + + blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount; + + // Save the last block for the next decryption CBC batch's iv + if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE) + { + memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); + aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); + } + + // Process the current batch + aes_batch(dst, src, blocks); + + // Save the last block for the next encryption CBC batch's iv + if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE) + { + memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); + aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); + } + + // Advance counter for CTR mode + else if((mode & AES_ALL_MODES) == AES_CTR_MODE) + aes_advctr(iv, blocks, ivMode); + + src += blocks * AES_BLOCK_SIZE; + dst += blocks * AES_BLOCK_SIZE; + blockCount -= blocks; + } +} + +void sha_wait_idle() +{ + while(*REG_SHA_CNT & 1); +} + +void sha(void* res, const void* src, u32 size, u32 mode) +{ + sha_wait_idle(); + *REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND; + + const u32* src32 = (const u32*)src; + int i; + while(size >= 0x40) + { + sha_wait_idle(); + for(i = 0; i < 4; ++i) + { + *REG_SHA_INFIFO = *src32++; + *REG_SHA_INFIFO = *src32++; + *REG_SHA_INFIFO = *src32++; + *REG_SHA_INFIFO = *src32++; + } + + size -= 0x40; + } + + sha_wait_idle(); + memcpy((void*)REG_SHA_INFIFO, src32, size); + + *REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND; + + while(*REG_SHA_CNT & SHA_FINAL_ROUND); + sha_wait_idle(); + + u32 hashSize = SHA_256_HASH_SIZE; + if(mode == SHA_224_MODE) + hashSize = SHA_224_HASH_SIZE; + else if(mode == SHA_1_MODE) + hashSize = SHA_1_HASH_SIZE; + + memcpy(res, (void*)REG_SHA_HASH, hashSize); +} + +void rsa_wait_idle() +{ + while(*REG_RSA_CNT & 1); +} + +void rsa_use_keyslot(u32 keyslot) +{ + *REG_RSA_CNT = (*REG_RSA_CNT & ~RSA_CNT_KEYSLOTS) | (keyslot << 4); +} + +void rsa_setkey(u32 keyslot, const void* mod, const void* exp, u32 mode) +{ + rsa_wait_idle(); + *REG_RSA_CNT = (*REG_RSA_CNT & ~RSA_CNT_KEYSLOTS) | (keyslot << 4) | RSA_IO_BE | RSA_IO_NORMAL; + + u32 size = mode * 4; + + volatile u32* keyslotCnt = REG_RSA_SLOT0 + (keyslot << 4); + keyslotCnt[0] &= ~(RSA_SLOTCNT_KEY_SET | RSA_SLOTCNT_WPROTECT); + keyslotCnt[1] = mode; + + memcpy((void*)REG_RSA_MOD_END - size, mod, size); + + if(exp == NULL) + { + size -= 4; + while(size) + { + *REG_RSA_EXPFIFO = 0; + size -= 4; + } + *REG_RSA_EXPFIFO = 0x01000100; // 0x00010001 byteswapped + } + else + { + const u32* exp32 = (const u32*)exp; + while(size) + { + *REG_RSA_EXPFIFO = *exp32++; + size -= 4; + } + } +} + +int rsa_iskeyset(u32 keyslot) +{ + return *(REG_RSA_SLOT0 + (keyslot << 4)) & 1; +} + +void rsa(void* dst, const void* src, u32 size) +{ + u32 keyslot = (*REG_RSA_CNT & RSA_CNT_KEYSLOTS) >> 4; + if(rsa_iskeyset(keyslot) == 0) + return; + + rsa_wait_idle(); + *REG_RSA_CNT |= RSA_IO_BE | RSA_IO_NORMAL; + + // Pad the message with zeroes so that it's a multiple of 8 + // and write the message with the end aligned with the register + u32 padSize = ((size + 7) & ~7) - size; + memset((void*)REG_RSA_TXT_END - (size + padSize), 0, padSize); + memcpy((void*)REG_RSA_TXT_END - size, src, size); + + // Start + *REG_RSA_CNT |= RSA_CNT_START; + + rsa_wait_idle(); + memcpy(dst, (void*)REG_RSA_TXT_END - size, size); +} + +int rsa_verify(const void* data, u32 size, const void* sig, u32 mode) +{ + u8 dataHash[SHA_256_HASH_SIZE]; + sha(dataHash, data, size, SHA_256_MODE); + + u8 decSig[0x100]; // Way too big, need to request a work area + + u32 sigSize = mode * 4; + rsa(decSig, sig, sigSize); + + return memcmp(dataHash, decSig + (sigSize - SHA_256_HASH_SIZE), SHA_256_HASH_SIZE) == 0; +} + +/**************************************************************** +* Nand/FIRM Crypto stuff +****************************************************************/ + +//Get Nand CTR key +void getNandCTR(u8 *buf) { + u8 *addr = (u8*)0x080D8BBC; + u8 keyLen = 0x10; //CTR length + addr += 0x0F; + while (keyLen --) { *(buf++) = *(addr--); } +} + +//Read firm0 from NAND and write to buffer +void nandFirm0(u8 *outbuf, const u32 size){ + u8 CTR[0x10]; + getNandCTR(CTR); + aes_advctr(CTR, 0x0B130000/0x10, AES_INPUT_BE | AES_INPUT_NORMAL); + sdmmc_nand_readsectors(0x0B130000 / 0x200, size / 0x200, outbuf); + aes_use_keyslot(0x06); + aes(outbuf, outbuf, size / AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); +} + +//Decrypt the arm9 binary on N3DS firm +void decryptArm9Bin(void *armHdr, u32 kversion){ + u8 keyX[0x10]; + u8 keyY[0x10]; + u8 CTR[0x10]; + u32 slot = (kversion == 0x0F ? 0x16 : 0x15); + + memcpy(keyY, armHdr+0x10, 0x10); + memcpy(CTR, armHdr+0x20, 0x10); + u32 size = atoi(armHdr+0x30); + + aes_use_keyslot(0x11); + + if(kversion == 0x0F){ + aes(keyX, armHdr+0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0); + aes_setkey(slot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); + } + + aes_setkey(slot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_setiv(CTR, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_use_keyslot(slot); + + aes(armHdr+0x800, armHdr+0x800, size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); +} \ No newline at end of file diff --git a/source/crypto.h b/source/crypto.h new file mode 100644 index 0000000..4d0ae2d --- /dev/null +++ b/source/crypto.h @@ -0,0 +1,138 @@ +// From http://github.com/b1l1s/ctr + +#ifndef __CRYPTO_H +#define __CRYPTO_H + +#include +#include "types.h" + +#define FIRM_TYPE_ARM9 0 +#define FIRM_TYPE_ARM11 1 + +#define MEDIA_UNITS 0x200 + +#define NCCH_MAGIC (0x4843434E) +#define NCSD_MAGIC (0x4453434E) +#define FIRM_MAGIC (0x4D524946) +#define ARM9BIN_MAGIC (0x47704770) + +/**************************AES****************************/ +#define REG_AESCNT ((volatile u32*)0x10009000) +#define REG_AESBLKCNT ((volatile u32*)0x10009004) +#define REG_AESWRFIFO ((volatile u32*)0x10009008) +#define REG_AESRDFIFO ((volatile u32*)0x1000900C) +#define REG_AESKEYSEL ((volatile u8 *)0x10009010) +#define REG_AESKEYCNT ((volatile u8 *)0x10009011) +#define REG_AESCTR ((volatile u32*)0x10009020) + +#define REG_AESKEYFIFO ((volatile u32*)0x10009100) +#define REG_AESKEYXFIFO ((volatile u32*)0x10009104) +#define REG_AESKEYYFIFO ((volatile u32*)0x10009108) + +#define AES_CCM_DECRYPT_MODE (0u << 27) +#define AES_CCM_ENCRYPT_MODE (1u << 27) +#define AES_CTR_MODE (2u << 27) +#define AES_CTR_MODE (2u << 27) +#define AES_CBC_DECRYPT_MODE (4u << 27) +#define AES_CBC_ENCRYPT_MODE (5u << 27) +#define AES_ECB_DECRYPT_MODE (6u << 27) +#define AES_ECB_ENCRYPT_MODE (7u << 27) +#define AES_ALL_MODES (7u << 27) + +#define AES_CNT_START 0x80000000 +#define AES_CNT_INPUT_ORDER 0x02000000 +#define AES_CNT_OUTPUT_ORDER 0x01000000 +#define AES_CNT_INPUT_ENDIAN 0x00800000 +#define AES_CNT_OUTPUT_ENDIAN 0x00400000 +#define AES_CNT_FLUSH_READ 0x00000800 +#define AES_CNT_FLUSH_WRITE 0x00000400 + +#define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN) +#define AES_INPUT_LE 0 +#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER) +#define AES_INPUT_REVERSED 0 + +#define AES_TEMP_KEYSLOT 0x11 + +#define AES_BLOCK_SIZE 0x10 + +#define AES_KEYCNT_WRITE (1 << 0x7) +#define AES_KEYNORMAL 0 +#define AES_KEYX 1 +#define AES_KEYY 2 + +/**************************SHA****************************/ +#define REG_SHA_CNT ((volatile u32*)0x1000A000) +#define REG_SHA_BLKCNT ((volatile u32*)0x1000A004) +#define REG_SHA_HASH ((volatile u32*)0x1000A040) +#define REG_SHA_INFIFO ((volatile u32*)0x1000A080) + +#define SHA_CNT_STATE 0x00000003 +#define SHA_CNT_UNK2 0x00000004 +#define SHA_CNT_OUTPUT_ENDIAN 0x00000008 +#define SHA_CNT_MODE 0x00000030 +#define SHA_CNT_ENABLE 0x00010000 +#define SHA_CNT_ACTIVE 0x00020000 + +#define SHA_HASH_READY 0x00000000 +#define SHA_NORMAL_ROUND 0x00000001 +#define SHA_FINAL_ROUND 0x00000002 + +#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN +#define SHA_OUTPUT_LE 0 + +#define SHA_256_MODE 0 +#define SHA_224_MODE 0x00000010 +#define SHA_1_MODE 0x00000020 + +#define SHA_256_HASH_SIZE (256 / 8) +#define SHA_224_HASH_SIZE (224 / 8) +#define SHA_1_HASH_SIZE (160 / 8) + +/**************************RSA****************************/ +#define REG_RSA_CNT ((volatile u32*)0x1000B000) +#define REG_RSA_SLOT0 ((volatile u32*)0x1000B100) +#define REG_RSA_SLOT1 ((volatile u32*)0x1000B110) +#define REG_RSA_SLOT2 ((volatile u32*)0x1000B120) +#define REG_RSA_SLOT3 ((volatile u32*)0x1000B130) +#define REG_RSA_EXPFIFO ((volatile u32*)0x1000B200) +#define REG_RSA_MOD_END ((volatile u32*)0x1000B500) +#define REG_RSA_TXT_END ((volatile u32*)0x1000B900) + +#define RSA_CNT_START 0x00000001 +#define RSA_CNT_KEYSLOTS 0x000000F0 +#define RSA_CNT_IO_ENDIAN 0x00000100 +#define RSA_CNT_IO_ORDER 0x00000200 + +#define RSA_SLOTCNT_KEY_SET 0x00000001 +#define RSA_SLOTCNT_WPROTECT 0x00000002 // Write protect + +#define RSA_IO_BE RSA_CNT_IO_ENDIAN +#define RSA_IO_LE 0 +#define RSA_IO_NORMAL RSA_CNT_IO_ORDER +#define RSA_IO_REVERSED 0 + +#define RSA_TEMP_KEYSLOT 0 + +#define RSA_1024_MODE 0x20 +#define RSA_2048_MODE 0x40 + +//Crypto Libs +void aes_setkey(u8 keyslot, const void* key, u32 keyType, u32 mode); +void aes_use_keyslot(u8 keyslot); +void aes(void* dst, const void* src, u32 blockCount, void* iv, u32 mode, u32 ivMode); +void aes_setiv(const void* iv, u32 mode); +void aes_advctr(void* ctr, u32 val, u32 mode); +void aes_change_ctrmode(void* ctr, u32 fromMode, u32 toMode); +void aes_batch(void* dst, const void* src, u32 blockCount); +void sha(void* res, const void* src, u32 size, u32 mode); +void rsa_setkey(u32 keyslot, const void* mod, const void* exp, u32 mode); +void rsa_use_keyslot(u32 keyslot); +int rsa_verify(const void* data, u32 size, const void* sig, u32 mode); + +//NAND/FIRM stuff +void getNandCTR(u8 *buf); +void nandFirm0(u8 *outbuf, const u32 size); +void decryptArm9Bin(void *armHdr, u32 kversion); + +#endif /*__CRYPTO_H*/ diff --git a/source/draw.c b/source/draw.c index d125a5b..4bf6c70 100644 --- a/source/draw.c +++ b/source/draw.c @@ -6,6 +6,7 @@ #include "draw.h" #include "fs.h" +#include "memory.h" void clearScreen(void){ memset(fb->top_left, 0, 0x38400); diff --git a/source/firm.c b/source/firm.c index d2eac24..76b04bb 100644 --- a/source/firm.c +++ b/source/firm.c @@ -7,61 +7,76 @@ #include "firm.h" #include "patches.h" #include "memory.h" -#include "types.h" #include "fs.h" #include "emunand.h" +#include "crypto.h" firmHeader *firmLocation = (firmHeader *)0x24000000; const u32 firmSize = 0xF1000; firmSectionHeader *section; u32 emuOffset = 0; u32 emuHeader = 0; +u32 kversion = 0; -void loadFirm(void){ - //Read FIRM from SD card and write to FCRAM - fileRead((u8*)firmLocation, "/rei/firmware.bin", firmSize); - section = firmLocation->section; -} - -void loadSys(void){ - memcpy((u8*)mpuCode, mpu, sizeof(mpu)); +//Load firm into FCRAM +void loadFirm(int mode){ + //Sysnand mode + if(mode == 0 || getEmunand(&emuOffset, &emuHeader) == 0){ + //Read FIRM from NAND and write to FCRAM + nandFirm0((u8*)firmLocation, firmSize); + section = firmLocation->section; + kversion = 0x04; //TODO: make this not hard coded + decryptArm9Bin((u8*)firmLocation + section[2].offset, kversion); + } + //Emunand mode + else{ + //Read FIRM from SD card and write to FCRAM + fileRead((u8*)firmLocation, "/rei/firmware.bin", firmSize); + section = firmLocation->section; + kversion = 0x0F; //TODO: make this not hard coded + loadEmu(); + } } +//Nand redirection void loadEmu(void){ - 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); + + //Read emunand code from SD + u32 code = emuCode(); + fileRead((u8*)code, "/rei/emunand/emunand.bin", 0); + u32 *pos_offset = memsearch((u8*)code, "NAND", 0x218, 4); + u32 *pos_header = memsearch((u8*)code, "NCSD", 0x218, 4); memcpy((void *)pos_offset, (void *)emuOffset, 4); memcpy((void *)pos_header, (void *)emuHeader, 4); //Add emunand hooks - memcpy((u8*)mpuCode, mpu, sizeof(mpu)); - memcpy((u8*)emuHook2, eh2, sizeof(eh2)); - memcpy((u8*)emuHook3, eh3, sizeof(eh3)); - memcpy((u8*)emuHook4, eh4, sizeof(eh4)); + memcpy((u8*)emuHook(1), eh1, sizeof(eh1)); + memcpy((u8*)emuHook(2), eh2, sizeof(eh2)); + memcpy((u8*)emuHook(3), eh3, sizeof(eh3)); } -void patchFirm(void){ +//Patches +void patchFirm(){ - //Part1: Get Emunand - if(getEmunand(&emuOffset, &emuHeader) == 1) - loadEmu(); - else - loadSys(); + //Part1: Set MPU for payload area + memcpy((u8*)mpuCode(kversion), mpu, sizeof(mpu)); //Part2: Disable signature checks - memcpy((u8*)patch1, p1, sizeof(p1)); - memcpy((u8*)patch2, p2, sizeof(p2)); + memcpy((u8*)sigPatch(1, kversion), p1, sizeof(p1)); + memcpy((u8*)sigPatch(2, kversion), p2, sizeof(p2)); //Part3: Create arm9 thread - fileRead((u8*)threadCode, "/rei/thread/arm9.bin", 0); - memcpy((u8*)threadHook1, th1, sizeof(th1)); - memcpy((u8*)threadHook2, th2, sizeof(th2)); + fileRead((u8*)threadCode(kversion), "/rei/thread/arm9.bin", 0); + if(kversion == 0x0F){ //TODO: 0F only untill i can figure out why the hell this doesnt work on sysnand anymore. + memcpy((u8*)threadHook(1, kversion), th1, sizeof(th1)); + memcpy((u8*)threadHook(2, kversion), th2, sizeof(th2)); + } } +//Firmlaunchhax void launchFirm(void){ + //Set MPU - __asm__ ( "msr cpsr_c, #0xDF\n\t" //Set system mode, disable interrupts "ldr r0, =0x10000035\n\t" //Memory area 0x10000000-0x18000000, enabled, 128MB diff --git a/source/firm.h b/source/firm.h index cf2129a..3e97be9 100644 --- a/source/firm.h +++ b/source/firm.h @@ -6,9 +6,10 @@ #ifndef FIRM_INC #define FIRM_INC +#include "types.h" + void loadSplash(void); -void loadFirm(void); -void loadSys(void); +void loadFirm(int mode); void loadEmu(void); void patchFirm(void); void launchFirm(void); diff --git a/source/main.c b/source/main.c index 943fb30..20526bd 100644 --- a/source/main.c +++ b/source/main.c @@ -10,11 +10,16 @@ #include "firm.h" #include "draw.h" +int mode = 1; + int main(){ mountSD(); loadSplash(); - while(((~*(unsigned *)0x10146000) & 0xFFF) == (1 << 3) ? 0 : 1); //Press start to boot - loadFirm(); + while(1){ + if(((~*(unsigned *)0x10146000) & 0xFFF) == (1 << 3)) break; + else if(((~*(unsigned *)0x10146000) & 0xFFF) == ((1 << 3) | (1 << 1))) {mode = 0; break;} + } //Start = emu; Start+B = sys + loadFirm(mode); patchFirm(); launchFirm(); return 0; diff --git a/source/patches.c b/source/patches.c new file mode 100644 index 0000000..e8bd204 --- /dev/null +++ b/source/patches.c @@ -0,0 +1,135 @@ +/* +* patches.c +* by Reisyukaku +* Copyright (c) 2015 All Rights Reserved +*/ + +#include "patches.h" + +#define FIRM 0x24000000 +#define KERNEL9 (FIRM + 0x66A00) +#define PROC9 (FIRM + 0x7D700) + +#define K9_ADDR 0x08006000 +#define P9_ADDR 0x08028000 + +/************************************************** +* Patches +**************************************************/ + +/* +* Emunand +*/ +u8 mpu[0x2C] = { //MPU shit + 0x03, 0x00, 0x36, 0x00, 0x00, 0x00, 0x10, 0x10, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x36, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x01, 0x01, 0x03, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x01, 0x01, 0x01, 0x01, 0x03, 0x06, 0x1C, 0x00, 0x00, 0x00, 0x02, 0x08 + }; +u8 eh1[0x14] = { //Sets Slot0x25KeyX + 0x03, 0x4A, 0x05, 0x21, 0x25, 0x20, 0x2F, 0xF0, 0xAB, 0xF8, 0x37, 0xF0, 0x6F, 0xFB, 0x70, 0xBD, + 0xC8, 0xA6, 0x01, 0x08 + }; +u8 eh2[0x0A] = {0x01, 0x4C, 0x20, 0x47, 0x00, 0x00, 0xC0, 0xA4, 0x01, 0x08}; //Branch to emunand write function +u8 eh3[0x0A] = {0x01, 0x4C, 0x20, 0x47, 0x00, 0x00, 0xB0, 0xA5, 0x01, 0x08}; //Branch to emunand read function + +/* +* Sig checks +*/ +u8 p1[2] = {0x00, 0x20}; +u8 p2[4] = {0x00, 0x20, 0x70, 0x47}; + +/* +* Arm9 thread +*/ +u8 th1[4] = {0x2C, 0xF0, 0x9F, 0xE5}; //ldr pc, =0x080860E4 +u8 th2[4] = {0xE0, 0xA6, 0x01, 0x08}; //0x080860E4 + + + +/************************************************** +* Functions +**************************************************/ + +u32 emuCode(void){ //0F only + return KERNEL9 + (0x0801A4C0 - K9_ADDR); +} + +u32 mpuCode(u32 kver){ + u32 ret = NULL; + switch(kver){ + case 0x04: + case 0x0C: + case 0x0F: + ret = KERNEL9 + (0x0801B3D4 - K9_ADDR); + break; + } + return ret; +} + +u32 threadCode(u32 kver){ + u32 ret = NULL; + switch(kver){ + case 0x04: + case 0x0C: + case 0x0F: + ret = KERNEL9 + (0x0801A6E0 - K9_ADDR); + break; + } + return ret; +} + +u32 threadHook(u8 val, u32 kver){ + u32 ret = NULL; + switch(kver){ + case 0x04: + ret = val == 1 ? + PROC9 + (0x0808690C - P9_ADDR) : + PROC9 + (0x08086940 - P9_ADDR); + break; + case 0x0C: + //TODO: find + break; + case 0x0F: + ret = val == 1 ? + PROC9 + (0x080860B0 - P9_ADDR) : + PROC9 + (0x080860E4 - P9_ADDR); + break; + } + return ret; +} + +u32 emuHook(u8 val){ //0F only + u32 ret = NULL; + if(val == 1){ + ret = PROC9 + (0x080282F8 - P9_ADDR); + } + else if(val == 2){ + ret = PROC9 + (0x0807877E - P9_ADDR); + } + else if(val == 3){ + ret = PROC9 + (0x080787BE - P9_ADDR); + } + return ret; +} + +u32 sigPatch(u8 val, u32 kver){ + u32 ret = NULL; + switch(kver){ + case 0x04: + ret = val == 1 ? + PROC9 + (0x08063C28 - P9_ADDR) : + PROC9 + (0x0805E2D4 - P9_ADDR); + break; + case 0x0C: + ret = val == 1 ? + 0 : + 0; //TODO: find + break; + case 0x0F: + ret = val == 1 ? + PROC9 + (0x08063374 - P9_ADDR) : + PROC9 + (0x0805D498 - P9_ADDR); + break; + } + return ret; +} \ No newline at end of file diff --git a/source/patches.h b/source/patches.h index eb7a979..72600d1 100644 --- a/source/patches.h +++ b/source/patches.h @@ -8,56 +8,26 @@ #include "types.h" -#define FIRM 0x24000000 -#define KERNEL9 (FIRM + 0x66A00) -#define PROC9 (FIRM + 0x7D700) +/************************************************** +* Patches +**************************************************/ +u8 mpu[0x2C]; +u8 eh1[0x14]; +u8 eh2[0x0A]; +u8 eh3[0x0A]; +u8 p1[2]; +u8 p2[4]; +u8 th1[4]; +u8 th2[4]; -#define K9_ADDR 0x08006000 -#define P9_ADDR 0x08028000 - -/* -* Emunand -*/ -//Addresses to patch -u32 emuCode = KERNEL9 + (0x0801A4C0 - K9_ADDR); -u32 mpuCode = KERNEL9 + (0x0801B3D4 - K9_ADDR); -u32 emuHook2 = PROC9 + (0x080282F8 - P9_ADDR); -u32 emuHook3 = PROC9 + (0x0807877E - P9_ADDR); -u32 emuHook4 = PROC9 + (0x080787BE - P9_ADDR); -//Patches -u8 mpu[0x2C] = { //MPU shit - 0x03, 0x00, 0x36, 0x00, 0x00, 0x00, 0x10, 0x10, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x36, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x01, 0x01, 0x03, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x08, - 0x01, 0x01, 0x01, 0x01, 0x03, 0x06, 0x1C, 0x00, 0x00, 0x00, 0x02, 0x08 - }; -u8 eh2[0x14] = { //Sets Slot0x25KeyX - 0x03, 0x4A, 0x05, 0x21, 0x25, 0x20, 0x2F, 0xF0, 0xAB, 0xF8, 0x37, 0xF0, 0x6F, 0xFB, 0x70, 0xBD, - 0xC8, 0xA6, 0x01, 0x08 - }; -u8 eh3[0x0A] = {0x01, 0x4C, 0x20, 0x47, 0x00, 0x00, 0xC0, 0xA4, 0x01, 0x08}; //Branch to emunand write function -u8 eh4[0x0A] = {0x01, 0x4C, 0x20, 0x47, 0x00, 0x00, 0xB0, 0xA5, 0x01, 0x08}; //Branch to emunand read function - - -/* -* Sig checks -*/ -//Addresses to patch -u32 patch1 = PROC9 + (0x08063374 - P9_ADDR); -u32 patch2 = PROC9 + (0x0805D498 - P9_ADDR); -//Patches -u8 p1[2] = {0x00, 0x20}; -u8 p2[4] = {0x00, 0x20, 0x70, 0x47}; - - -/* -* Arm9 thread -*/ -//Addresses to patch -u32 threadCode = KERNEL9 + (0x0801A6E0 - K9_ADDR); -u32 threadHook1 = PROC9 + (0x080860B0 - P9_ADDR); -u32 threadHook2 = PROC9 + (0x080860E4 - P9_ADDR); -//Patches -u8 th1[4] = {0x2C, 0xF0, 0x9F, 0xE5}; //ldr pc, =0x080860E4 -u8 th2[4] = {0xE0, 0xA6, 0x01, 0x08}; //0x080860E4 +/************************************************** +* Functions +**************************************************/ +u32 emuCode(void); +u32 mpuCode(u32 kver); +u32 threadCode(u32 kver); +u32 threadHook(u8 val, u32 kver); +u32 emuHook(u8 val); +u32 sigPatch(u8 val, u32 kver); #endif \ No newline at end of file diff --git a/thread/Makefile b/thread/Makefile index 34ffc88..9ea9a0b 100644 --- a/thread/Makefile +++ b/thread/Makefile @@ -9,7 +9,7 @@ CFLAGS=$(SFLAGS) -std=c99 all: $(CC) -g source/thread.c source/lib.c $(CFLAGS) - $(CC) -g source/_start.s source/FS.S -I source $(SFLAGS) + $(CC) -g source/_start.s source/FS.s -I source $(SFLAGS) $(CC) -nostdlib -T 3ds.ld _start.o thread.o lib.o FS.o $(OBJCOPY) -O binary a.out arm9.bin rm -f *.o *.out diff --git a/thread/source/FS.h b/thread/source/FS.h index 21ae8d3..d7d9fcc 100644 --- a/thread/source/FS.h +++ b/thread/source/FS.h @@ -1,3 +1,9 @@ +/* +* FS.h +* by Reisyukaku +* Copyright (c) 2015 All Rights Reserved +*/ + #ifndef FS_H #define FS_H #include diff --git a/thread/source/FS.s b/thread/source/FS.s index 94a2bbb..e3f2843 100644 --- a/thread/source/FS.s +++ b/thread/source/FS.s @@ -1,3 +1,9 @@ +# +# FS.s +# by Reisyukaku +# Copyright (c) 2015 All Rights Reserved +#/ + .text .thumb diff --git a/thread/source/thread.c b/thread/source/thread.c index 0f6ee1d..ab94ed4 100644 --- a/thread/source/thread.c +++ b/thread/source/thread.c @@ -1,6 +1,7 @@ /* * thread.c * by Reisyukaku +* Copyright (c) 2015 All Rights Reserved */ #include