I have a strange obsession with the STM8 microcontroller. Arguably because it’s so cheap (you could get in in bulk from <0,40€ per piece or for 0,60€ on a dev-board), but powerful and versatile at the same time, due to:
- lots of GPIOs
- UART/SPI/I2C/ADC
- low power
- proper interrupts
- works both at 3.3V and 5V
When investigating radio communication for some hobby projects a few years I stumbled upon the HC-12 module which easily adds wireless serial communication to your project. It’s essentially an STM8 that controls a Si4463 radio IC. Which got me thinking that it’d be nice to run my software directly on the STM8 instead of requiring an additional one. Unfortunately there’s no open-source firmware for the device (there is https://github.com/al177/hc12pj, but it’s not really functional), so I thought about modifying the original firmware to add my own handlers.
And so this story begins. And yes, I may have nerded out about this in the process…
Part 1: Acquiring the firmware
Unfortunately the HC-12 firmware isn’t public. While the datasheet mentions an AT+UPDATE
command for firmware updates,
I wasn’t able to find further documentation on this nor any firmware images.
Buffer overflows
My initial attempts to cause buffer-overflows weren’t really successful. I definitely triggered some undefined behavior and was likely able to dump some RAM, but if the target registers (e.g. of counters) are 8-bit wide that isn’t sufficient to dump the whole firmware.
SWIM Debug Interface
The STM8 has a debug interface via the SWIM pin (and I may have already written a tool to directly interact with it). The HC-12 has the readout protection option bytes set though. While you can reprogram the device, you cannot read out the firmware.
Glitching
My next attempt was to glitch the chip and bypass the readout protection.
The MCU booted the readout protection wasn’t active and I was able to use the SWIM debug interface to dump the complete firmware.
Part 2: Understanding the firmware
The firmware image itself is of little use if you can’t understand it. I couldn’t find a useful disassembler. There was an IDA 6 plugin (Stm8Ida) and I tried to port it to IDA 7, but never really finished and took on different projects. Until a year later when I discovered that someone had in fact ported it.
A few evening of exploration yielded a good enough understanding of the internals. I identified a few sections of code that can probably be replaced with custom things. Now to make this available to others I’d need to provide the firmware dump which would probably cause copyright issues. So instead it’d be much nicer to provide others the ability to extract the firmware themselves.
During the firmware analysis I also found the code responsible for handling the AT+UPDATE
command and it can
indeed be used to reprogram the device. I wrote a little tool that adds code to dump the firmware into a section
of the AT+VERSION
command handler and then executes it to retrieve a firmware dump.
TODO datasheets
Part 3: Customizing the firmware
There’s about 1.2kb usable space for code & data without compromising any of the core functionalities. That should be enough for many use-cases. Expect more on this soon.
2024 Update
Customizing the firmware turned out not to be a viable option, so I experimented with a complete custom rewrite. Unfortunately I didn’t get around to finishing it, but the somewhat working (but still incomplete) state is available at: https://github.com/rumpeltux/hc12fw
Meanwhile others started to take interest in this too: https://github.com/papadeltasierra/hc12x/tree/start