104 lines
5.3 KiB
Markdown
104 lines
5.3 KiB
Markdown
# 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).
|
|
|
|
## The idea
|
|
|
|
The 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 implemented correctly
|
|
|
|
1. Memory in the BSL region cannot be read using data accesses from user code.
|
|
Reads come back as `3f ff`, which decodes as an infinite loop.
|
|
1. Arbitrary code in the BSL region cannot be jumped to from user code, the
|
|
CPU execution path has to go through the Z-area. Doing this will cause an
|
|
infinite loop or a reset.
|
|
|
|
## Vulnerabilities of the BSL against a readout attack
|
|
|
|
1. When the CPU is executing the BSL, it can perform data accesses to other BSL
|
|
areas. Thus, if an arbitrary read gadget is found, it can be used to dump
|
|
the entire BSL region.
|
|
1. The routine at `0x1002` provides such a gadget, *as indicatd in SLAU550AA*.
|
|
1. The BSL execution is allowed to be interrutped, thus the instruction flow
|
|
can be traced by dumping CPU register values throughout the BSL execution.
|
|
This allows for finding arbitrary read gadgets.
|
|
1. Interrupts can also be used to change any register value while the BSL is
|
|
executing, even at a specific point in time. This can be used to skip over
|
|
certain instructions during analysis, for example.
|
|
|
|
## Vulnerabilities of the BSL against use as a source of ROP gadgets
|
|
|
|
1. The routine at `0x1002` returns quickly, *as indicatd in SLAU550AA*.
|
|
Therefore, it can be used as an easy ROP entrypoint. This bypasses the "only
|
|
call code from the Z-area" limitation.
|
|
1. Interrutps can be used to change return addresses etc., to jump to arbitrary
|
|
locations inside the BSL.
|
|
1. Potentially, DMA transfers can also be used to change the stack contents,
|
|
including return addresses, while the BSL is executing.
|
|
|
|
## Inaccurracies of the datasheets
|
|
|
|
1. The BSL clears all RAM from `0x1C00` to `0x3FC7`, not just `0x1C00` to
|
|
`0x1FFF`.
|
|
1. The BSL also clears Tiny RAM and some "reserved" low addresses, from `6` to
|
|
`0x1F`.
|
|
1. The BSL sets up Timer A, while the datasheet only mentions Timer B usage in
|
|
*other* BSLs, and nothing about this one.
|
|
|
|
## What has not been checked
|
|
|
|
1. Pipelining: can code running at `0x0FFE` (or a similar address) access the
|
|
BSL memory, (mis)using the possibility that the effective value of `pc`
|
|
might differ from the executed address due to pipelining effects? (cf.
|
|
MerryMage's GBA BIOS dump)
|
|
1. DMA: can a DMA transfer be used to change the stack contents during BSL
|
|
execution? (Most likely, just like interrupts can, I simply haven't checked.)
|
|
|