Breaking the RS41
The main goal of this project was to dump and inspect the original firmware of the popular Vaisala RS41 meteosonde.
The hardware is already very well researched and there are public repositories documenting the PCBs and individual components used:
On the software side, not much work has been done because of the chip protection. The meteosonde has some pretty neat peripherals that we don't know how to work with, especially the expansion module or NFC communication, so a firmware dump could be quite handy for further reverse engineering.
The RS41 and its pressure module RPM411 use the STM32F100C8 (value line) as the main processor, with key features:
- ARM Cortex-M3 core
- 64 Kbytes flash
- 8 Kbytes SRAM
- 3 USARTy
- 37 GPIO
- debug with ST-LINKem over SWD
- Read out protection ability (RDP)
- Flash write protection (WRP)
By default, the chip is locked against data readout by RDP level 1 in the meteosonde and in the add-on module. What is level 1?
- if debug is connected, it cannot read/change FLASH content, but it can change SRAM
- if booted from SRAM, FLASH cannot be read/changed
- code booted from FLASH can read/change whatever it wants
Apart from invasive methods, it is almost impossible to read the contents of the chip, and it is also not possible to step through the firmware. However, like all software, hardware contains vulnerabilities that could help break protection.
In 2020, three gentlemen (Johannes Obermaier, Marc Schink, Kosma Moczek) presented several ways to break RDP in the STM32F1 and its Chinese clones and make them dump the contents of the flash, for details see https://www.usenix.org/system/files/woot20-paper-obermaier.pdf.
Since the meteosonde contains the original STM chip, we choose the last method, a combination of two errors - power supply manipulation and FPB overwriting. This method proceeds as follows:
move the STM32F1 from the Meteosonde board to the Blue Pill PCB to avoid interfering with power circuits, mainly capacitors.
- power-glitch and FPB override is coordinated by another board, in our case Raspberry Pico W and the picopwner project, so we build the interconnection on a solderless board
- procedure of exploit itself:
- upload a compiled two-phase exploit to SRAM write using ST-LINK
- [controller] RPico do power glitch - remove voltage until RST pin is down (removes RDP cond. caused by debug probe)
- blue pill boots from SRAM
- code in SRAM stage1 sets FPB to redirect the program run to the code from SRAM on reset interupt (0x0...04) - this will de-facto get rid of the condition of booting from SRAM
- [controller] sends reset with boot from FLASH
- overriden reset starts SRAM code, stage2 (0x2....) and dump firmware via Pico UART
There were a couple of problems with this process. At first, the main chip code (written in C) was HardFaulting the controller. Reason still unknown, but I've worked around this by stepping and tweaking the code to just work. With second chip there was a problem with the power glitch itself - it seems that some internal settings affect how long the MCU can be left without power to preserve SRAM. The controller has been updated to fix the glitch time and not wait for RST to be down. The time was simply determined by trial and error.
This heavily edited exploit finally allowed us to dump two firmwares for analysis and much needed step-by-step debugging in the live device.
Using the STM32Programmer, we removed the RDP and WRP and flashed back the firmware - this also means that the chip erases itself for obvious reasons. We then uploaded the dumped firmware. When the chip was rebooted, another problem arose. The firmware was actively running procedures to lock the chip again - so some analysing and patching of the firmware was required to prepare the "open" device.
The RDP locking procedure uses the FLASH_OBR register, so it was quite easy to find the code doing the work by finding the hex value 0x4002201C - address of the register. Later, the function call to this code was overridden with two "mov r8,r8" instructions in both firmwares:
Interesting places in dumps
- 0x08001080 - device setup function, multiple peripherals initialization
- 0x08007478 - chip locking function
- 0x08004bee - hidden code match "STwsv" to show menu
- 0x08004c56 - another hidden code match "HXmcr" to print some kind of debug
- 0x0800abb0 - command menu
Firmware seems to be structurally the same. Setup function with multiple calls to peripherals init, also locking function included.
- 0x08000100 - device setup function, multiple peripherals initialization
- 0x08001e16 - chip locking function
A very handy approach to reverse engineering the firmware is to look at ARM/STM32 registers such as SPI or UART and trace the functions that deal with them.
Captured communication between boards
It appears that all important communication is done via the SPI and not the UART. Dumped transfer is available at spi-dump.txt. It seems that some initialisation is required, as no values are sent - just settings and some sort of regular ping.
- RS41 UART can communicate via command picocom -b 9600 --imap crcrlf /dev/ttyUSB0, just type in "STwsv" and it will show you the menu
- RPM411 UART extension can communicate with picocom -b 19200 --imap crcrlf /dev/ttyUSB0, menu is accessible without any hidden codes - but board powered without connection to RS41 seems to ends up restarted by watchdog. According to http://rayer.g6.cz/elektro/rpm411.htm(CZECH only) solution might be to disable SW watchdog with STM32Programmer, not tested myself.