Added crypto libs, tons of code refactoring to support other firms, other minor stability issues handled.
This commit is contained in:
parent
9989554994
commit
b914674325
@ -28,7 +28,7 @@ Pre-compiled version can still be found on my [pastebin](http://pastebin.com/c5A
|
|||||||
|
|
||||||
**Credits:**
|
**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.
|
3DBREW for saving me plenty of reverse engineering time.
|
||||||
|
|
||||||
|
402
source/crypto.c
Normal file
402
source/crypto.c
Normal 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
138
source/crypto.h
Normal 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*/
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
void clearScreen(void){
|
void clearScreen(void){
|
||||||
memset(fb->top_left, 0, 0x38400);
|
memset(fb->top_left, 0, 0x38400);
|
||||||
|
@ -7,61 +7,76 @@
|
|||||||
#include "firm.h"
|
#include "firm.h"
|
||||||
#include "patches.h"
|
#include "patches.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "types.h"
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "emunand.h"
|
#include "emunand.h"
|
||||||
|
#include "crypto.h"
|
||||||
|
|
||||||
firmHeader *firmLocation = (firmHeader *)0x24000000;
|
firmHeader *firmLocation = (firmHeader *)0x24000000;
|
||||||
const u32 firmSize = 0xF1000;
|
const u32 firmSize = 0xF1000;
|
||||||
firmSectionHeader *section;
|
firmSectionHeader *section;
|
||||||
u32 emuOffset = 0;
|
u32 emuOffset = 0;
|
||||||
u32 emuHeader = 0;
|
u32 emuHeader = 0;
|
||||||
|
u32 kversion = 0;
|
||||||
|
|
||||||
void loadFirm(void){
|
//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
|
//Read FIRM from SD card and write to FCRAM
|
||||||
fileRead((u8*)firmLocation, "/rei/firmware.bin", firmSize);
|
fileRead((u8*)firmLocation, "/rei/firmware.bin", firmSize);
|
||||||
section = firmLocation->section;
|
section = firmLocation->section;
|
||||||
|
kversion = 0x0F; //TODO: make this not hard coded
|
||||||
|
loadEmu();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadSys(void){
|
//Nand redirection
|
||||||
memcpy((u8*)mpuCode, mpu, sizeof(mpu));
|
|
||||||
}
|
|
||||||
|
|
||||||
void loadEmu(void){
|
void loadEmu(void){
|
||||||
fileRead((u8*)emuCode, "/rei/emunand/emunand.bin", 0);
|
|
||||||
u32 *pos_offset = memsearch((u8*)emuCode, "NAND", 0x218, 4);
|
//Read emunand code from SD
|
||||||
u32 *pos_header = memsearch((u8*)emuCode, "NCSD", 0x218, 4);
|
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_offset, (void *)emuOffset, 4);
|
||||||
memcpy((void *)pos_header, (void *)emuHeader, 4);
|
memcpy((void *)pos_header, (void *)emuHeader, 4);
|
||||||
|
|
||||||
//Add emunand hooks
|
//Add emunand hooks
|
||||||
memcpy((u8*)mpuCode, mpu, sizeof(mpu));
|
memcpy((u8*)emuHook(1), eh1, sizeof(eh1));
|
||||||
memcpy((u8*)emuHook2, eh2, sizeof(eh2));
|
memcpy((u8*)emuHook(2), eh2, sizeof(eh2));
|
||||||
memcpy((u8*)emuHook3, eh3, sizeof(eh3));
|
memcpy((u8*)emuHook(3), eh3, sizeof(eh3));
|
||||||
memcpy((u8*)emuHook4, eh4, sizeof(eh4));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void patchFirm(void){
|
//Patches
|
||||||
|
void patchFirm(){
|
||||||
|
|
||||||
//Part1: Get Emunand
|
//Part1: Set MPU for payload area
|
||||||
if(getEmunand(&emuOffset, &emuHeader) == 1)
|
memcpy((u8*)mpuCode(kversion), mpu, sizeof(mpu));
|
||||||
loadEmu();
|
|
||||||
else
|
|
||||||
loadSys();
|
|
||||||
|
|
||||||
//Part2: Disable signature checks
|
//Part2: Disable signature checks
|
||||||
memcpy((u8*)patch1, p1, sizeof(p1));
|
memcpy((u8*)sigPatch(1, kversion), p1, sizeof(p1));
|
||||||
memcpy((u8*)patch2, p2, sizeof(p2));
|
memcpy((u8*)sigPatch(2, kversion), p2, sizeof(p2));
|
||||||
|
|
||||||
//Part3: Create arm9 thread
|
//Part3: Create arm9 thread
|
||||||
fileRead((u8*)threadCode, "/rei/thread/arm9.bin", 0);
|
fileRead((u8*)threadCode(kversion), "/rei/thread/arm9.bin", 0);
|
||||||
memcpy((u8*)threadHook1, th1, sizeof(th1));
|
if(kversion == 0x0F){ //TODO: 0F only untill i can figure out why the hell this doesnt work on sysnand anymore.
|
||||||
memcpy((u8*)threadHook2, th2, sizeof(th2));
|
memcpy((u8*)threadHook(1, kversion), th1, sizeof(th1));
|
||||||
|
memcpy((u8*)threadHook(2, kversion), th2, sizeof(th2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Firmlaunchhax
|
||||||
void launchFirm(void){
|
void launchFirm(void){
|
||||||
//Set MPU
|
|
||||||
|
|
||||||
|
//Set MPU
|
||||||
__asm__ (
|
__asm__ (
|
||||||
"msr cpsr_c, #0xDF\n\t" //Set system mode, disable interrupts
|
"msr cpsr_c, #0xDF\n\t" //Set system mode, disable interrupts
|
||||||
"ldr r0, =0x10000035\n\t" //Memory area 0x10000000-0x18000000, enabled, 128MB
|
"ldr r0, =0x10000035\n\t" //Memory area 0x10000000-0x18000000, enabled, 128MB
|
||||||
|
@ -6,9 +6,10 @@
|
|||||||
#ifndef FIRM_INC
|
#ifndef FIRM_INC
|
||||||
#define FIRM_INC
|
#define FIRM_INC
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
void loadSplash(void);
|
void loadSplash(void);
|
||||||
void loadFirm(void);
|
void loadFirm(int mode);
|
||||||
void loadSys(void);
|
|
||||||
void loadEmu(void);
|
void loadEmu(void);
|
||||||
void patchFirm(void);
|
void patchFirm(void);
|
||||||
void launchFirm(void);
|
void launchFirm(void);
|
||||||
|
@ -10,11 +10,16 @@
|
|||||||
#include "firm.h"
|
#include "firm.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
|
||||||
|
int mode = 1;
|
||||||
|
|
||||||
int main(){
|
int main(){
|
||||||
mountSD();
|
mountSD();
|
||||||
loadSplash();
|
loadSplash();
|
||||||
while(((~*(unsigned *)0x10146000) & 0xFFF) == (1 << 3) ? 0 : 1); //Press start to boot
|
while(1){
|
||||||
loadFirm();
|
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();
|
patchFirm();
|
||||||
launchFirm();
|
launchFirm();
|
||||||
return 0;
|
return 0;
|
||||||
|
135
source/patches.c
Normal file
135
source/patches.c
Normal 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;
|
||||||
|
}
|
@ -8,56 +8,26 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define FIRM 0x24000000
|
/**************************************************
|
||||||
#define KERNEL9 (FIRM + 0x66A00)
|
* Patches
|
||||||
#define PROC9 (FIRM + 0x7D700)
|
**************************************************/
|
||||||
|
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
|
* Functions
|
||||||
|
**************************************************/
|
||||||
/*
|
u32 emuCode(void);
|
||||||
* Emunand
|
u32 mpuCode(u32 kver);
|
||||||
*/
|
u32 threadCode(u32 kver);
|
||||||
//Addresses to patch
|
u32 threadHook(u8 val, u32 kver);
|
||||||
u32 emuCode = KERNEL9 + (0x0801A4C0 - K9_ADDR);
|
u32 emuHook(u8 val);
|
||||||
u32 mpuCode = KERNEL9 + (0x0801B3D4 - K9_ADDR);
|
u32 sigPatch(u8 val, u32 kver);
|
||||||
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
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -9,7 +9,7 @@ CFLAGS=$(SFLAGS) -std=c99
|
|||||||
|
|
||||||
all:
|
all:
|
||||||
$(CC) -g source/thread.c source/lib.c $(CFLAGS)
|
$(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
|
$(CC) -nostdlib -T 3ds.ld _start.o thread.o lib.o FS.o
|
||||||
$(OBJCOPY) -O binary a.out arm9.bin
|
$(OBJCOPY) -O binary a.out arm9.bin
|
||||||
rm -f *.o *.out
|
rm -f *.o *.out
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* FS.h
|
||||||
|
* by Reisyukaku
|
||||||
|
* Copyright (c) 2015 All Rights Reserved
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef FS_H
|
#ifndef FS_H
|
||||||
#define FS_H
|
#define FS_H
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
#
|
||||||
|
# FS.s
|
||||||
|
# by Reisyukaku
|
||||||
|
# Copyright (c) 2015 All Rights Reserved
|
||||||
|
#/
|
||||||
|
|
||||||
.text
|
.text
|
||||||
|
|
||||||
.thumb
|
.thumb
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* thread.c
|
* thread.c
|
||||||
* by Reisyukaku
|
* by Reisyukaku
|
||||||
|
* Copyright (c) 2015 All Rights Reserved
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
Reference in New Issue
Block a user