mspbsldump/README.md

104 lines
5.3 KiB
Markdown
Raw Normal View History

2022-04-09 01:56:33 +00:00
# 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).
2022-04-09 19:55:52 +00:00
## The idea
2022-04-09 01:56:33 +00:00
2022-04-09 19:55:52 +00:00
The MSP430FR bootloader ('BSL') resides at 0x1000, this memory cannot be read,
2022-04-09 01:56:33 +00:00
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.
2022-04-09 19:55:52 +00:00
## What has been implemented correctly
2022-04-09 01:56:33 +00:00
2022-04-09 19:55:52 +00:00
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.
2022-04-09 01:56:33 +00:00
2022-04-09 19:55:52 +00:00
## Vulnerabilities of the BSL against a readout attack
2022-04-09 01:56:33 +00:00
2022-04-09 19:55:52 +00:00
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.)
2022-04-09 01:56:33 +00:00