more info in readme, fix dump mode
This commit is contained in:
parent
b97e026d9a
commit
b1c1aa0806
27
README.md
27
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
|
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
|
||||||
|
|
||||||
|
|
33
src/main.c
33
src/main.c
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue