Here’s a deeper look at how rajkosto’s briccmii works. We’re gonna be looking at main.c because that’s where most of the interesting stuff happens. If you want to follow along at home, code checked out was
https://github.com/rajkosto/briccmii/blob/master/src/main.c from the commit faea0fc, most recent at the time of writing.
From line 22 - the beginning of main function - to line 65 we take care of initializing the hardware and setting up the capability to interact with the eMMC. This is fairly standard stuff and looks a lot like what we find in Hekate.
From lines 67-74 we read in the BCT, the part that configures the boot procedure of the Switch. This is already important since that is what we’re going to corrupt in order to force the Switch to boot into RCM. No corrupting has happened yet, though.
From 76-88 we map out the BCT entries that are currently in use. This is done somewhat needlessly fancy but from a coders perspective it looks kinda cool. I wouldn’t expect anything else from rajkosto to be honest. ^^ This is gonna make things a little easier later on.
Now for the real meat:
From lines 90-119 we first read the correct SHA256 hash from the Tegra fuses so we know what correct output has to look like, then compare it to the current values’ hashes and display which ones are correct at this time and which ones are not.
Time to get bricking! Since this is a somewhat user-friendly program, it displays a menu in line 122. After that we enter an infinite loop. This isn’t as infinite as it sounds, quitting the program will end it. For our purposes that means the program will always return to this point after doing something.
After reading the buttons (line 124) we determine our course of action:
Pressing Power will safely exit the program (125+126) by skipping out of the infinite loop towards the end of the program.
If we press Vol+ (line 128) we begin the unbricking process:
If there are no valid BCT entries - we determined these earlier, remember? - we grab a known good public key from the BCT signature data. (lines 129 147) Otherwise we go through each key and, if we find a corrupt one, repair it under the assumption that it was corrupted using the very same method we will use later down the line in the bricking part of the code. (lines 150-177)
Now that we should have a known good key - we verify this in lines 180-187, quitting the program if we still don’t have one - let’s unbrick. We cycle through the BCT entries, skipping any entries that are already correct. The write of the correct data occurs in line 205, informing the user whether it worked or something went wrong.
Phew, that’s a load. There are quite a few checks and safety measures in place here to make sure we only do what we need.
After this, we have the code that most of you came here to see, starting in line 212: If the user presses Vol-, the bricking process is intiated.
We cycle through our BCT entries, checking if they are already “bricc’d” as rajkosto calls it, since we only ever want to apply the bricking procedure to valid data. It is reversible but we can only use the code above to unbrick it if it was bricked in a very specific way so this is a very sane check to perform. (220-225)
If we reached this point in the code we know we are good to brick. So let’s do that! In a loop that refuses to end until we have successfully bricked the Switch, we generate a pseudo-random number, AND it with 0xff and then write it to the position 0x10 of our BCT data. Having done that, we calculate the sha256 hash of our data. If we get a mismatch, our data is correctly wrong (meaning corrupted) and we can exit the loop. (230-234)
Now that we have the data we want to write, all that is left is to write our changed data to the eMMC, which we do in line 236. If it succeeded, we also display a cheeky message to the user to let them know they just “GOT BRICC’D!”.
The rest of the code after the infinite loop is just fairly standard cleanup code, it will only ever be reached if the program or user decide to quit.
The good thing about the method used is that it both uses pseudo-random numbers to corrupt - making it indistinguishable from accidental corruption on a grander scale if someone were to try to find such a thing - and corrupts only data that is easy to reconstruct at any time, because the Switch always has a spare copy available in its fuses.
I like what I see here. If I wanted to brick my Switch on purpose, this would be a candidate for me.
Correction: After talking with rajkosto I saw why I misread the code that restores the data thinking it would only restore one (I mistakenly thought a break; statement broke more than it actually does.) This has since been fixed to accurately reflect the actual code.