Arm9LoaderHax - Deeper inside

(Images from 32C3 presentation)

The Nintendo 3DS hacking and homebrew scene completely found life and energy again, after the famous 32C3 conference where smealum, derrek and plutoo talked about their personal progress in the console reverse engineering, explaining all their goals from the past two years step by step, along with the revelation of exploits which weren't public yet, for either usermode, arm11 and arm9 kernel mode. 

The exploit that stimolated me for the most is arm9loaderhax, an ARM9 exploit which gives code exection just before the kernel starts up at coldboot, which means that the console can fall under our complete control just a millisecond after we turn it on. 
So what i'll attempt to do in this article is a simple explanation on how it works and why it is so "user-unfriendly", let's go! 

The ARM9 Loader vulnerability

First of all i suggest to have a good read of this 3dbrew page, that will give you the basic knowledge of how the 3ds firmware files are handled. 
With the release of the New 3DS Nintendo implemented a new strategy to prevent the hackers from hacking and reading their ARM9 (Security processor) firmware partition; this consist of encrypting the entire ARM9 binary (While in Old 3DS in was completely plaintext) and appending to it a plaintext loader which is delegated to generate the New 3DS specific keys, decrypt the binary, control that everything is correct and then jump to the kernel entrypoint. 
Starting from system update 9.6 this implementation uses a new key to decrypt the binary (Which is read from the NAND 0x96 sector, containing New3DS specific keys) and it is not checked at all, allowing us to write in the interested place whatever random key we want; in this way the binary will be decrypted as completely uncontrolled garbage data, and then the cpu will jump to it! 
So our goal would be to find a proper key that will result on the ARM9 Kernel entrypoint to be decrypted on a branch (jump) ASM instruction, that will redirect the code flow to another memory address, which hopefully contains our payload. 

Structure of an ARM branch instruction

But then, how can we write an ASM payload in memory at coldboot? 

The Bootrom uncleared memory area

We are casually lucky this time, since the bootrom give us a great help. 
This is what it does at boot, shortly: 

  1. Do many top-secret things
  2. Read the firmware from FIRM0 partition
  3. Check its RSA signature. If it's good, jump to it.
  4. In the other case read the firmware from FIRM1 partiton.
  5. Check its RSA signature. If it's good, jump to it.
  6. If both FIRM0 and FIRM1 are signature-broken, trigger a blue screen of death.

This is all correct, assuming that FIRM0 and FIRM1 are identical (FIRM1 should be a "recovery" backup) and that they have the same size. 
What catches our attenction is the fact that bootrom does not clear the memory between steps 2 and 4, and it reads FIRM1 on top of the "broken" FIRM0. 
So what can we do? 
Basically we can attack this with an hard mod (Hardware access to the NAND chip) by writing in FIRM0 a firmware with a big ARM9 partition, write our ASM payload at the end of it, then write in FIRM1 a firmware with a small ARM9 partition (At least smaller than FIRM0's one) and with a 9.6+ version of New 3DS arm9loader. 
In this way at boot we'll have a signature-correct ARM9 binary that will be accepted by bootrom, with our little payload after its end. 

The exploitation

At this point we have a way to write an ASM payload in ARM9 memory, and with some bruteforcing tool we can easily (But not fastly) find a key that decrypts the ARM9 entrypoint to a branch instruction that jumps to our payload's location. Let's turn on the console! 

  1. Bootrom reads FIRM0, but due to our payload presence, the signature check will fail.
  2. It will read FIRM1 on top of FIRM0, and our payload will still be after it.
  3. Check its RSA signature, since it's good it will jump to its arm9loader.
  4. The arm9loader will use our crafted key to decrypt the ARM9 binary as garbage, then jump to the kernel entrypoint.
  5. With our key the garbage kernel entrypoint will make the cpu jump to our payload location.
  6. Code execution!


(Images from 32C3 presentation)

Once we get code executiuon in this small portion of space, we can load a bigger binary in memory, in order to have a suitable executive space, and we since this exploit happens before kernel boot we can dump some cool things like the 6.X save key and the 7.X NCCH key. 

What is the problem with it then?

To make the explanation simpler i before excluded some important details that makes the situation more difficult than it can appear. 
The main problem is that the 0x96 NAND sector keys are enctrypted through AES-ECB with a key obtained from a SHA256 hash of the OTP area. 
OTP is an IO area where some console specific data is stored; the block to OTP is set at boot from ARM9 (By arm9loader on New 3DS and by Kernel9 by Old 3DS) by writing an IO bit, and once set it cannot be changed, which means that once the console boots properly we cannot access this area even if we get ARM9 code exection with wathever exploit in any successive moment. 
We actually need our OTP SHA256 then if we want to successfully encrypt our key, and have arm9loaderhax to happen (Obviously we can bruteforce it as hell if we want, but we are smarter than that, not to mention that it can take ages to find the right data). 

We are still lucky, because Nintendo forgot to lock the OTP area on firmware versions below 3.0! 
So we can downgrade (Find a tutorial for this) to a system version between 1.0 and 2.2, gain ARM9 code execution and dump OTP! 
Do not think that this is a comfortable plan, it's more trivial than it can appear, expecially on New 3DS, which is not even meant to run that old firmwares and requires many attenctions to make it work; and after that, you still need some application entrypoint to execute code, like Cubic Ninja. 
This is the only way to retrieve our console-specific data, at least on Old 3DS; New3DS can use instead this same arm9loader vulnerability to obtain the OTP hash without downgrading, but requires some brutalforcing and many tries (explained in this page). 
To sum it up, one needs to be really careful and has to know what he is doing, it's not for all the users. 

Last but not least, we have to remember that the 0x96 is New 3DS specific, so on Old 3DS we'll need to write it encrypted in NAND manually after we have it dumped from a retail New 3DS (Do not worry, someone already leaked the data on pastebin). 


To sum it up the requirements are : 

This is a really wonderful exploit which gives us lots of possibilities, and once it has been setted up it's really comfortable, making ARM9 tools and firmware patching possible directly at boot. 
Also it's not patchable, because we can always overwrite FIRM1 with an old exploitable version of ARM9 loader, so that will be permanent from any system updated from now on, if implemented. 

I really hope this will be of any help for the ones who will try to attempt it, and the ones which will ask others to install it on their console. 
It's a really fun exploit to play with, and i am still working on it on my personal Old 3DS. 

Here is my key bruteforcer doing his work.

Also keep in mind that this is one of my first articles, so be patient for grammar errors and ambiguous explanations, you can always contact me for clarifications.