From b1c1aa0806c4c3609c81f43a1b66b48d74ef69d5 Mon Sep 17 00:00:00 2001 From: sys64738 Date: Fri, 15 Apr 2022 02:23:52 +0200 Subject: [PATCH] more info in readme, fix dump mode --- README.md | 27 +++++++++++++++++++++++++-- src/main.c | 33 ++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index c8473b7..b4a3aa0 100644 --- a/README.md +++ b/README.md @@ -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 not possible to return from this interrupt directly back to BSL code, as 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 @@ -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 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 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 -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 diff --git a/src/main.c b/src/main.c index 15d52dc..14d0489 100644 --- a/src/main.c +++ b/src/main.c @@ -75,12 +75,12 @@ static void pico_wait_ack(void) { /*#define SKIP_CYC_OFF 5*/ // DUMP_MODE == 0 => insn trace mode -#define DUMP_MODE 0 +#define DUMP_MODE 1 #define DUMP_CYC_OFF 14 -#define DUMP_ADDR_START (0x1000+2) /* there's an off-by-4 error */ -#define DUMP_ADDR_END 0x1800 +#define DUMP_ADDR_START (0x1000) /* there's an off-by-4 error */ +#define DUMP_ADDR_END 0x17fc -#define USE_NMI 1 +#define USE_NMI 0 #if USE_NMI #define STORAGE @@ -116,7 +116,9 @@ __attribute__(( , __no_inline__, __used__)) void do_trace(void) { const bool nmi = USE_NMI; +#if USE_NMI P1OUT ^= BIT1; +#endif // TODO: chain 2 timers for 32 bit tick number // TODO: continue instead of restarting? @@ -174,12 +176,8 @@ void do_trace(void) { #endif #if USE_NMI // send trigger + "mov.w #0xa5a5, 0x1c00\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" @@ -214,9 +212,15 @@ void do_trace(void) { "push.w r13\n" "mov.w #2, r12\n" "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 "1: jmp 1b\n" -//#endif +//#endif*/ ); //#if !USE_NMI while (1) ; @@ -251,14 +255,14 @@ void do_collect(uint16_t* sp) { uint16_t v1 = sp[2*(12-4)]; uint16_t v2 = sp[2*(13-4)]; - if ((curaddr & 0xf) == 0x2) { - iprintf("%04x: ", curaddr-2/*correct off-by-2 error*/); + if ((curaddr & 0xf) == 0x0) { + iprintf("%04x: ", curaddr-0/*correct off-by-2 error*/); } iprintf("%02x %02x %02x %02x ", v1 & 0xff, (v1 >> 8) & 0xff, v2 & 0xff, (v2 >> 8) & 0xff ); - if ((curaddr & 0xf) == 0xe) { + if ((curaddr & 0xf) == 0xc) { iprintf("\r\n"); } #else @@ -311,7 +315,6 @@ next_iter: ++curticks; #endif #if USE_NMI - //P1OUT ^= BIT1; // return... #else do_trace(); @@ -501,8 +504,8 @@ CODESP int main(void) { #if USE_NMI pico_send_cmd('0'); pico_wait_ack(); -#endif dma_init(); +#endif do_trace(); /*while(1);*/__builtin_unreachable();