9.6+ emunand!
This commit is contained in:
parent
b914674325
commit
1f0a8f692a
@ -1,5 +1,5 @@
|
|||||||
# ReiNand
|
# ReiNand
|
||||||
3DS CFW for N3DS
|
The original open source N3DS CFW!
|
||||||
|
|
||||||
|
|
||||||
**Compiling:**
|
**Compiling:**
|
||||||
|
@ -1,155 +1,50 @@
|
|||||||
.nds
|
.nds
|
||||||
|
|
||||||
sdmmc equ 0x80D86F0
|
sdmmc equ 0x080D86F0
|
||||||
sdmmc_unk1 equ 0x080788C0
|
|
||||||
aes_unk equ 0x0805F9E4
|
|
||||||
aes_setkey equ 0x08057458
|
|
||||||
sdmmc_unk2 equ 0x080786A0
|
|
||||||
sdmmc_unk0 equ 0x08062890
|
|
||||||
|
|
||||||
.create "emunand.bin", 0x0801A4C0
|
.create "emunand.bin", 0x0801A4C0
|
||||||
.org 0x0801A4C0
|
.org 0x0801A4C0
|
||||||
.arm
|
.arm
|
||||||
EMU_WRITE:
|
nand_sd:
|
||||||
stmfd sp!, {r0-r3}
|
; Original code that still needs to be executed.
|
||||||
mov r3, r0
|
mov r4, r0
|
||||||
ldr r1, =orig_sector
|
mov r5, r1
|
||||||
ldr r2, [r3,#4]
|
mov r7, r2
|
||||||
str r2, [r1,#4]
|
mov r6, r3
|
||||||
ldr r0, =sdmmc
|
; End.
|
||||||
cmp r2, r0
|
|
||||||
ldr r2, [r3,#8]
|
|
||||||
str r2, [r1]
|
|
||||||
beq @@orig_code
|
|
||||||
ldr r1, =sdmmc
|
|
||||||
str r1, [r3,#4]
|
|
||||||
cmp r2, #0
|
|
||||||
ldr r0, =nand_offset
|
|
||||||
ldrne r0, [r0]
|
|
||||||
addne r0, r2
|
|
||||||
ldreq r0, [r0, #(ncsd_header_offset - nand_offset)]
|
|
||||||
str r0, [r3,#8]
|
|
||||||
@@orig_code:
|
|
||||||
ldmfd sp!, {r0-r3}
|
|
||||||
movs r4, r0
|
|
||||||
movs r5, r1
|
|
||||||
movs r7, r2
|
|
||||||
movs r6, r3
|
|
||||||
movs r0, r1, lsl#23
|
|
||||||
beq loc_801a534
|
|
||||||
stmfd sp!, {r4}
|
|
||||||
ldr r4, =(sdmmc_unk0 + 1)
|
|
||||||
blx r4
|
|
||||||
ldmfd sp!, {r4}
|
|
||||||
loc_801a534:
|
|
||||||
ldr r0, [r4,#4]
|
|
||||||
ldr r1, [r0]
|
|
||||||
ldr r1, [r1,#0x18]
|
|
||||||
blx r1
|
|
||||||
ldr r1, [r4,#4]
|
|
||||||
movs r3, r0
|
|
||||||
ldr r0, [r1,#0x20]
|
|
||||||
movs r2, r5, lsr#9
|
|
||||||
mov r12, r0
|
|
||||||
ldr r0, [r4,#8]
|
|
||||||
str r7, [sp,#4]
|
|
||||||
adds r0, r0, r2
|
|
||||||
cmp r1, #0
|
|
||||||
str r6, [sp,#8]
|
|
||||||
str r0, [sp]
|
|
||||||
beq loc_801a578
|
|
||||||
adds r1, r1, #8
|
|
||||||
loc_801a578:
|
|
||||||
movs r2, r4
|
|
||||||
adds r2, r2, #0xc
|
|
||||||
mov r0, r12
|
|
||||||
ldr r5, =(sdmmc_unk1 + 1) ; called by the original function
|
|
||||||
blx r5
|
|
||||||
stmfd sp!, {r0-r3}
|
|
||||||
ldr r2, =orig_sector
|
|
||||||
ldr r1, [r2]
|
|
||||||
str r1, [r4,#8]
|
|
||||||
ldr r1, [r2,#4]
|
|
||||||
str r1, [r4,#4]
|
|
||||||
ldmfd sp!, {r0-r3}
|
|
||||||
ldmfd sp!, {r1-r7,lr}
|
|
||||||
bx lr
|
|
||||||
|
|
||||||
EMU_READ:
|
; If we're already trying to access the SD, return.
|
||||||
stmfd sp!, {r0-r3}
|
ldr r2, [r0, #4]
|
||||||
mov r3, r0
|
|
||||||
ldr r1, =orig_sector
|
|
||||||
ldr r2, [r3,#4]
|
|
||||||
str r2, [r1,#4]
|
|
||||||
ldr r0, =sdmmc
|
|
||||||
cmp r2, r0
|
|
||||||
ldr r2, [r3,#8]
|
|
||||||
str r2, [r1]
|
|
||||||
beq @@orig_code
|
|
||||||
ldr r1, =sdmmc
|
ldr r1, =sdmmc
|
||||||
str r1, [r3,#4]
|
cmp r2, r1
|
||||||
cmp r2, #0
|
beq nand_sd_ret
|
||||||
ldr r0, =nand_offset
|
|
||||||
ldrne r0, [r0]
|
|
||||||
addne r0, r2
|
|
||||||
ldreq r0, [r0, #(ncsd_header_offset - nand_offset)]
|
|
||||||
str r0, [r3,#8]
|
|
||||||
@@orig_code:
|
|
||||||
ldmfd sp!, {r0-r3}
|
|
||||||
movs r4, r0
|
|
||||||
movs r5, r1
|
|
||||||
movs r7, r2
|
|
||||||
movs r6, r3
|
|
||||||
movs r0, r1, lsl#23
|
|
||||||
beq loc_801a624
|
|
||||||
stmfd sp!, {r4}
|
|
||||||
ldr r4, =(sdmmc_unk0 + 1)
|
|
||||||
blx r4
|
|
||||||
ldmfd sp!, {r4}
|
|
||||||
loc_801a624:
|
|
||||||
ldr r0, [r4,#4]
|
|
||||||
ldr r1, [r0]
|
|
||||||
ldr r1, [r1,#0x18]
|
|
||||||
blx r1
|
|
||||||
ldr r1, [r4,#4]
|
|
||||||
movs r3, r0
|
|
||||||
ldr r0, [r1,#0x20]
|
|
||||||
movs r2, r5, lsr#9
|
|
||||||
mov r12, r0
|
|
||||||
ldr r0, [r4,#8]
|
|
||||||
str r7, [sp,#4]
|
|
||||||
adds r0, r0, r2
|
|
||||||
cmp r1, #0
|
|
||||||
str r6, [sp,#8]
|
|
||||||
str r0, [sp]
|
|
||||||
beq loc_801a668
|
|
||||||
adds r1, r1, #8
|
|
||||||
loc_801a668:
|
|
||||||
movs r2, r4
|
|
||||||
adds r2, r2, #0xC
|
|
||||||
mov r0, r12
|
|
||||||
ldr r5, =(sdmmc_unk2 + 1)
|
|
||||||
blx r5
|
|
||||||
stmfd sp!, {r0-r3}
|
|
||||||
ldr r2, =orig_sector
|
|
||||||
ldr r1, [r2]
|
|
||||||
str r1, [r4,#8]
|
|
||||||
ldr r1, [r2,#4]
|
|
||||||
str r1, [r4,#4]
|
|
||||||
ldmfd sp!, {r0-r3}
|
|
||||||
ldmfd sp!, {r1-r7,lr}
|
|
||||||
bx lr
|
|
||||||
|
|
||||||
|
str r1, [r0, #4] ; Set object to be SD
|
||||||
|
ldr r2, [r0, #8] ; Get sector to read
|
||||||
|
cmp r2, #0 ; For GW compatibility, see if we're trying to read the ncsd header (sector 0)
|
||||||
|
|
||||||
|
ldr r3, =nand_offset
|
||||||
|
ldr r3, [r3]
|
||||||
|
add r2, r3 ; Add the offset to the NAND in the SD.
|
||||||
|
|
||||||
|
ldreq r3, =ncsd_header_offset
|
||||||
|
ldreq r3, [r3]
|
||||||
|
addeq r2, r3 ; If we're reading the ncsd header, add the offset of that sector.
|
||||||
|
|
||||||
|
str r2, [r0, #8] ; Store sector to read
|
||||||
|
|
||||||
|
nand_sd_ret:
|
||||||
|
; Restore registers.
|
||||||
|
mov r1, r5
|
||||||
|
mov r2, r7
|
||||||
|
mov r3, r6
|
||||||
|
|
||||||
|
; Return 4 bytes behind where we got called,
|
||||||
|
; due to the offset of this function being stored there.
|
||||||
|
mov r0, lr
|
||||||
|
add r0, #4
|
||||||
|
bx r0
|
||||||
.pool
|
.pool
|
||||||
orig_sector: .word 0x00000000
|
|
||||||
orig_ptr: .word 0x00000000
|
|
||||||
nand_offset: .ascii "NAND" ; for rednand this should be 1
|
nand_offset: .ascii "NAND" ; for rednand this should be 1
|
||||||
ncsd_header_offset: .ascii "NCSD" ; depends on nand manufacturer + emunand type (GW/RED)
|
ncsd_header_offset: .ascii "NCSD" ; depends on nand manufacturer + emunand type (GW/RED)
|
||||||
;ncsd_header_offset: .word 0x1D7800
|
|
||||||
;ncsd_header_offset: .word 0x1DD000
|
|
||||||
slot0x25keyX:
|
|
||||||
.word 0xABD8E7CE
|
|
||||||
.word 0xAE0DC030
|
|
||||||
.word 0xE3F50E85
|
|
||||||
.word 0xF35AAC82
|
|
||||||
.close
|
.close
|
||||||
|
@ -60,7 +60,6 @@ __asm__\
|
|||||||
void aes_setkey(u8 keyslot, const void* key, u32 keyType, u32 mode)
|
void aes_setkey(u8 keyslot, const void* key, u32 keyType, u32 mode)
|
||||||
{
|
{
|
||||||
if(keyslot <= 0x03) return; // Ignore TWL keys for now
|
if(keyslot <= 0x03) return; // Ignore TWL keys for now
|
||||||
|
|
||||||
u32* key32 = (u32*)key;
|
u32* key32 = (u32*)key;
|
||||||
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
|
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
|
||||||
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
|
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
|
||||||
@ -376,20 +375,26 @@ void nandFirm0(u8 *outbuf, const u32 size){
|
|||||||
aes(outbuf, outbuf, size / AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes(outbuf, outbuf, size / AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Decrypt the arm9 binary on N3DS firm
|
//Emulates the Arm9loader process
|
||||||
void decryptArm9Bin(void *armHdr, u32 kversion){
|
//9.5.0 = 0x0F
|
||||||
|
//9.6.0 = 0x18
|
||||||
|
void arm9loader(void *armHdr, u32 kversion){
|
||||||
|
//Set Nand key#2 here (decrypted from 0x12C10)
|
||||||
|
u8 key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
||||||
|
|
||||||
u8 keyX[0x10];
|
u8 keyX[0x10];
|
||||||
u8 keyY[0x10];
|
u8 keyY[0x10];
|
||||||
u8 CTR[0x10];
|
u8 CTR[0x10];
|
||||||
u32 slot = (kversion == 0x0F ? 0x16 : 0x15);
|
u32 slot = (kversion >= 0x0F ? 0x16 : 0x15);
|
||||||
|
|
||||||
|
//Setupkeys needed for arm9bin decryption
|
||||||
memcpy(keyY, armHdr+0x10, 0x10);
|
memcpy(keyY, armHdr+0x10, 0x10);
|
||||||
memcpy(CTR, armHdr+0x20, 0x10);
|
memcpy(CTR, armHdr+0x20, 0x10);
|
||||||
u32 size = atoi(armHdr+0x30);
|
u32 size = atoi(armHdr+0x30);
|
||||||
|
|
||||||
|
if(kversion >= 0x0F){
|
||||||
|
if(kversion >= 0x18) aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
aes_use_keyslot(0x11);
|
aes_use_keyslot(0x11);
|
||||||
|
|
||||||
if(kversion == 0x0F){
|
|
||||||
aes(keyX, armHdr+0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
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, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
}
|
}
|
||||||
@ -400,3 +405,65 @@ void decryptArm9Bin(void *armHdr, u32 kversion){
|
|||||||
|
|
||||||
aes(armHdr+0x800, armHdr+0x800, size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes(armHdr+0x800, armHdr+0x800, size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setKeys(kversion){
|
||||||
|
u8 key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
||||||
|
//Initialze keys
|
||||||
|
if(kversion >= 0x18){
|
||||||
|
|
||||||
|
u8 keyX18[16] = {0x82, 0xE9, 0xC9, 0xBE, 0xBF, 0xB8, 0xBD, 0xB8, 0x75, 0xEC, 0xC0, 0xA0, 0x7D, 0x47, 0x43, 0x74};
|
||||||
|
u8 keyX19[16] = {0xF5, 0x36, 0x7F, 0xCE, 0x73, 0x14, 0x2E, 0x66, 0xED, 0x13, 0x91, 0x79, 0x14, 0xB7, 0xF2, 0xEF};
|
||||||
|
u8 keyX1A[16] = {0xEA, 0xBA, 0x98, 0x4C, 0x9C, 0xB7, 0x66, 0xD4, 0xA3, 0xA7, 0xE9, 0x74, 0xE2, 0xE7, 0x13, 0xA3};
|
||||||
|
u8 keyX1B[16] = {0x45, 0xAD, 0x04, 0x95, 0x39, 0x92, 0xC7, 0xC8, 0x93, 0x72, 0x4A, 0x9A, 0x7B, 0xCE, 0x61, 0x82};
|
||||||
|
u8 keyX1C[16] = {0xC3, 0x83, 0x0F, 0x81, 0x56, 0xE3, 0x54, 0x3B, 0x72, 0x3F, 0x0B, 0xC0, 0x46, 0x74, 0x1E, 0x8F};
|
||||||
|
u8 keyX1D[16] = {0xD6, 0xB3, 0x8B, 0xC7, 0x59, 0x41, 0x75, 0x96, 0xD6, 0x19, 0xD6, 0x02, 0x9D, 0x13, 0xE0, 0xD8};
|
||||||
|
u8 keyX1E[16] = {0xBB, 0x62, 0x3A, 0x97, 0xDD, 0xD7, 0x93, 0xD7, 0x57, 0xC4, 0x10, 0x4B, 0x8D, 0x9F, 0xB9, 0x69};
|
||||||
|
u8 keyX1F[16] = {0x4C, 0x28, 0xEC, 0x6E, 0xFF, 0xA3, 0xC2, 0x36, 0x46, 0x07, 0x8B, 0xBA, 0x35, 0x0C, 0x79, 0x95};
|
||||||
|
aes_setkey(0x18, keyX18, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x19, keyX19, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x1A, keyX19, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x1B, keyX1B, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x1C, keyX19, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x1D, keyX19, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x1E, keyX19, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x1F, keyX19, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
//data at armHdr+0x8A804 (its not in FCRAM for whatever reason)
|
||||||
|
u8 encryptedData1[0x10] = {
|
||||||
|
0xA4, 0x8D, 0xE4, 0xF1, 0x0B, 0x36, 0x44, 0xAA, 0x90, 0x31, 0x28, 0xFF,
|
||||||
|
0x4D, 0xCA, 0x76, 0xDF
|
||||||
|
};
|
||||||
|
//data at armHdr+0x8A814 (its not in FCRAM for whatever reason)
|
||||||
|
u8 encryptedData2[0x10] = {
|
||||||
|
0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D,
|
||||||
|
0x9D, 0x2A, 0x21, 0x98
|
||||||
|
};
|
||||||
|
|
||||||
|
//Set key 0x18 keyX
|
||||||
|
u8 keyX18[0x10];
|
||||||
|
aes(keyX18, encryptedData1, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||||
|
aes_setkey(0x18, keyX18, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
|
//Set key 0x11 normalkey
|
||||||
|
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_use_keyslot(0x11);
|
||||||
|
|
||||||
|
//Set keys 0x19..0x1F keyXs
|
||||||
|
u8 keyTemp[0x10];
|
||||||
|
u8 keys[7][0x10];
|
||||||
|
aes_use_keyslot(0x11);
|
||||||
|
int i; for(i = 0; i < 7; i++) {
|
||||||
|
aes(keyTemp, encryptedData2, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||||
|
encryptedData2[0x0F]++;
|
||||||
|
memcpy(keys[i], keyTemp, 0x10);
|
||||||
|
}
|
||||||
|
aes_setkey(0x19, keys[0], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x1A, keys[1], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x1B, keys[2], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x1C, keys[3], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x1D, keys[4], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x1E, keys[5], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x1F, keys[6], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);*/
|
||||||
|
}
|
||||||
|
}
|
@ -133,6 +133,7 @@ int rsa_verify(const void* data, u32 size, const void* sig, u32 mode);
|
|||||||
//NAND/FIRM stuff
|
//NAND/FIRM stuff
|
||||||
void getNandCTR(u8 *buf);
|
void getNandCTR(u8 *buf);
|
||||||
void nandFirm0(u8 *outbuf, const u32 size);
|
void nandFirm0(u8 *outbuf, const u32 size);
|
||||||
void decryptArm9Bin(void *armHdr, u32 kversion);
|
void arm9loader(void *armHdr, u32 kversion);
|
||||||
|
void setKeys(kversion);
|
||||||
|
|
||||||
#endif /*__CRYPTO_H*/
|
#endif /*__CRYPTO_H*/
|
||||||
|
@ -26,14 +26,15 @@ void loadFirm(int mode){
|
|||||||
nandFirm0((u8*)firmLocation, firmSize);
|
nandFirm0((u8*)firmLocation, firmSize);
|
||||||
section = firmLocation->section;
|
section = firmLocation->section;
|
||||||
kversion = 0x04; //TODO: make this not hard coded
|
kversion = 0x04; //TODO: make this not hard coded
|
||||||
decryptArm9Bin((u8*)firmLocation + section[2].offset, kversion);
|
arm9loader((u8*)firmLocation + section[2].offset, kversion);
|
||||||
}
|
}
|
||||||
//Emunand mode
|
//Emunand mode
|
||||||
else{
|
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
|
kversion = 0x18; //TODO: make this not hard coded
|
||||||
|
arm9loader((u8*)firmLocation + section[2].offset, kversion);
|
||||||
loadEmu();
|
loadEmu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,7 +43,7 @@ void loadFirm(int mode){
|
|||||||
void loadEmu(void){
|
void loadEmu(void){
|
||||||
|
|
||||||
//Read emunand code from SD
|
//Read emunand code from SD
|
||||||
u32 code = emuCode();
|
u32 code = emuCode(kversion);
|
||||||
fileRead((u8*)code, "/rei/emunand/emunand.bin", 0);
|
fileRead((u8*)code, "/rei/emunand/emunand.bin", 0);
|
||||||
u32 *pos_offset = memsearch((u8*)code, "NAND", 0x218, 4);
|
u32 *pos_offset = memsearch((u8*)code, "NAND", 0x218, 4);
|
||||||
u32 *pos_header = memsearch((u8*)code, "NCSD", 0x218, 4);
|
u32 *pos_header = memsearch((u8*)code, "NCSD", 0x218, 4);
|
||||||
@ -50,9 +51,8 @@ void loadEmu(void){
|
|||||||
memcpy((void *)pos_header, (void *)emuHeader, 4);
|
memcpy((void *)pos_header, (void *)emuHeader, 4);
|
||||||
|
|
||||||
//Add emunand hooks
|
//Add emunand hooks
|
||||||
memcpy((u8*)emuHook(1), eh1, sizeof(eh1));
|
memcpy((u8*)emuHook(1, kversion), nandRedir, sizeof(nandRedir));
|
||||||
memcpy((u8*)emuHook(2), eh2, sizeof(eh2));
|
memcpy((u8*)emuHook(2, kversion), nandRedir, sizeof(nandRedir));
|
||||||
memcpy((u8*)emuHook(3), eh3, sizeof(eh3));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Patches
|
//Patches
|
||||||
@ -62,12 +62,12 @@ void patchFirm(){
|
|||||||
memcpy((u8*)mpuCode(kversion), mpu, sizeof(mpu));
|
memcpy((u8*)mpuCode(kversion), mpu, sizeof(mpu));
|
||||||
|
|
||||||
//Part2: Disable signature checks
|
//Part2: Disable signature checks
|
||||||
memcpy((u8*)sigPatch(1, kversion), p1, sizeof(p1));
|
memcpy((u8*)sigPatch(1, kversion), sigPat1, sizeof(sigPat1));
|
||||||
memcpy((u8*)sigPatch(2, kversion), p2, sizeof(p2));
|
memcpy((u8*)sigPatch(2, kversion), sigPat2, sizeof(sigPat2));
|
||||||
|
|
||||||
//Part3: Create arm9 thread
|
//Part3: Create arm9 thread
|
||||||
fileRead((u8*)threadCode(kversion), "/rei/thread/arm9.bin", 0);
|
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.
|
if(kversion == 0x18){ //TODO: 0x18 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(1, kversion), th1, sizeof(th1));
|
||||||
memcpy((u8*)threadHook(2, kversion), th2, sizeof(th2));
|
memcpy((u8*)threadHook(2, kversion), th2, sizeof(th2));
|
||||||
}
|
}
|
||||||
@ -109,6 +109,9 @@ void launchFirm(void){
|
|||||||
memcpy(section[2].address, (u8*)firmLocation + section[2].offset, section[2].size);
|
memcpy(section[2].address, (u8*)firmLocation + section[2].offset, section[2].size);
|
||||||
*(u32 *)0x1FFFFFF8 = (u32)firmLocation->arm11Entry;
|
*(u32 *)0x1FFFFFF8 = (u32)firmLocation->arm11Entry;
|
||||||
|
|
||||||
|
setKeys(kversion);
|
||||||
|
|
||||||
//Final jump to arm9 binary
|
//Final jump to arm9 binary
|
||||||
((void (*)())0x801B01C)();
|
((void (*)())0x801B01C)();
|
||||||
|
//((void (*)())firmLocation->arm9Entry)();
|
||||||
}
|
}
|
101
source/patches.c
101
source/patches.c
@ -7,8 +7,10 @@
|
|||||||
#include "patches.h"
|
#include "patches.h"
|
||||||
|
|
||||||
#define FIRM 0x24000000
|
#define FIRM 0x24000000
|
||||||
|
|
||||||
#define KERNEL9 (FIRM + 0x66A00)
|
#define KERNEL9 (FIRM + 0x66A00)
|
||||||
#define PROC9 (FIRM + 0x7D700)
|
#define PROC9 (FIRM + 0x7D700)
|
||||||
|
#define v9_6_Offset 0x1600
|
||||||
|
|
||||||
#define K9_ADDR 0x08006000
|
#define K9_ADDR 0x08006000
|
||||||
#define P9_ADDR 0x08028000
|
#define P9_ADDR 0x08028000
|
||||||
@ -25,24 +27,20 @@ u8 mpu[0x2C] = { //MPU shit
|
|||||||
0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x01, 0x01, 0x03, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x08,
|
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
|
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,
|
u8 nandRedir[0x08] = {0x00, 0x4C, 0xA0, 0x47, 0xC0, 0xA4, 0x01, 0x08}; //Branch to emunand function
|
||||||
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
|
* Sig checks
|
||||||
*/
|
*/
|
||||||
u8 p1[2] = {0x00, 0x20};
|
u8 sigPat1[2] = {0x00, 0x20};
|
||||||
u8 p2[4] = {0x00, 0x20, 0x70, 0x47};
|
u8 sigPat2[4] = {0x00, 0x20, 0x70, 0x47};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Arm9 thread
|
* Arm9 thread
|
||||||
*/
|
*/
|
||||||
u8 th1[4] = {0x2C, 0xF0, 0x9F, 0xE5}; //ldr pc, =0x080860E4
|
u8 th1[4] = {0x2C, 0xF0, 0x9F, 0xE5}; //ldr pc, =0x0801A6E0
|
||||||
u8 th2[4] = {0xE0, 0xA6, 0x01, 0x08}; //0x080860E4
|
u8 th2[4] = {0xE0, 0xA6, 0x01, 0x08}; //0x0801A6E0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -50,10 +48,38 @@ u8 th2[4] = {0xE0, 0xA6, 0x01, 0x08}; //0x080860E4
|
|||||||
* Functions
|
* Functions
|
||||||
**************************************************/
|
**************************************************/
|
||||||
|
|
||||||
u32 emuCode(void){ //0F only
|
//Where the emunand code is stored in firm
|
||||||
return KERNEL9 + (0x0801A4C0 - K9_ADDR);
|
u32 emuCode(u32 kver){
|
||||||
|
u32 ret = NULL;
|
||||||
|
switch(kver){
|
||||||
|
case 0x04:
|
||||||
|
case 0x0C:
|
||||||
|
case 0x0F:
|
||||||
|
ret = KERNEL9 + (0x0801A4C0 - K9_ADDR);
|
||||||
|
break;
|
||||||
|
case 0x18:
|
||||||
|
ret = KERNEL9 + v9_6_Offset + (0x0801A4C0 - K9_ADDR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Where thread code is stored in firm
|
||||||
|
u32 threadCode(u32 kver){
|
||||||
|
u32 ret = NULL;
|
||||||
|
switch(kver){
|
||||||
|
case 0x04:
|
||||||
|
case 0x0C:
|
||||||
|
case 0x0F:
|
||||||
|
ret = KERNEL9 + (0x0801A6E0 - K9_ADDR);
|
||||||
|
case 0x18:
|
||||||
|
ret = KERNEL9 + v9_6_Offset + (0x0801A6E0 - K9_ADDR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Area of MPU setting code
|
||||||
u32 mpuCode(u32 kver){
|
u32 mpuCode(u32 kver){
|
||||||
u32 ret = NULL;
|
u32 ret = NULL;
|
||||||
switch(kver){
|
switch(kver){
|
||||||
@ -62,22 +88,14 @@ u32 mpuCode(u32 kver){
|
|||||||
case 0x0F:
|
case 0x0F:
|
||||||
ret = KERNEL9 + (0x0801B3D4 - K9_ADDR);
|
ret = KERNEL9 + (0x0801B3D4 - K9_ADDR);
|
||||||
break;
|
break;
|
||||||
}
|
case 0x18:
|
||||||
return ret;
|
ret = KERNEL9 + v9_6_Offset + (0x0801B3D4 - K9_ADDR);
|
||||||
}
|
|
||||||
|
|
||||||
u32 threadCode(u32 kver){
|
|
||||||
u32 ret = NULL;
|
|
||||||
switch(kver){
|
|
||||||
case 0x04:
|
|
||||||
case 0x0C:
|
|
||||||
case 0x0F:
|
|
||||||
ret = KERNEL9 + (0x0801A6E0 - K9_ADDR);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Offsets to redirect to thread code
|
||||||
u32 threadHook(u8 val, u32 kver){
|
u32 threadHook(u8 val, u32 kver){
|
||||||
u32 ret = NULL;
|
u32 ret = NULL;
|
||||||
switch(kver){
|
switch(kver){
|
||||||
@ -94,24 +112,38 @@ u32 threadHook(u8 val, u32 kver){
|
|||||||
PROC9 + (0x080860B0 - P9_ADDR) :
|
PROC9 + (0x080860B0 - P9_ADDR) :
|
||||||
PROC9 + (0x080860E4 - P9_ADDR);
|
PROC9 + (0x080860E4 - P9_ADDR);
|
||||||
break;
|
break;
|
||||||
|
case 0x18:
|
||||||
|
ret = val == 1 ?
|
||||||
|
PROC9 + v9_6_Offset + (0x08086140 - P9_ADDR) :
|
||||||
|
PROC9 + v9_6_Offset + (0x08086174 - P9_ADDR);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 emuHook(u8 val){ //0F only
|
//Offsets to redirect to Emunand code
|
||||||
|
u32 emuHook(u8 val, u32 kver){ //latest only
|
||||||
u32 ret = NULL;
|
u32 ret = NULL;
|
||||||
if(val == 1){
|
switch(kver){
|
||||||
ret = PROC9 + (0x080282F8 - P9_ADDR);
|
case 0x04:
|
||||||
}
|
//???
|
||||||
else if(val == 2){
|
break;
|
||||||
ret = PROC9 + (0x0807877E - P9_ADDR);
|
case 0x0C:
|
||||||
}
|
//???
|
||||||
else if(val == 3){
|
break;
|
||||||
ret = PROC9 + (0x080787BE - P9_ADDR);
|
case 0x0F:
|
||||||
|
if(val == 1) ret = PROC9 + (0x0807882C - P9_ADDR);
|
||||||
|
else if(val == 2) ret = PROC9 + (0x0807886C - P9_ADDR);
|
||||||
|
break;
|
||||||
|
case 0x18:
|
||||||
|
if(val == 1) ret = PROC9 + v9_6_Offset + (0x0807882C - P9_ADDR);
|
||||||
|
else if(val == 2) ret = PROC9 + v9_6_Offset + (0x0807886C - P9_ADDR);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Offsets to redirect to thread code
|
||||||
u32 sigPatch(u8 val, u32 kver){
|
u32 sigPatch(u8 val, u32 kver){
|
||||||
u32 ret = NULL;
|
u32 ret = NULL;
|
||||||
switch(kver){
|
switch(kver){
|
||||||
@ -130,6 +162,11 @@ u32 sigPatch(u8 val, u32 kver){
|
|||||||
PROC9 + (0x08063374 - P9_ADDR) :
|
PROC9 + (0x08063374 - P9_ADDR) :
|
||||||
PROC9 + (0x0805D498 - P9_ADDR);
|
PROC9 + (0x0805D498 - P9_ADDR);
|
||||||
break;
|
break;
|
||||||
|
case 0x18:
|
||||||
|
ret = val == 1 ?
|
||||||
|
PROC9 + v9_6_Offset + (0x080632B8 - P9_ADDR) :
|
||||||
|
PROC9 + v9_6_Offset + (0x0805D628 - P9_ADDR);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
@ -12,22 +12,20 @@
|
|||||||
* Patches
|
* Patches
|
||||||
**************************************************/
|
**************************************************/
|
||||||
u8 mpu[0x2C];
|
u8 mpu[0x2C];
|
||||||
u8 eh1[0x14];
|
u8 nandRedir[0x08];
|
||||||
u8 eh2[0x0A];
|
u8 sigPat1[2];
|
||||||
u8 eh3[0x0A];
|
u8 sigPat2[4];
|
||||||
u8 p1[2];
|
|
||||||
u8 p2[4];
|
|
||||||
u8 th1[4];
|
u8 th1[4];
|
||||||
u8 th2[4];
|
u8 th2[4];
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
* Functions
|
* Functions
|
||||||
**************************************************/
|
**************************************************/
|
||||||
u32 emuCode(void);
|
u32 emuCode(u32 kver);
|
||||||
u32 mpuCode(u32 kver);
|
u32 mpuCode(u32 kver);
|
||||||
u32 threadCode(u32 kver);
|
u32 threadCode(u32 kver);
|
||||||
u32 threadHook(u8 val, u32 kver);
|
u32 threadHook(u8 val, u32 kver);
|
||||||
u32 emuHook(u8 val);
|
u32 emuHook(u8 val, u32 kver);
|
||||||
u32 sigPatch(u8 val, u32 kver);
|
u32 sigPatch(u8 val, u32 kver);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -11,7 +11,7 @@
|
|||||||
.type fopen9, %function
|
.type fopen9, %function
|
||||||
fopen9:
|
fopen9:
|
||||||
push {r0-r6, lr}
|
push {r0-r6, lr}
|
||||||
ldr r4, =0x0805B015
|
ldr r4, =0x0805B181
|
||||||
blx r4
|
blx r4
|
||||||
pop {r0-r6, pc}
|
pop {r0-r6, pc}
|
||||||
.pool
|
.pool
|
||||||
@ -21,7 +21,7 @@
|
|||||||
.type fwrite9, %function
|
.type fwrite9, %function
|
||||||
fwrite9:
|
fwrite9:
|
||||||
push {r4, lr}
|
push {r4, lr}
|
||||||
ldr r4, =0x0805C379
|
ldr r4, =0x0805C4D1
|
||||||
blx r4
|
blx r4
|
||||||
pop {r4, pc}
|
pop {r4, pc}
|
||||||
.pool
|
.pool
|
||||||
@ -41,7 +41,7 @@
|
|||||||
.type fclose9, %function
|
.type fclose9, %function
|
||||||
fclose9:
|
fclose9:
|
||||||
push {r4, lr}
|
push {r4, lr}
|
||||||
ldr r4, =0x08053C6D
|
ldr r4, =0x08053CF9
|
||||||
blx r4
|
blx r4
|
||||||
pop {r4, pc}
|
pop {r4, pc}
|
||||||
.pool
|
.pool
|
||||||
@ -51,7 +51,7 @@
|
|||||||
.type fsize9, %function
|
.type fsize9, %function
|
||||||
fsize9:
|
fsize9:
|
||||||
push {r4, lr}
|
push {r4, lr}
|
||||||
ldr r4, =0x0805C175
|
ldr r4, =0x0805C2CD
|
||||||
blx r4
|
blx r4
|
||||||
pop {r4, pc}
|
pop {r4, pc}
|
||||||
.pool
|
.pool
|
@ -16,5 +16,5 @@ _start:
|
|||||||
ldr r4, =0x1
|
ldr r4, =0x1
|
||||||
svc 0x8
|
svc 0x8
|
||||||
pop {r0-r12 , lr}
|
pop {r0-r12 , lr}
|
||||||
ldr r0, =0x80CB0A8
|
ldr r0, =0x80CB028
|
||||||
ldr pc, =0x080860B4
|
ldr pc, =0x08086144
|
@ -79,8 +79,7 @@ void thread(void){
|
|||||||
screenShot(BOT_FRAME);
|
screenShot(BOT_FRAME);
|
||||||
}
|
}
|
||||||
if(isPressed(BUTTON_START | BUTTON_X)){
|
if(isPressed(BUTTON_START | BUTTON_X)){
|
||||||
memdump(L"sdmc:/AXIWRAM.bin", AXIWRAM, 0x00080000);
|
memdump(L"sdmc:/BootRom.bin", 0xFFFF0000, 0x8000);
|
||||||
memdump(L"sdmc:/FCRAM.bin", FCRAM, 0x010000000);
|
|
||||||
}
|
}
|
||||||
patches();
|
patches();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user