diff --git a/README.md b/README.md index fc10833..cc1599b 100644 --- a/README.md +++ b/README.md @@ -5,40 +5,51 @@ Tools to try to dump the MSP430FR BSL, mainly targetting the [MSP430FR5994 ## 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 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. 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 +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 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). +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 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. +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. 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. +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. 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 @@ -64,7 +75,8 @@ described near the end, the article is quite large. 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. + the entire BSL region. This is the same issue as present in the Nintendo + DS ARM7 boot ROM. 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. @@ -101,3 +113,14 @@ described near the end, the article is quite large. 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.) +## Hashes + +This is the hash of the memory region `0x1000` to `0x17FF`, on an MSP430FR5994, +with BSL 00.08.35.B3: + +| Hash function | value | +| MD5 | `4bb3bb753face80fffe1fef7a762884a` | +| SHA-1 | `1b4c13e006121a9b1c1ebcd4fbc6ec7c96cc017f` | +| SHA-256 | `e4d0d171013f847a357eebe5467bcd413ecb41dc01424b7e4ee636538d820766` | +| SHA-512 | `fed28a7e9643a551789075b79d9b04fa6e8cdca74d783c1c3830ece07e5c9141dda9532b3c442416a1ddab90d752e679c6918c0d5333ac6da9fd23ab6c33d1bb` | +