Worklog Getting the DSi bootroms

Joined
Mar 17, 2016
Messages
80
Likes
49
Something I've been working on lately, figured I'd post my progress.

Introduction:
The DSi and 3DS share many things, one of those is their protecting half of the bootrom on each main processor (of which there are two in each console). Initially upon boot, the bootroms are readable and executable, but near the end of the boot process, they are locked permanently. The DSi has an ARM7 and an ARM9, while the 3DS has an ARM9 and an ARM11. I'm going to be initially grabbing the ARM9 bootrom from the DSi, then possibly looking into attacking ARM7 using the early code execution to take over ARM7.

Basic concepts:
ARM processors, like most processors, have something called exceptions. Exceptions generally happen when something goes wrong with the software running on the processor. Initially upon boot, the exception vectors point to some uninitialized memory for it's handler, however RAM contents are kept upon reboot so we can put our own exception handler in, then all we have to do is cause an exception before bootrom gets locked. Easy, right? Well, not so much. Given that the bootrom is read only, it's pretty hard to get exceptions to happen and is likely impossible without some sort of external influence. This is where we use a technique called fault injection. Fault injection usually involves hardware, we can do lots of things like playing with clock speed, voltage levels or other things.

Basic tests:
About a week ago I started playing with the main voltage for the DSi processor, initially I wasn't getting very good results, but with some more testing I discovered where I was going wrong.

My initial setup was very simple, just a potentiometer on the voltage line and a switch to switch between normal voltage and the new, lower voltage. Initially I was trying to drag the voltage level down really far, but noticed that this wasn't very effective. I did get a few exceptions, but it was very inconsistent and crashed more often than I liked. After more testing, I found the sweet spot; it seems that just barely dropping the voltage fairly consistently causes an exception! So, after finding a good value on the pot, I replaced it with fixed resistors. This was my first real milestone.

Automation:
Doing this manually was way too slow, unfortunately, so I need to build something that can switch for me. Someone had graciously given me a dead 3d printer board, and on it I found some solid state relays. After a bit of testing, I determined that these were perfect for my purposes, and have since made a basic circuit with them:

(Please excuse the text oddities, those were out of my control)

From here, it's a simple matter of writing some code to control this circuit externally. I'll be using a raspberry pi 2 B to do this, since I have one on hand. I currently haven't written any code, but it's on the todo directly after writing this post :)

Hopefully, the ARM9 bootrom will be mine sometime this week :D
 

Aurelio

ᕕ( ᐛ )ᕗ
Staff member
.
.
.
.
.
Joined
Mar 3, 2016
Messages
2,219
Likes
2,937
Portables
2
Isn't this close to what derrek has done on both the 3DS and the Wii U?
 
Joined
Mar 17, 2016
Messages
80
Likes
49
Last edited:
Joined
Mar 17, 2016
Messages
80
Likes
49
I've been neglecting this thread a bit, sorry about that. The good news is, I got code execution pre-bootrom lock! After talking with someone else, it seems the main ram chip is actually disabled on boot, and there's a bit you need to set in software to turn it on, my exception handler is installed there (and is where the bootrom attempts to jump if there's an exception). So, I needed to somehow enable the RAM on boot. Looking through the wonderful board trace done by nocash, reading some RAM docs, looking at some signals with my logic analyzer, and talking to someone with the twlsdk, it seems that I needed to pull the CE2 signal high.

Logic analyzer screenshot:
Screenshot from 2017-01-25 21-16-28.png

What this shows is the CE2 signal being pulled up by the SoC during one of the NAND bootloaders that the bootrom loads (well after the bootrom is locked down). With this in mind, I went about trying to pull it up. Initial results weren't good, pulling it up manually to 1.8v didn't work, the whole console just wouldn't boot. So, I had to cut the trace. the only place this trace was on the top of the board was very small:

however, I did successfully cut and solder to this small trace:
I also had an idea. Based on the information I gained about how to set the CE2 signal from the friend with the SDK, I could also solder to the SoC side of the pin and use that to tell my automated program whether or not I got code execution. The CE2 pin is very consistently pulled up ~250ms into boot, so if it were to be pulled up earlier than that, then we might have a successful result. This ended up working pretty well, and you can see from the above picture the wire on the SoC side too.

So, after all of this was done, my code and circuit were finished, there was only one thing left to do. Actually try to get execution!

funnily enough, it worked on the very first attempt, then gave me some trouble after, I couldn't get execution again. So, I left it for that night and came back the next day, after messing around awhile, I did get execution again a few times, which was good.

The next problem then arose. My testing payloads had just been setting the CE2 bit to tell me that I got execution, and weren't actually dumping the bootrom anywhere. So, I started thinking about actually extracting the data. Some testing was done, and it seems some part of the boot process actually clears all RAM :( . That rules out dumping to RAM, then just using an exploit to dump it out on a normal reboot. So, I had to think of something else. Looking at gbatek, most of the I/O is all on the arm7, and we're just getting code execution on the arm9 here, which has not a lot of contact with the outside of the SoC package. The few areas where it could, you need to poke some arm7-only registers to active them, and a few other things that may have been useful (the CE2 line, for example) are just write-once registers (until reboot, ofc) so it's not like we could send the data out in a serial fashion. I got stuck for awhile, but I think I've got the answer here, I just need to implement it. Some more data about the RAM: it has an active low "Write enable" signal, which, as it sounds, will disable writes if pulled high. Perfect, we can just pull that high and RAM won't be cleared, but the DSi won't end up booting into it's FW. However, it's easy to take over the arm7 at the stage of execution it's in, due to it mapping code into the shared WRAM that both arm9 and arm7 can access. So the final plan to get everything working is as follows: execute the glitch and get code execution before bootrom is locked. Once we have that, copy the data from the bootrom and into the main ram, then disable writes to main ram. Reboot again, wait for execution to reach the stage where we can easily take over the arm7, take it over and dump the bootrom to an SD card using the arm7 :). Haven't put this final part into action yet, but the code for it is going to be written tonight, and hopefully this weekend I'll have some time to try attempts to get the bootrom :)
 
Last edited:
Top