logo
Kurashizu Blogwhere ideas flow
  • Home
  • News
  • Blog
  • About
  • Home
  • News
  • Blog
  • About

© 2026 Kurashizu. All rights reserved.

Admin·New Post·Service Status
Powered by Cloudflare·03.11.26
← Back to news

Reverse engineering my e-scooter and rewriting the firmware in Rust

Original article
bensimms.moe|198 points|54 comments|by vinhnx|Sep 10, 2026

Deconstructing My E-Scooter: Hardware Hacking and Rust Firmware

Published on 2026-08-09 by Ben

I recently embarked on a project to reverse engineer both the hardware and the firmware of my Egret GT E-Scooter. In this write-up, I detail my entry point, the analysis of inter-component communication, and the process of dissecting the firmware.

🛴 The Target: Egret GT

The Egret GT is a premium e-scooter boasting a ≈100km\approx 100\text{km}≈100km range and oversized tires for a smooth ride. To signal its "high-end" status, it features a 320x480 LCD HUD that displays:

  • Current Speed
  • Active Driving Mode
  • Battery Percentage
  • Estimated Remaining Range

🛠️ The Motivation

Driven by an uncontrollable urge to tinker with everything I own, I began investigating the system's internals. The catalyst was a discovery regarding the keypad: holding the 'down' button during power-up →\rightarrow→ enters firmware update mode.

Interestingly, exiting this menu via a button press lands the user in "driving mode," effectively bypassing the PIN requirement. While I use a physical lock for security, this software vulnerability was a curiosity I couldn't ignore.

📱 Phase 1: Mobile App & Bluetooth Analysis

I started by analyzing the companion mobile app, which handles remote unlocking, settings, and battery monitoring. By auditing the Bluetooth handlers, I uncovered several secrets:

  1. OTA Updates: The scooter supports firmware updates over Bluetooth for the display, controller, and button panel.
  2. Hidden Telemetry: The app transmits data not visible to the user, including:
    • Duration spent in each driving mode.
    • Hardware temperature and motor current.
    • Battery voltage and charging logs.
  3. Data Privacy:

    Total driving time, odometer readings, and charge history are transmitted to the manufacturer and linked to the scooter's ID—a behavior not explicitly disclosed in the app's documentation.

The VIN Spoofing Experiment

The scooter is "blank" regarding its Vehicle Identification Number (VIN) until the app connects and assigns one. I attempted to spoof the VIN of a 45km/h model to see if the speed governor was a simple software check.

Result: Spoofing≠Higher Speed\text{Spoofing} \neq \text{Higher Speed}Spoofing=Higher Speed. The limit is implemented more robustly than a simple VIN check.


🔌 Phase 2: The USB-C "Mystery"

I shifted my focus to the USB-C port on the display. While the manufacturer claims this is solely for charging phones, my testing showed that the data pins didn't trigger standard USB host or device behavior.

I decided to probe the pins with an oscilloscope, leading to a shocking discovery:

Pin Function (Official)Pin Function (Actual)Compliance Status
Power/Ground (Charging)Power/GroundCompliant
Data ±\pm±CAN Bus❌ Horribly Non-compliant

📡 Phase 3: CAN Bus Sniffing

To intercept this traffic, I constructed a custom logger (see Figure 2) using the following components:

  • ESP32-C6
  • SN65HVD230 (Transceiver)
  • MCP2515 (Controller)

Why two transceivers? The SN65HVD230 worked perfectly for listening via the ESP-CAN peripheral but triggered bus errors during transmission. However, I kept it because the Rust library I used provided an async interface for it, which simplified the implementation of my state machine.

Reverse Engineering Workflow

📊 The Data Log

I initialized the CAN peripherals and recorded the following frames during the scooter's boot sequence:

// Logged CAN Traffic
1  CAN_FRAME:1024, false, [0, 40, 87, 4, 0, 0, 0, 0]
2  CAN_FRAME:1025, false, [74, bd, 0, 0, 16, c, 0, 0]
3  CAN_FRAME:1028, false, [20, 4e, 0, 0, 1, 0, b9, b]
4  CAN_FRAME:1024, false, [0, 40, 87, 4, 0, 0, 0, 0]
5  CAN_FRAME:1025, false, [74, bd, 0, 0, 16, c, 0, 0]
6  CAN_FRAME:1028, false, [20, 4e, 0, 0, 1, 0, b9, b]
7  CAN_FRAME:513,  false, [0, 0, 0, 0, 0]
8  CAN_FRAME:515,  false, [0, 0, 0, 0, 0, 0, 21, 0]
9  CAN_FRAME:528,  false, [0, 0, 0, 0, 0, 0, 0, 0]
...
43 CAN_FRAME:774,  false, [55, 0, 0, 0, 2, 0, 0, 0]
44 CAN_FRAME:513,  false, [0, 0, 0, 0, 0]
45 CAN_FRAME:515,  false, ...

Project Checklist

  • Analyze Mobile App Bluetooth handlers
  • Attempt VIN spoofing for speed unlock
  • Probe USB-C port with oscilloscope
  • Build CAN bus sniffer with ESP32-C6
  • Capture and log boot sequence frames
  • Rewrite firmware in Rust (In Progress)