add readme
This commit is contained in:
parent
7f1c85134d
commit
b43120968d
|
@ -0,0 +1,65 @@
|
|||
# MSP430FR BSL dumper
|
||||
|
||||
Tools to try to dump the MSP430FR BSL, mainly targetting the [MSP430FR5994
|
||||
](https://www.ti.com/product/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
|
||||
](https://www.ti.com/lit/ug/slau550aa/slau550aa.pdf)) 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
|
||||
](http://problemkaputt.de/gbatek-bios-dumping.htm) and [here
|
||||
](http://problemkaputt.de/gbatek-ds-memory-control-bios.htm), but is also
|
||||
described in the academic literature, eg. [here
|
||||
](https://www.usenix.org/system/files/woot19-paper_schink.pdf).
|
||||
|
||||
The "use DMA to get ROP" trick comes from [here
|
||||
](https://hexkyz.blogspot.com/2021/11/je-ne-sais-quoi-falcons-over-horizon.html),
|
||||
described near the end, the article is quite large.
|
||||
|
||||
## What has been found
|
||||
|
||||
1. `0x1000` is a jump to `0x1014`.
|
||||
1. `0x1002` is a jump to `0x1028`.
|
||||
1. The other code in the Z-Area are infinite loops (to itself, instruction `ff 3f`).
|
||||
|
||||
### 0x1014 (BSL_main())
|
||||
|
||||
1. `0x1014` sets `sp` to `0x3c00`.
|
||||
1. It then calls `0x16fa` which fills a lot of RAM
|
||||
|
Loading…
Reference in New Issue