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:
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?
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.
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;
}
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,
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?
- 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.
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?
- Reset MAY cause a specific fingerprint of power consumption. We may measure the power consumption and trigger vcc glitching when this fingerprint occurs.
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,