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 20:10:12 +00:00
|
|
|
The MSP430FR bootloader ('BSL') resides at `0x1000`. This memory cannot be
|
|
|
|
read, and user code can only jump to `0x1000` or `0x1002`, called the "Z-area",
|
|
|
|
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, as that is often needed to store eg. structs, lookup tables, and so on.
|
|
|
|
Several other "execute-only" memory implementations function in a similar way,
|
|
|
|
such as the Nintendo GameBoy Advance and DS boot ROMS ("BIOS"es, citation
|
|
|
|
below), as well as in other systems analyzed by Schink and Obermaier,
|
|
|
|
publication also linked below.
|
2022-04-09 01:56:33 +00:00
|
|
|
|
|
|
|
The BSL (according to [the datasheet
|
|
|
|
](https://www.ti.com/lit/ug/slau550aa/slau550aa.pdf)) doesn't disable
|
2022-04-09 20:10:12 +00:00
|
|
|
interrupts. That means that, while the BSL is executing, it is possible to
|
|
|
|
interrupt this execution flow to
|
|
|
|
jump to code controlled by the user. An interrupt can inspect and modify
|
2022-04-09 01:56:33 +00:00
|
|
|
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
|
2022-04-09 20:10:12 +00:00
|
|
|
having it dump the register and stack contents after a certain interval increasing
|
|
|
|
by one cycle every iteration, it is possible to trace the instruction flow of
|
|
|
|
the CPU, as well as which registers and stack contents it is accessing, and how,
|
|
|
|
even though the code itself is not visible. Furthermore, the MSP430 CPU uses a
|
|
|
|
variable-length instruction set and instructions can use a variable amount of
|
|
|
|
cycles, therefore these traces can also be used to infer more infromation about
|
|
|
|
which instructions are executed, as the `pc` CPU register will never point to
|
|
|
|
the middle of an instruction, and will only advance to the next instruction
|
|
|
|
depending on how long the current instruction takes to execute.
|
|
|
|
|
|
|
|
Function epilogues typically first pop a number of values off the stack and
|
|
|
|
load these back into registers, and then return. By controlling the stack
|
|
|
|
pointer value, these can be used as a way to perform arbitrary reads. However,
|
|
|
|
as we are targetting nonwritable memory, an interrupt needs to happen before
|
|
|
|
the return occurs, otherwise CPU execution becomes very unpredictable.
|
2022-04-09 01:56:33 +00:00
|
|
|
|
|
|
|
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).
|
|
|
|
|
2022-04-09 20:10:12 +00:00
|
|
|
Alternatively, by timing an interrupt or 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 as well as the program counter. Then, CPU
|
|
|
|
execution can be redirected to another code snippet performing the memory read
|
|
|
|
before returning. With control over the address it reads from, this can be used
|
|
|
|
as an arbitrary read to read one word of the BSL, then return to use code to do
|
|
|
|
the next iteration.
|
2022-04-09 01:56:33 +00:00
|
|
|
|
|
|
|
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
|
2022-04-09 20:10:12 +00:00
|
|
|
the entire BSL region. This is the same issue as present in the Nintendo
|
|
|
|
DS ARM7 boot ROM.
|
2022-04-09 19:55:52 +00:00
|
|
|
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`.
|
2022-04-09 21:06:02 +00:00
|
|
|
1. ~~The BSL sets up Timer A, while the datasheet only mentions Timer B usage
|
|
|
|
in *other* BSLs, and nothing about this one.~~ This is wrong, it changes the
|
|
|
|
clock settings, which has an influence on which clock source a timer uses.
|
2022-04-10 00:43:28 +00:00
|
|
|
1. The BSL communication method does not depend on the part number (eg. 5994 vs
|
|
|
|
59941), only the values in TLV are checked.
|
|
|
|
1. While the code has paths for other UART baudrate settings for the
|
|
|
|
communication interface, only one is available.
|
|
|
|
1. The memory area from `0x1b00` to `0x1bff` also contains ROM code, with its
|
|
|
|
own Z-area (also at the beginning, also 8 bytes in size). It has three
|
|
|
|
entrypoints, the fourth is an infinite loop. (`0x3c00..0x3fff` looks like
|
|
|
|
the same type of execute-only memory at first, but actually contains nothing,
|
|
|
|
at least not according to the techniques used here.)
|
2022-04-09 19:55:52 +00:00
|
|
|
|
|
|
|
## 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.
|
2022-04-09 20:26:45 +00:00
|
|
|
[MerryMage's GBA BIOS dump](https://mary.rs/lab/gbabios/))
|
2022-04-09 19:55:52 +00:00
|
|
|
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-10 00:43:28 +00:00
|
|
|
1. Dumping of the `0x1b00`..`0x1bff` region still needs to happen.
|
2022-04-09 01:56:33 +00:00
|
|
|
|
2022-04-09 20:10:12 +00:00
|
|
|
## Hashes
|
|
|
|
|
|
|
|
This is the hash of the memory region `0x1000` to `0x17FF`, on an MSP430FR5994,
|
|
|
|
with BSL 00.08.35.B3:
|
|
|
|
|
|
|
|
| Hash function | value |
|
2022-04-09 20:11:50 +00:00
|
|
|
| ----- | ----- |
|
2022-04-09 20:10:12 +00:00
|
|
|
| MD5 | `4bb3bb753face80fffe1fef7a762884a` |
|
|
|
|
| SHA-1 | `1b4c13e006121a9b1c1ebcd4fbc6ec7c96cc017f` |
|
|
|
|
| SHA-256 | `e4d0d171013f847a357eebe5467bcd413ecb41dc01424b7e4ee636538d820766` |
|
|
|
|
| SHA-512 | `fed28a7e9643a551789075b79d9b04fa6e8cdca74d783c1c3830ece07e5c9141dda9532b3c442416a1ddab90d752e679c6918c0d5333ac6da9fd23ab6c33d1bb` |
|
|
|
|
|
2022-04-10 00:43:28 +00:00
|
|
|
## Region 2 WIP stuff
|
|
|
|
|
|
|
|
* `0x1b00` entrypoint: basically halts the CPU. Not very useful.
|
|
|
|
* `0x1b02` jumps to `0x1bc2` which almost immediately disables interrupts.
|
|
|
|
* `0x1b04` jumps to `0x1bd6` which almost immediately disables interrupts.
|
|
|
|
|
|
|
|
Haven't been able to get around the IRQ disable thing yet... TODO: try NMI? Or
|
|
|
|
some timer IRQ sneakiness to get around the IRQ disable code.
|
|
|
|
|
2022-04-09 20:14:59 +00:00
|
|
|
## Proof of concept
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
By setting the `DUMP_MODE` preprocessor definition to 0, it can instead be used
|
|
|
|
as an instruction tracer, accompanied by `logtracer.py`.
|
|
|
|
|