3DS reverse engineering

Discussion of development of software for any "obsolete" computer or video game system.
naseyuki
Posts: 4
Joined: Wed Feb 13, 2019 6:30 pm

Re: 3DS reverse engineering

Post by naseyuki » Sun Mar 31, 2019 6:37 am

nocash wrote:If there are different firmwares, how are chances to know which version I have (on japanese console without top screen)?
You can check these memory addresses:

Code: Select all

FIRM_VERMAJOR	1FF80063h	1 byte
FIRM_VERMINOR	1FF80062h	1 byte
FIRM_VERREV	  1FF80061h	1 byte
I think it's possible to find this information looking at the firm0 partition in the NAND (0B130000h), but I don't know where.

nocash
Posts: 1061
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Sun Mar 31, 2019 7:37 am

The firm sectors are encrypted, so there is no way to read version info from there without knowing the decryption keys in first place.

Yeah, reading ram locations would work, but I have no idea how to write homebrew code in which file format for 3ds yet (except firm format, which seems to be pretty simple, apart from getting around the encryption issue).

I have some zelda card exploit, but with the japanese language barrier it's no fun to use: Like randomly clicking some icons until zelda pops up, and then randomly clicking some more symbols until something shows up which might be a homebrew file menu, but then not knowing how to write my own homebrew code (or at least knowing how to power off the console properly). That's not so satisfying. Well, I guess my main problem is that I am unwilling to learn how to use the existing exploits and high level tools, and instead want to jump straight into low level coding.

Pokun
Posts: 1237
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: 3DS reverse engineering

Post by Pokun » Sun Mar 31, 2019 3:07 pm

If the Japanese is really that much of a problem we are many people on the forum that are professional or amateur translators and can help you if you post photos.

pirate
Posts: 1
Joined: Mon Apr 01, 2019 2:52 am

Re: 3DS reverse engineering

Post by pirate » Mon Apr 01, 2019 3:00 am

nocash wrote:The firm sectors are encrypted, so there is no way to read version info from there without knowing the decryption keys in first place.

See if this helps
https://pirate.s-ul.eu/6AdyvCX2

It's a spreadsheet with the keys, made by Reisyukaku years ago but recently locked down.
(https://docs.google.com/spreadsheets/d/ ... FisP8/edit)

nocash
Posts: 1061
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Tue Apr 02, 2019 5:50 pm

Not knowing japanese is part of the problem. The other parts are the 3DS boot delays and the whole 3DS GUI in general, I would rather avoid dealing with that, and prefer to patch the console to boot my own code. Hmmmm, translated photos? Knowing how to "click [image] for OK and [image] for Cancel" could be useful, but only when knowing what I am accepting when clicking OK. I guess that would require loads of photos, plus some huge poster-sized neon photos saying "Never click [image] or [image] because that would block all exploits or delete all data". So, no, I don't think that's practicable.

The spreadsheet is nice for verifying that my key generator has put the keys into correct keyslots. Though there seem to be a few bugs in the spreadsheet (I think the normal key in keyslot 38h should be in keyslot 38h only, not also in keyslot 3Ah. And the DSi keyX in keyslot 03h should be console unique). Anyways, the spreadsheet doesn't help on patching eMMC because I don't have OTP dump for generating all the console unique keys.

At the moment, I could see three DIY hacking approaches (or combinations thereof):

Patching firm0 at eMMC offset 0B130000h
For XORing without knowing the AES key: Is there anything known about how many firm0 versions exist? And does somebody know how to get hold of those version(s)?
I think there must be at least two versions (one for Old3DS, one for New3DS). Possibly with about 30 variations for the different firmware updates, and 6 more variants for 6 regions, and possibly 2 more variants for debug/retail? In worst case that would be up to 1440 different versions (2*30*6*2).
I have one decrypted firm0 dump (unfortunately not the one installed on the actual console). That dump contains some zerofilled areas - that would make XORing much easier (if one knows where the zerofilled area is located in each version). But to do that, one would also need to patch the NCSD header with RSA slot 3 sighax signature, and then redirect firm0 it to the zerofilled area.

sighax
The bootrom uses three RSA keys in RSA slot 1,2,3:
- RSA slot 1: For FIRM signature in eMMC
- RSA slot 2: For FIRM signature in WifiFlash/Ntrcard
- RSA slot 3: For NCSD signature in eMMC
So that would require three different sighax signatures (and another three for debug version). Unfortunately, the .bin file download on http://www.sighax.com/ contains only one of those brute-forced signatures (and doesn't even tell which one... probably the retail RSA slot 1 one, as that would be most commonly used).
This tool might be capable of brute-forcing missing signatures: https://github.com/Myriachan/sighax did anybody already do that brute work? I've read that it would take 1 week with a fast GPU (or presumably several months with my own old PC).

Booting from Wifi-Flash (from flash offset 400h)
Wifi-Flash boot uses a fixed AES key. So that would work without needing any OTP-based console unique keys. The main issue would be the missing sighax signature for RSA slot 2. Another issue is that the 3DS Wifi-Flash chip probably doesn't have any write-able memory at offset 400h (but I have a spare bigger chip from a DSi wifi board, so I could use that instead; and rewire the write-protect pin, of course).

zoogie
Posts: 8
Joined: Sat Nov 10, 2018 5:38 pm

Re: 3DS reverse engineering

Post by zoogie » Wed Apr 03, 2019 8:28 pm

nocash wrote:The spreadsheet is nice for verifying that my key generator has put the keys into correct keyslots. Though there seem to be a few bugs in the spreadsheet (I think the normal key in keyslot 38h should be in keyslot 38h only, not also in keyslot 3Ah. And the DSi keyX in keyslot 03h should be console unique). Anyways, the spreadsheet doesn't help on patching eMMC because I don't have OTP dump for generating all the console unique keys.
Here are the correct non console unique keys:
https://pastebin.com/7TYfQzSv
This list is generated from:
https://github.com/yellows8/boot9_tools/ (this yellows8 guy's stuff can be trusted without question)

A script for generating the console unique keys from otp is also there. (when you get around to softmodding your 3ds and you are able to dump otp).
nocash wrote: At the moment, I could see three DIY hacking approaches (or combinations thereof):

Patching firm0 at eMMC offset 0B130000h
For XORing without knowing the AES key: Is there anything known about how many firm0 versions exist? And does somebody know how to get hold of those version(s)?
I think there must be at least two versions (one for Old3DS, one for New3DS). Possibly with about 30 variations for the different firmware updates, and 6 more variants for 6 regions, and possibly 2 more variants for debug/retail? In worst case that would be up to 1440 different versions (2*30*6*2).
I have one decrypted firm0 dump (unfortunately not the one installed on the actual console). That dump contains some zerofilled areas - that would make XORing much easier (if one knows where the zerofilled area is located in each version). But to do that, one would also need to patch the NCSD header with RSA slot 3 sighax signature, and then redirect firm0 it to the zerofilled area.
Using a known-plaintext attack on firm0 would probably be the way to go here. Fortunately for new 3ds, there are only 14 different native firms for overall firmware versions 8.1 to 11.9.
nocash wrote: sighax
The bootrom uses three RSA keys in RSA slot 1,2,3:
- RSA slot 1: For FIRM signature in eMMC
- RSA slot 2: For FIRM signature in WifiFlash/Ntrcard
- RSA slot 3: For NCSD signature in eMMC
So that would require three different sighax signatures (and another three for debug version). Unfortunately, the .bin file download on http://www.sighax.com/ contains only one of those brute-forced signatures (and doesn't even tell which one... probably the retail RSA slot 1 one, as that would be most commonly used).
This tool might be capable of brute-forcing missing signatures: https://github.com/Myriachan/sighax did anybody already do that brute work? I've read that it would take 1 week with a fast GPU (or presumably several months with my own old PC).
Yeah, the brute force work has been done. The results are posted here:
https://gist.github.com/SciresM/cdd2266 ... e86f9d8c52

nocash
Posts: 1061
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Thu Apr 04, 2019 7:13 am

zoogie wrote:Yeah, the brute force work has been done. The results are posted here...
Many thanks! That's very useful to have!
zoogie wrote:Here are the correct non console unique keys... can be trusted without question.
I think that has the same small glitch in there. These three opcodes in ARM9 bootrom,
FFFF9446 movs r0,10h
FFFF94CC movs r0,24h
FFFF9550 movs r0,38h
are executed in loops (with r4=0..3), and they are apparently supposed to set normal key 10h..13h, 24h..27h, 38h..3Bh.
But, with the "mov r0,imm" (instead of "add r0,r4,imm"), they are actually setting only key 10h, 24h, 38h, and leave key 11h..13h, 25h..27h, 39h..3Bh uninitialized (and same for console unique Key.X slots 11h..13h, 25h..27h).
In practice it doesn't make much of a difference, unless the console should rely on whatever is in the uninitialized keyslots - maybe they are zerofilled upon /reset, or maybe contain old values on warmboot?
zoogie wrote:Using a known-plaintext attack on firm0 would probably be the way to go here. Fortunately for new 3ds, there are only 14 different native firms for overall firmware versions 8.1 to 11.9.
I thought "firm0" and "firm1" (in the boot sectors) would be something different than "native firm" (in the title\00040138 folder).
But now, looking closer at it, it does really look as if all three of them are exact copies of each other, good to know that!
Makes me wonder what the copies are used for...
- "firm0" boot sectors are normally loaded by bootrom.
- "firm1" boot sectors are a backup copy of above, and loaded only if above sectors were corrupted.
- the ".firm" file (within "title\00040138\x0000002" ExeFS) is what for? Is that ever used for any purpose?

zoogie
Posts: 8
Joined: Sat Nov 10, 2018 5:38 pm

Re: 3DS reverse engineering

Post by zoogie » Fri Apr 05, 2019 12:40 am

nocash wrote: I think that has the same small glitch in there. These three opcodes in ARM9 bootrom,
FFFF9446 movs r0,10h
FFFF94CC movs r0,24h
FFFF9550 movs r0,38h
are executed in loops (with r4=0..3), and they are apparently supposed to set normal key 10h..13h, 24h..27h, 38h..3Bh.
But, with the "mov r0,imm" (instead of "add r0,r4,imm"), they are actually setting only key 10h, 24h, 38h, and leave key 11h..13h, 25h..27h, 39h..3Bh uninitialized (and same for console unique Key.X slots 11h..13h, 25h..27h).
In practice it doesn't make much of a difference, unless the console should rely on whatever is in the uninitialized keyslots - maybe they are zerofilled upon /reset, or maybe contain old values on warmboot?
I'm not sure why Nintendo does that, but several keyslots are are in groups of four with the same key values. I don't think this is a bug.
nocash wrote: I thought "firm0" and "firm1" (in the boot sectors) would be something different than "native firm" (in the title\00040138 folder).
But now, looking closer at it, it does really look as if all three of them are exact copies of each other, good to know that!
Makes me wonder what the copies are used for...
- "firm0" boot sectors are normally loaded by bootrom.
- "firm1" boot sectors are a backup copy of above, and loaded only if above sectors were corrupted.
- the ".firm" file (within "title\00040138\x0000002" ExeFS) is what for? Is that ever used for any purpose?
firm0 and firm1 refer to consecutive 4 MB partitions that native FIRM is installed to (at offset firm0/1 + 0). The actual native FIRM file is usually slightly under 1MB, so most of the firm0/1 partition space is leftover padding.

This is roughly how native firm winds up in firm0/1:
1. A .cia (Ctr Importable Archive) with titleID 00040138x0000002 is downloaded to the 3ds during a system update.
2. The ncch contained in the above .cia is installed to the CTR-NAND file partition in that "title\00040138\x0000002" filepath you mentioned.
3. AM InstallFIRM is called, then the FIRM contained in the above ncch is installed to firm0 and firm1, identical copies.

Other types of FIRMs like TWL and AGB can be launched straight from their ncch containers in CTR-NAND.

nocash
Posts: 1061
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Wed May 08, 2019 4:48 pm

Wheeee, I got my first 3DS program working!
It's blinking the power LED by sending I2C commands from ARM11.
And, once when I got that working, I have added a feature that can power-off the console by simply pushing button A/B. Yeah!!!
The power-off feature is definetly making it most useful 3DS tool that I could think of.

Before getting there, I had spent last some weeks mostly on doing nothing useful... or at least nothing other than considering how to boot from SPI-flash... and then came up with the conclusion that there are too many problems for SPI booting: The built-in 4Kbyte chip doesn't have write-able memory at offset 400h (see DSi wifi thread), there are easy to use solder pads for installing a bigger 128Kbyte chip, but no good way for deactivating the old chip (other than completely removing it; which may be difficult if its bottom plate is soldered to GND), and I had tried to wire an old 128Kbyte chip to my PC, but it didn't work (either bad wiring, or the chip was damaged, or whatever).

So I gave up on SPI-booting, and focused on directly patching the eMMC via hardmod instead. After borrowing another PC card reader I've finally managed to dump the original firmware, so I can now safely unbrick the console if something goes wrong. For actually patching the console, I've spent 2-3 days on writing a relative small DSi tool (it's 2500 lines, mostly for eMMC and SHA256 stuff): It can backup the original NCSD and FIRM sectors, and then patch the NCSD and FIRM sectors for booting 512 bytes of code (ie. the LED-blinking code, and the 512 bytes should be also more than enough for loading more code from some other location).

Some noteworthy troubles: The DSi doesn't seem to strong enough to drive the eMMC CLK line when the 3DS is pulling it low (as so during bluescreen booterror). I had originally tried to fix that by inserting 120 ohm between 3DS CPU and eMMC, but that wasn't enough: I am now using 660 ohm, and that's working. Well, and then I got some things wrong, or wasn't aware of some issues that are different than DSi: The 3DS is booting the FIRM's wirth stack pointer set to zero. After issuing a I2C command, one seems to need to wait a while before sending another command (additionally to waiting for the busy-flag). Plus some mere software bugs in my code. But I somehow got it alive after all : )

The most painstaking part was probably attempting to reboot the 3DS after reflashing the firmware. In the 3DS bluescreen, the power button is even less responsive as than in the 3DS firmware. It's really bewildering: My initial approaches have been to hold the power-button several times for several seconds, hoping that console would eventually switch off.
Once and then, I've succeeded with that method. More often I gave up, and put the console aside... and at some point I noticed that console would sometimes mysteriously power-off seconds after attempting to switch it off. So, I think the power-off procedure is somewhat like so:
-- step 1: Hold power-button pressed for about 5 seconds
-- step 2: Hold your breath and wait about 5 seconds (without attempting to push the button)
Arguably, it would be easier to remove the battery, or to add a mechanical power-supply switch. But I can now use button A/B for power-off, so good-bye to that problem!

The current 512 byte code limit is due to using the two "ACI" blocks in firm0 (I am XORing one block with my FIRM header, the other block with my FIRM code (and redirect NCSD to the first of those blocks)). The ACI blocks are apparently same in all firmware versions (on New3DS at least). Except that, the last byte can be 02 (older firmware) or 03 (newer firmware). So there's a 50% chance to get it working on first attempt (and 100% chance on second attempt with 02/03 flipped). When patching both firm0 and firm1 (with 02 and 03 accordingly) then it should even work at 100% chance on first attempt).

Well, I am pretty happy that I've finally managed to run code on the damn console. After having solved that, I can now finally start testing various things that had been puzzling me for years.

PS.
Here's the DSi source code for patching the 3DS firmware. It's probably not so useful in it's current form (unless you need a LED-blinker) (also note that there's no uninstall function, so it's effectively bricking the 3DS).
Later versions might be useful in case some people don't have any working exploits for their console/region. I don't know if that's an issue... or are there so many 3DS exploits that nobody ever needs hardmodding?
Firm3ds.zip
(29.75 KiB) Downloaded 255 times

profi200
Posts: 14
Joined: Fri May 10, 2019 4:48 am

Re: 3DS reverse engineering

Post by profi200 » Fri May 10, 2019 5:37 am

So i registered just to tell you come to IRC. I understand you want to preserve all conversations but nothing will stop you from reposting relevant parts here. Besides nothing will guarantee this site will still exist in 20+ years.
All of the smart people who reverse engineered the 3DS for many years (and some who still do) are on EFnet in #3dsdev. You will get much quicker help if you ask there since it's coming from the experts themselves. We also have a bot posting links to 3dbrew edits to the channel so you will miss nothing. And it can translate all of the error codes Nintendo uses which will help you if you start reverse engineering the firmware.

nocash wrote:The 3DS is booting the FIRM's wirth stack pointer set to zero. After issuing a I2C command, one seems to need to wait a while before sending another command (additionally to waiting for the busy-flag).
boot9/11 clears every single reg before jumping to the entrypoint. They even use some weird barely documented coprocessor writes to clear all cache lines which is ironic considering how spectacularly they failed in the end with security.
The MCU is a buggy piece of shit. But it's not generally like you need to wait on every single MCU reg write/read. It's just some which will ruin your day if you don't follow the "rules". For example turning on the LCDs has been a problem since forever on New 3DS consoles. If you don't give the MCU at least 3 ms after writing to the reg screens may not turn on or show glitchy lines.
nocash wrote:The most painstaking part was probably attempting to reboot the 3DS after reflashing the firmware. In the 3DS bluescreen, the power button is even less responsive as than in the 3DS firmware. It's really bewildering: My initial approaches have been to hold the power-button several times for several seconds, hoping that console would eventually switch off.
Once and then, I've succeeded with that method. More often I gave up, and put the console aside... and at some point I noticed that console would sometimes mysteriously power-off seconds after attempting to switch it off. So, I think the power-off procedure is somewhat like so:
-- step 1: Hold power-button pressed for about 5 seconds
-- step 2: Hold your breath and wait about 5 seconds (without attempting to push the button)
Arguably, it would be easier to remove the battery, or to add a mechanical power-supply switch. But I can now use button A/B for power-off, so good-bye to that problem!
Pressing the power button will do nothing but trigger the MCU interrupt notifying the running OS. When you hold it for at least 3 seconds it will force poweroff after another ~7 seconds.


I would highly recommend you install some bootloader like boot9strap or fastboot3DS. That will make your life much easier since you can boot FIRM files directly from the SD card or one of the partitions on eMMC. If you know the installed firmware version you can easily use the known plaintext attack replacing the contents of firm0/1. I'm sure someone will share the matching NATIVE_FIRM for your 3DS (but not here of course) :wink:

nocash
Posts: 1061
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Sun May 12, 2019 11:24 am

Can I invite anyone back to join more public places? Dev forums could be really helpful to get things done, and also helpful to know what was already done.

MCU Delays: When writing to the power LED register, all following MCU writes were ignored until I had added a delay after each write (the part marked "EXTRA delay" in the source code in previous post).
I don't know if that's specific to the LED register, or if it's needed for all writes. HLL code might be slow enough for not needing that delay at all. And a smaller delay with only 10-100 cycles would be probably enough, too.

EDIT: There seems to be a hardware timer at 17E00604h (related to MPCore Timer interrupts). The bootrom uses that timer to memorize the previous I2C transfer end time (ie. the end of the last data byte of a "device+index+data" transfer sequence), and checks that time before starting a new I2C transfer.
If the difference between current time and memorzized time is 188 or higher then it starts right away. Otherwise it does seem to try to wait "(188-difference)*2 clock cycles".
To compute that value, it does multiply everything by 1000000, then divide it by 268112, and does then carefully undo those steps by multiplying the result by 268112, and then dividing it by 1000000. Which, I assume that alone might serve as a suitable delay, so it could then simply omit waiting for the computed amount of clock cycles ; )

LCD Init Delays: I guess the delays in the bootrom should be more or less suitable; unless they are too slow for practical use. The way how the bootrom calculates the delay timings (with 64bit multiiplactions... and divisions?) is a bit confusing, I'll still need to figure out what those delays mean in terms of "microseconds" or "clock cycles".

LCD/GPU Init: Apart from the delays, I have almost fully figured out how the bootrom is initializing the video hardware for text output. Implementing my own text output functions should be done in 1-2 days... and then I can finally test anything I want : )

Knowing the installed firmware version: No, that isn't required. I got my LED blinker booted & working - and I have no idea what firmware version I have. At least the New3DS seems to have only two(?) different ACI versions, so one could either easily guess/retry, or simply patch both firm0 and firm1 for not needing any retries.

Booting more than 512 bytes: That was already included as untested/unimplemented feature, appended at the end of the source code in previous post. I've meanwhile implemented & tested that stuff, and it worked just fine, so I could now boot larger programs or FIRM partitions or whatever.

Existing Exploits: Yeah, using existing exploits might have been much easier. Somehow the japanese gui, the obscure 3ds guide, the slowish firmware, and the broken top screen got in my way. Altogether I had decided that the easy method is much too annoying, and that it would be more satisfying to look-up the boot process on 3dbrew and to write my own bootloader.
The problem about XORing the installed firmware with homebrew bootcode is that it's only working if it wasn't already patched with other homebrew bootcode. Is there some standarized way for determining if NCSD/FIRM are already patched? And uninstall info for removing the old patch before installing a new one?

My installer is currently storing that kind of uninstall info at the end of the first 4000h-byte block in eMMC. But of course, everyone else is supposedly doing that differently. And the first 4000h bytes are a bit risky anyways (assuming that software crashes with accidental eMMC-writes may tend to destroy just that area).
Last edited by nocash on Sun May 12, 2019 6:21 pm, edited 3 times in total.

profi200
Posts: 14
Joined: Fri May 10, 2019 4:48 am

Re: 3DS reverse engineering

Post by profi200 » Sun May 12, 2019 6:04 pm

You are hitting a brickwall if you try to get them to move anywhere else other than IRC or the Wiki. They would not even move to a different network even though EFnet is motorious for stability problems. I would highly recommend joining that channel as said even if you don't want to use it for dev talk.

When i was measuring how much time/cycles the CPU spends waiting for a single byte I2C transfer (switched to using interrupts since) i got far over 10000 cyles on ARM11 (measured using the MPCore performance monitor) so don't worry about that I2C is a real slug. Performance is not just about code size.
I had no problems at all with the power LED but i only use it as sleep indicator anyway.

There was no need to reverse engineer the GPU/LCD init code. It has been figured out long ago. Most of the register names are missing but it works well: https://github.com/derrekr/fastboot3DS/ ... gfx.c#L249
boot9strap has very similar code.

Everything detects modified FIRM partitions by looking for the sighax signatures. That's it. There is a new exploit since a while which allows pre-bootrom lockout code execution in an easier way than what b9s implements (see superhax folder in the linked repo above).

PSI
Posts: 15
Joined: Mon May 13, 2019 5:32 pm

Re: 3DS reverse engineering

Post by PSI » Mon May 13, 2019 5:45 pm

Hi nocash, I made an account to get a chance to talk to you. I'm also making a 3DS emulator: https://github.com/PSI-Rockin/Corgi3DS

My emulator runs the boot ROMs and successfully loads NATIVE_FIRM off the NAND. It doesn't get much further than that as Kernel11 needs MMU, but it's also capable of booting ARM9 payloads such as GodMode9 from an SD image. As far as I know, this is the furthest anyone has ever gotten with an LLE 3DS emulator.

I've used your documentation in the past for previous projects, and I'm a big fan of your work. If you would like, I can offer assistance and advice for your emulator - just let me know.

Good luck! Can't wait to see how yours turns out.

zoogie
Posts: 8
Joined: Sat Nov 10, 2018 5:38 pm

Re: 3DS reverse engineering

Post by zoogie » Mon May 13, 2019 9:46 pm

PSI wrote: ...
As far as I know, this is the furthest anyone has ever gotten with an LLE 3DS emulator.
Well, there's this
https://github.com/archshift/llama
The fact that it's coded in Rust is a bit of a killjoy, but at least it's in a pretty advanced stage.

PSI
Posts: 15
Joined: Mon May 13, 2019 5:32 pm

Re: 3DS reverse engineering

Post by PSI » Tue May 14, 2019 4:36 am

Llama does appear to have some good work put into it. Judging by its description though (having to manually provide CPU entrypoints for a list of files), it doesn't seem to be capable of booting from the boot ROMs, which would require an encrypted OTP and NAND. Someone please correct me if I'm wrong.

Post Reply