Dumping the MSP430FR BSL
Go to file
Triss b43120968d add readme 2022-04-09 03:56:33 +02:00
include initial stuff 2022-04-09 03:48:43 +02:00
src initial stuff 2022-04-09 03:48:43 +02:00
.gitignore initial stuff 2022-04-09 03:48:43 +02:00
Makefile initial stuff 2022-04-09 03:48:43 +02:00
README.md add readme 2022-04-09 03:56:33 +02:00
logtracer.py initial stuff 2022-04-09 03:48:43 +02:00
msp430fr5962.ld initial stuff 2022-04-09 03:48:43 +02:00
msp430fr5962_symbols.ld initial stuff 2022-04-09 03:48:43 +02:00
msp430fr5994.ld initial stuff 2022-04-09 03:48:43 +02:00
msp430fr5994_symbols.ld initial stuff 2022-04-09 03:48:43 +02:00

README.md

MSP430FR BSL dumper

Tools to try to dump the MSP430FR BSL, mainly targetting the MSP430FR5994 (on an MSP-EXP430FR5994 devboard).

How

Mhe MSP430FR bootloader ('BSL') resides at 0x1000, this memory cannot be read, and user code can only jump to 0x1000 or 0x1002 to run certian functions of the BSL. Though, it is very likely that when the CPU is running from inside this memory region, it can access this memory as data, because that's often needed to store eg. complex integer values, structs, lookup tables, and so on.

The BSL (according to the datasheet ) doesn't disable interrupts. That means that you can still jump to it, and then interrupt it to jump to code controlled by the user. As this is an interrupt, it can inspect the registers of the BSL code at the time when the interrupt happened, as well as the stack contents. Having a timer at the same frequency as the CPU, and having it dump the register+stack contents after a while, and doing that over and over again while advancing the time-until-interrupt delay by one cycle every iteration, you can get a view of what the CPU is doing while executing this hidden code (also, the MSP430 CPU is multicycling and uses variable-length instructions, so instruction timings and pc deltas can also be used as a side channel to figure out which instruction is which).

Function epilogues typically first pop a bunch of values off the stack and load these back into registers, and then return. Additionally, if you're lucky, you may also find a memory read right before the end of such an epilogue.

You can find these epilogues by staring at many, many execution traces (obtained from these timer interrupts) and thinking really hard (this is the hard, time-consuming and labor-intensive part).

Then, by timing a DMA transfer such that it happens after a function is called but before it returns, it is possible to overwrite the memory popped off the stack when an epilogue executes, thereby gaining control of a few register values, and the program counter. Then you could redirect it to another piece of code that does the memory read before returning. As you now (hopefully) have control over the address it reads from, you can use this as an arbitrary read to read one word of the BSL, then return to use code to do the next iteration.

The "using interrupts to figure out what execute-only code is doing" trick was first (afaik) used by Martin Korth to find such a gadget inside the Nintendo DS ARM7 boot ROM to read it out (and dump some keys), see here and here , but is also described in the academic literature, eg. here .

The "use DMA to get ROP" trick comes from here , described near the end, the article is quite large.

What has been found

  1. 0x1000 is a jump to 0x1014.
  2. 0x1002 is a jump to 0x1028.
  3. The other code in the Z-Area are infinite loops (to itself, instruction ff 3f).

0x1014 (BSL_main())

  1. 0x1014 sets sp to 0x3c00.
  2. It then calls 0x16fa which fills a lot of RAM