more info in readme, fix dump mode

This commit is contained in:
Triss 2022-04-15 02:23:52 +02:00
parent b97e026d9a
commit b1c1aa0806
2 changed files with 43 additions and 17 deletions

View File

@ -92,6 +92,8 @@ described near the end, the article is quite large.
1. Even when returning from an interrupt serviced during BSL execution, it is 1. Even when returning from an interrupt serviced during BSL execution, it is
not possible to return from this interrupt directly back to BSL code, as not possible to return from this interrupt directly back to BSL code, as
this counts as a jump-to-arbitrary-BSL-location. this counts as a jump-to-arbitrary-BSL-location.
1. DMA transfers cannot read from the BSL region at all (not from the Z-area,
not from the BSL region during BSL execution).
## Vulnerabilities of the BSL against a readout attack ## Vulnerabilities of the BSL against a readout attack
@ -182,13 +184,34 @@ normally return into the BSL from user code, doing this would cause a reset.
Luckily, it is still possible to change the program counter on the stack of the Luckily, it is still possible to change the program counter on the stack of the
address returned to, so the experiment can be restarted from the beginning. address returned to, so the experiment can be restarted from the beginning.
`0x1b00` halts the CPU by writing some code into tiny RAM (at address `0`) that
sets the CPU in a low power mode and performs an infinite loop. It then jumps
to that code.
`0x1b02` and `0x1b04` eventually converge to address `0x1bea`, where NMI
tracing starts failing for a yet unknown reason. It does not seem to be an "NMI
disable" instruction (by writing to an SFR or SYS register), as using DMA to
continuously rewrite these registers with values that enable these signals,
doesn't seem to work. It does not disable the UART, as LEDs used in debugging
stop blinking at this moment as well.
At this point in, the second BSL code has not performed any stack accesses or
memory-to-register reads.
As `0x1b02` is called from the main BSL code as part of the "mass-erase FRAM"
command, it most likely implements this functionality, and hardly anything
else.
## Proof of concept ## Proof of concept
The code in `src/main.c` will dump the content of the BSL to `eUSCI_A0` in UART The code in `src/main.c` will dump the content of the BSL to `eUSCI_A0` in UART
mode. Tested on an MSP430FR5994, but no other chips. mode, at 9600 baud. Tested on an MSP430FR5994, but no other chips.
By setting the `DUMP_MODE` preprocessor definition to 0, it can instead be used By setting the `DUMP_MODE` preprocessor definition to 0, it can instead be used
as an instruction tracer, accompanied by `logtracer.py`. as an instruction tracer, accompanied by `logtracer.py`. Setting `USE_NMI` to 1
will use an NMI-based tracer instead of a `Timer_A`-based one. The address to
jump to (to trace) will still have to be changed manually in the `do_trace()`
function body.
## Useful shellcode ## Useful shellcode

View File

@ -75,12 +75,12 @@ static void pico_wait_ack(void) {
/*#define SKIP_CYC_OFF 5*/ /*#define SKIP_CYC_OFF 5*/
// DUMP_MODE == 0 => insn trace mode // DUMP_MODE == 0 => insn trace mode
#define DUMP_MODE 0 #define DUMP_MODE 1
#define DUMP_CYC_OFF 14 #define DUMP_CYC_OFF 14
#define DUMP_ADDR_START (0x1000+2) /* there's an off-by-4 error */ #define DUMP_ADDR_START (0x1000) /* there's an off-by-4 error */
#define DUMP_ADDR_END 0x1800 #define DUMP_ADDR_END 0x17fc
#define USE_NMI 1 #define USE_NMI 0
#if USE_NMI #if USE_NMI
#define STORAGE #define STORAGE
@ -116,7 +116,9 @@ __attribute__((
, __no_inline__, __used__)) , __no_inline__, __used__))
void do_trace(void) { void do_trace(void) {
const bool nmi = USE_NMI; const bool nmi = USE_NMI;
#if USE_NMI
P1OUT ^= BIT1; P1OUT ^= BIT1;
#endif
// TODO: chain 2 timers for 32 bit tick number // TODO: chain 2 timers for 32 bit tick number
// TODO: continue instead of restarting? // TODO: continue instead of restarting?
@ -174,12 +176,8 @@ void do_trace(void) {
#endif #endif
#if USE_NMI #if USE_NMI
// send trigger // send trigger
"mov.w #0xa5a5, 0x1c00\n"
"bis.w #0x10, P1OUT\n" "bis.w #0x10, P1OUT\n"
#else
//TA1CTL = TASSEL__SMCLK | ID__1 | MC__UP | TACLR | TAIE;
"mov.w #0x0216, TA1CTL\n"
"eint\n"
#endif
"nop\n" "nop\n"
"nop\n" "nop\n"
"nop\n" "nop\n"
@ -214,9 +212,15 @@ void do_trace(void) {
"push.w r13\n" "push.w r13\n"
"mov.w #2, r12\n" "mov.w #2, r12\n"
"br #0x1b02\n" // CHANGEME (address to trace insn flow of) "br #0x1b02\n" // CHANGEME (address to trace insn flow of)
#else
//TA1CTL = TASSEL__SMCLK | ID__1 | MC__UP | TACLR | TAIE;
"mov.w #0x0216, TA1CTL\n"
"eint\n"
"br #0x1002\n"
#endif
//#if !USE_NMI //#if !USE_NMI
"1: jmp 1b\n" "1: jmp 1b\n"
//#endif //#endif*/
); );
//#if !USE_NMI //#if !USE_NMI
while (1) ; while (1) ;
@ -251,14 +255,14 @@ void do_collect(uint16_t* sp) {
uint16_t v1 = sp[2*(12-4)]; uint16_t v1 = sp[2*(12-4)];
uint16_t v2 = sp[2*(13-4)]; uint16_t v2 = sp[2*(13-4)];
if ((curaddr & 0xf) == 0x2) { if ((curaddr & 0xf) == 0x0) {
iprintf("%04x: ", curaddr-2/*correct off-by-2 error*/); iprintf("%04x: ", curaddr-0/*correct off-by-2 error*/);
} }
iprintf("%02x %02x %02x %02x ", iprintf("%02x %02x %02x %02x ",
v1 & 0xff, (v1 >> 8) & 0xff, v1 & 0xff, (v1 >> 8) & 0xff,
v2 & 0xff, (v2 >> 8) & 0xff v2 & 0xff, (v2 >> 8) & 0xff
); );
if ((curaddr & 0xf) == 0xe) { if ((curaddr & 0xf) == 0xc) {
iprintf("\r\n"); iprintf("\r\n");
} }
#else #else
@ -311,7 +315,6 @@ next_iter:
++curticks; ++curticks;
#endif #endif
#if USE_NMI #if USE_NMI
//P1OUT ^= BIT1;
// return... // return...
#else #else
do_trace(); do_trace();
@ -501,8 +504,8 @@ CODESP int main(void) {
#if USE_NMI #if USE_NMI
pico_send_cmd('0'); pico_send_cmd('0');
pico_wait_ack(); pico_wait_ack();
#endif
dma_init(); dma_init();
#endif
do_trace(); do_trace();
/*while(1);*/__builtin_unreachable(); /*while(1);*/__builtin_unreachable();