Homebrew [WIP] Dumping the bootrom

bayleef

Well-Known Member
OP
Newcomer
Joined
Sep 15, 2015
Messages
83
Trophies
0
XP
254
Country
Gambia, The
See https://media.ccc.de/v/33c3-8344-nintendo_hacking_2016
Please do only respond to this thread, if you have to say something that could be helpful in order to dump the bootrom. Please do not discuss about sighax and/or its value here. It is hard to identify the posts that could help us with dumping the bootrom in the other threads about the 33c3 talk, because there is so much discussion about the value of sighax. So I made this thread to promote bootrom dumping.

At first, writing the a9lh payload for dumping (the protected part of) the bootrom should not be hard.
It could look like this:
You need some header and source files from Decrypt9WIP to build the code. You may remove some unneeded source files and remove the definition of LOG_FILE in common.h.
Code:
#include "common.h"
#include "draw.h"
#include "fs.h"
#include "hid.h"
#include "platform.h"
#include "i2c.h"

// code for vector-glitch hack of 33c3 talk
//
// on normal boot, the interrupt vector table is modified for the following interrupts
// - undefined instruction
// - prefetch abort
// - data abort
//
// if such an interrupt is thrown (after cold reboot),
// the protected bootrom is copied to 0x23e0000,
// followed by magic word 0xDEADBEEF
//
// if the magic word is present (after bootrom execution in order to have everything initialzed),
// the bootrom is copied from 0x23e0000 to file

void PowerOff()
{
   i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
   while (true);
}

void Reboot()
{
  i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
  while(true);
}

u32 payload[] =
{
    // ; set r2 to 0x23e00000 (out address)
   0xe3a02c23, // mov  r2, #8960  ; 0x2300
   0xe28220e0, // add  r2, r2, #224  ; 0xe0
   0xe1a02802, // lsl  r2, r2, #16
    // ; set r1 to 0xffff8000 (in address)
   0xe3a01cff, // mov  r1, #65280  ; 0xff00
   0xe28110ff, // add  r1, r1, #255  ; 0xff
   0xe1a01801, // lsl  r1, r1, #16
   0xe2811902, // add  r1, r1, #32768 ; 0x8000
    // ; set r3 to 0x8000 (counter)
   0xe3a03902, // mov  r3, #32768  ; 0x8000
    // <loop>: ; memcpy
   0xe4910004, // ldr  r0, [r1], #4
   0xe4820004, // str  r0, [r2], #4
   0xe2533004, // subs r3,  r3,  #4
   0xcafffffb, // bgt  <loop>
    // ; memcpy finished, load magic word
    // ; set r0 to 0xdeadbeef
   0xe3a00cde, // mov  r0, #56832  ; 0xde00
   0xe28000ad, // add  r0, r0, #173  ; 0xad
   0xe1a00800, // lsl  r0, r0, #16
   0xe2800cbe, // add  r0, r0, #48640  ; 0xbe00
   0xe28000ef, // add  r0, r0, #239  ; 0xef
   0xe4820004, // str  r0, [r2], #4
   0xe51ff004, // ldr pc, [pc, #-4]  ; run bootrom again (to initialize everything)
   0xffff0000, // bootrom reset vector
};

int main()
{
   u32 dump_addr = 0x23E00000;
   u8* dump = (u8*)dump_addr;

   // test whether bootrom has been copied to memory already (test magic word)
   if (*((u32*)&dump[0x8000]) == 0xDEADBEEF)
   {
     ClearScreenFull(true, true);
     DebugClear();
     // maybe successful dumped, now copy to file
     InitFS();
     FileCreate("PROT_BOOT9.BIN", true);
     FileWrite(dump, 0x8000, 0);
     FileClose();
     DeinitFS();
     Debug("dumped :-)");
     while (true)
     {
       u32 pad_state = InputWait();
       if (pad_state & BUTTON_A)
       {
         while(1)
         {
           PowerOff();
         }
       }
     }
   }else{
     // set up interrupt vector table
     u32 inv_instr_handler_addr = 0x08000018;
     u32* inv_instr_handler = (u32*)inv_instr_handler_addr;
     int i=0;
     for (i=0;i<3;i++)
     {
       *inv_instr_handler = 0xe51ff004; // ldr pc, [pc, #-4]
       inv_instr_handler++;
       *inv_instr_handler = (u32)((void*)payload); // dump bootrom
       inv_instr_handler++;
     }
     ClearScreenFull(true, true);
     DebugClear();
     Debug("Interrupt vector table set up.");
     // TODO: synchronize with vcc glitching device
     Reboot();
   }
   return 0;
}
Please reply to this thread if you have any improvements, I may update the code in this post.

How can we do the fault injection? I think, the easiest way for fault injection would be vcc glitching.
It MAY be sufficient to use a Raspberry Pi for this task, we MAY just need to pull VCC of the battery to GND for some nano seconds we have to pull VCC input of the ARM9 to GND (or even negative voltage?) for some nano seconds, e.g. with the help of a MOSFET controlled by the Raspberry.
However, according to https://www.3dbrew.org/wiki/3DS_System_Flaws#Hardware we need a very precise timing.
Hence, we have to synchronise the reset with our vcc glitching hardware. How could we do this?
  1. Via hardmod
    • We could connect to the I2C bus to trigger / capture the reset signal. Which pins of the 3DS board do we need to connect?
    • We may not connect to I2C, but to a button of the 3DS. Then the vcc glitching hardware would "press" that button, telling the 3DS software to trigger reset via I2C.
  2. Could we do it without opening the 3DS? We have to solder a wire to ARM9 VCC coneection. However, maybe we do not need to add any additional wires to the board? We may trigger reboot by writing to the I2C bus by software, but how could we synchronize with the vcc glitching device then?
    • Reset MAY cause a specific fingerprint of power consumption. We may measure the power consumption and trigger vcc glitching when this fingerprint occurs.
    • Could we create an audio signal just before triggering the reboot and connect the vcc glithing device as haedphone? We would have to implement an audio driver for ARM9 mode, which may be complicated (but should be possible). However, would this method be too slow to achieve the synchronization?
Do you have some helpful comments to the ideas presented above? Which way could be the best? Are there any other ideas to synchronize the reset with the vcc glitching hardware?

Update: VCC glitching at battery connection does not really seem to work. There may be voltage stabilizers that we need to bypass by glitching VCC at the ARM9 directly.
 
Last edited by bayleef,

zoogie

playing around in the end of life
Developer
Joined
Nov 30, 2014
Messages
8,560
Trophies
2
XP
14,998
Country
Micronesia, Federated States of
I don't know if you're aware, but #cakey on freenode is where the most promising of 3ds bootrom development community meets to discuss things. They're actually getting kinda close; maybe they could use your help or vice-versa.
 
Last edited by zoogie,

Thunder Hawk

Firefox Master Race
Member
Joined
Jan 21, 2013
Messages
804
Trophies
1
XP
2,585
Country
United States
See https://media.ccc.de/v/33c3-8344-nintendo_hacking_2016
Please do only respond to this thread, if you have to say something that could be helpful in order to dump the bootrom. Please do not discuss about sighax and/or its value here. It is hard to identify the posts that could help us with dumping the bootrom in the other threads about the 33c3 talk, because there is so much discussion about the value of sighax. So I made this thread to promote bootrom dumping.

At first, writing the a9lh payload for dumping (the protected part of) the bootrom should not be hard.
It could look like this:
You need some header and source files from Decrypt9WIP to build the code. You may remove some unneeded source files and remove the definition of LOG_FILE in common.h.
Code:
#include "common.h"
#include "draw.h"
#include "fs.h"
#include "hid.h"
#include "platform.h"
#include "i2c.h"

// code for vector-glitch hack of 33c3 talk
//
// on normal boot, the interrupt vector table is modified for the following interrupts
// - undefined instruction
// - prefetch abort
// - data abort
//
// if such an interrupt is thrown (after cold reboot),
// the protected bootrom is copied to 0x23e0000,
// followed by magic word 0xDEADBEEF
//
// if the magic word is present (after bootrom execution in order to have everything initialzed),
// the bootrom is copied from 0x23e0000 to file

void PowerOff()
{
   i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
   while (true);
}

void Reboot()
{
  i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
  while(true);
}

u32 payload[] =
{
    // ; set r2 to 0x23e00000 (out address)
   0xe3a02c23, // mov  r2, #8960  ; 0x2300
   0xe28220e0, // add  r2, r2, #224  ; 0xe0
   0xe1a02802, // lsl  r2, r2, #16
    // ; set r1 to 0xffff8000 (in address)
   0xe3a01cff, // mov  r1, #65280  ; 0xff00
   0xe28110ff, // add  r1, r1, #255  ; 0xff
   0xe1a01801, // lsl  r1, r1, #16
   0xe2811902, // add  r1, r1, #32768 ; 0x8000
    // ; set r3 to 0x8000 (counter)
   0xe3a03902, // mov  r3, #32768  ; 0x8000
    // <loop>: ; memcpy
   0xe4910004, // ldr  r0, [r1], #4
   0xe4820004, // str  r0, [r2], #4
   0xe2533004, // subs r3,  r3,  #4
   0xcafffffb, // bgt  <loop>
    // ; memcpy finished, load magic word
    // ; set r0 to 0xdeadbeef
   0xe3a00cde, // mov  r0, #56832  ; 0xde00
   0xe28000ad, // add  r0, r0, #173  ; 0xad
   0xe1a00800, // lsl  r0, r0, #16
   0xe2800cbe, // add  r0, r0, #48640  ; 0xbe00
   0xe28000ef, // add  r0, r0, #239  ; 0xef
   0xe4820004, // str  r0, [r2], #4
   0xe51ff004, // ldr pc, [pc, #-4]  ; run bootrom again (to initialize everything)
   0xffff0000, // bootrom reset vector
};

int main()
{
   u32 dump_addr = 0x23E00000;
   u8* dump = (u8*)dump_addr;

   // test whether bootrom has been copied to memory already (test magic word)
   if (*((u32*)&dump[0x8000]) == 0xDEADBEEF)
   {
     ClearScreenFull(true, true);
     DebugClear();
     // maybe successful dumped, now copy to file
     InitFS();
     FileCreate("PROT_BOOT9.BIN", true);
     FileWrite(dump, 0x8000, 0);
     FileClose();
     DeinitFS();
     Debug("dumped :-)");
     while (true)
     {
       u32 pad_state = InputWait();
       if (pad_state & BUTTON_A)
       {
         while(1)
         {
           PowerOff();
         }
       }
     }
   }else{
     // set up interrupt vector table
     u32 inv_instr_handler_addr = 0x08000018;
     u32* inv_instr_handler = (u32*)inv_instr_handler_addr;
     int i=0;
     for (i=0;i<3;i++)
     {
       *inv_instr_handler = 0xe51ff004; // ldr pc, [pc, #-4]
       inv_instr_handler++;
       *inv_instr_handler = (u32)((void*)payload); // dump bootrom
       inv_instr_handler++;
     }
     ClearScreenFull(true, true);
     DebugClear();
     Debug("Interrupt vector table set up.");
     // TODO: synchronize with vcc glitching device
     Reboot();
   }
   return 0;
}
Please reply to this thread if you have any improvements, I may update the code in this post.

How can we do the fault injection? I think, the easiest way for fault injection would be vcc glitching.
It MAY be sufficient to use a Raspberry Pi for this task, we MAY just need to pull VCC of the battery to GND for some nano seconds we have to pull VCC input of the ARM9 to GND (or even negative voltage?) for some nano seconds, e.g. with the help of a MOSFET controlled by the Raspberry.
However, according to https://www.3dbrew.org/wiki/3DS_System_Flaws#Hardware we need a very precise timing.
Hence, we have to synchronise the reset with our vcc glitching hardware. How could we do this?
  1. Via hardmod
    • We could connect to the I2C bus to trigger / capture the reset signal. Which pins of the 3DS board do we need to connect?
    • We may not connect to I2C, but to a button of the 3DS. Then the vcc glitching hardware would "press" that button, telling the 3DS software to trigger reset via I2C.
  2. Could we do it without opening the 3DS? We have to solder a wire to ARM9 VCC coneection. However, maybe we do not need to add any additional wires to the board? We may trigger reboot by writing to the I2C bus by software, but how could we synchronize with the vcc glitching device then?
    • Reset MAY cause a specific fingerprint of power consumption. We may measure the power consumption and trigger vcc glitching when this fingerprint occurs.
    • Could we create an audio signal just before triggering the reboot and connect the vcc glithing device as haedphone? We would have to implement an audio driver for ARM9 mode, which may be complicated (but should be possible). However, would this method be too slow to achieve the synchronization?
Do you have some helpful comments to the ideas presented above? Which way could be the best? Are there any other ideas to synchronize the reset with the vcc glitching hardware?

Update: VCC glitching at battery connection does not really seem to work. There may be voltage stabilizers that we need to bypass by glitching VCC at the ARM9 directly.
Bumping this because you wanted people to reply here with helpful info, but it never happened and the thread went unnoticed.
 

bayleef

Well-Known Member
OP
Newcomer
Joined
Sep 15, 2015
Messages
83
Trophies
0
XP
254
Country
Gambia, The
Thank you. However, I guess that I have to wait for hedge's "very in-depth writeup + circuit detailing" to get some really good information.
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
  • ZeroT21 @ ZeroT21:
    it wasn't a question, it was fact
  • BigOnYa @ BigOnYa:
    He said he had 3 different doctors apt this week, so he prob there. Something about gerbal extraction, I don't know.
    +1
  • ZeroT21 @ ZeroT21:
    bored, guess i'll spread more democracy
  • LeoTCK @ LeoTCK:
    @K3Nv2 one more time you say such bs to @BakerMan and I'll smack you across the whole planet
  • K3Nv2 @ K3Nv2:
    Make sure you smack my booty daddy
    +1
  • LeoTCK @ LeoTCK:
    telling him that my partner is luke...does he look like someone with such big ne
    eds?
  • LeoTCK @ LeoTCK:
    do you really think I could stand living with someone like luke?
  • LeoTCK @ LeoTCK:
    I suppose luke has "special needs" but he's not my partner, did you just say that to piss me off again?
  • LeoTCK @ LeoTCK:
    besides I had bigger worries today
  • LeoTCK @ LeoTCK:
    but what do you know about that, you won't believe me anyways
  • K3Nv2 @ K3Nv2:
    @BigOnYa can answer that
  • BigOnYa @ BigOnYa:
    BigOnYa already left the chat
  • K3Nv2 @ K3Nv2:
    Biginya
  • BigOnYa @ BigOnYa:
    Auto correct got me, I'm on my tablet, i need to turn that shit off
  • K3Nv2 @ K3Nv2:
    With other tabs open you perv
  • BigOnYa @ BigOnYa:
    I'm actually in my shed, bout to cut 2-3 acres of grass, my back yard.
  • K3Nv2 @ K3Nv2:
    I use to have a guy for that thanks richard
  • BigOnYa @ BigOnYa:
    I use my tablet to stream to a bluetooth speaker when in shed. iHeartRadio, FlyNation
  • K3Nv2 @ K3Nv2:
    While the victims are being buried
  • K3Nv2 @ K3Nv2:
    Grave shovel
  • BigOnYa @ BigOnYa:
    Nuh those goto the edge of the property (maybe just on the other side of)
  • K3Nv2 @ K3Nv2:
    On the neighbors side
    +1
  • BigOnYa @ BigOnYa:
    Yup, by the weird smelly green bushy looking plants.
    K3Nv2 @ K3Nv2: https://www.the-sun.com/news/10907833/self-checkout-complaints-new-target-dollar-general-policies...