Added crypto libs, tons of code refactoring to support other firms, other minor stability issues handled.

This commit is contained in:
Reisyukaku 2015-08-21 14:11:23 -04:00
parent 9989554994
commit b914674325
13 changed files with 764 additions and 84 deletions

View File

@ -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.

402
source/crypto.c Normal file
View File

@ -0,0 +1,402 @@
// From http://github.com/b1l1s/ctr
#include "crypto.h"
#include <stddef.h>
#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);
}

138
source/crypto.h Normal file
View File

@ -0,0 +1,138 @@
// From http://github.com/b1l1s/ctr
#ifndef __CRYPTO_H
#define __CRYPTO_H
#include <stdint.h>
#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*/

View File

@ -6,6 +6,7 @@
#include "draw.h"
#include "fs.h"
#include "memory.h"
void clearScreen(void){
memset(fb->top_left, 0, 0x38400);

View File

@ -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
//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

View File

@ -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);

View File

@ -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;

135
source/patches.c Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -1,3 +1,9 @@
/*
* FS.h
* by Reisyukaku
* Copyright (c) 2015 All Rights Reserved
*/
#ifndef FS_H
#define FS_H
#include <stdio.h>

View File

@ -1,3 +1,9 @@
#
# FS.s
# by Reisyukaku
# Copyright (c) 2015 All Rights Reserved
#/
.text
.thumb

View File

@ -1,6 +1,7 @@
/*
* thread.c
* by Reisyukaku
* Copyright (c) 2015 All Rights Reserved
*/
#include <wchar.h>