
Reverse engineering an e-scooter and rewriting its firmware in Rust
Ben Simms reverse engineered his Egret GT e-scooter’s CAN bus, dumped its firmware through an exposed debug port and then wrote new display firmware in Rust — after finding that updates had no authentication at all.
An engineer who goes by Ben has published a detailed account of reverse engineering his Egret GT e-scooter: from the Bluetooth app that talks to it, through the CAN bus hidden inside its USB-C port, to new firmware for the display unit written in Rust.
The scooter, bought last year, advertises a 100 km range and a 320x480 LCD display used as a head-up display for speed, driving mode, battery level and range. The project began with a small annoyance: holding the down button on the keypad while switching the scooter on entered a firmware update mode, and leaving that menu dropped the rider into normal driving mode without requiring a PIN. “While I always secure the scooter with a reasonably good lock, this still irked me a bit,” he writes.
The app, the bus and a noncompliant USB-C port
Reading the mobile app’s Bluetooth handlers showed that the scooter receives firmware updates over Bluetooth, with separate targets for the display, controller and button panel. It also transmits metrics that never appear in the app — time spent in each driving mode, motor current, battery voltage and charge history — and sends total driving time, odometer and charge history to the manufacturer, stored against the scooter’s ID, which the app never clearly discloses.
Turning to the display’s USB-C port, which the manufacturer describes as a phone charging port, he probed the pins with an oscilloscope and found two of them carrying a CAN bus — a use he calls “horribly noncompliant”. With an ESP32-C6, an SN65HVD230 and an MCP2515 he built a logger and mapped the traffic: message 0x300 carries the driving mode and headlight state, 0x306 the throttle position, blinkers and speed limit, and 0x201 the motor speed and status flags.
Teardowns, firmware dumps and no authentication
Buying a replacement controller and display unit, he found the controller’s flash still carried component markings, spotted a likely SWD header and dumped it with OpenOCD; analysis in Ghidra revealed a bootloader, an updater and the main application at fixed addresses. The display was harder to open, and its board carried an AT32F415 main MCU, a Bluetooth chip, an NFC reader and a flash chip holding only the GUI’s bitmaps.
The update path turned out to be equally open: firmware is written over the CAN bus with no cryptography, in 64-byte chunks across nine frames with a CRC-16-CCITT check, the first chunk carrying only a file name and the firmware length as text. He wrote a flasher, tested it with the image he had dumped, and it worked first time. “It’s possible to modify the firmware of any scooter without authentication,” he notes.
Writing a hardware layer in Rust
The AT32F415 proved to be a mix of STM32 peripherals rather than a clone of one chip, so instead of using the Embassy framework he built a hardware abstraction layer, starting from another developer’s fork of the stm32-rs project, and brought up clocks, timers, the ADC, GPIO interrupts, UART, CAN and the RTC. An mipidsi parallel interface drives the ST7796 screen, a custom Bus type lets the firmware write all 16 GPIOB pins in a single instruction, and deku type definitions let the same structs decode CAN and Bluetooth frames.
SiTech — AI-powered web development
We build fast, modern websites and bring AI into real business workflows. Have a project or a question? We'd love to help.