This repository contains the artifacts for the USENIX Security'26 paper: "M-Step: A Single-Stepping Framework for Side-Channel Analysis on TrustZone-M".
M-Step is a software-based single-stepping framework that enables instruction-level side-channel analysis on ARM TrustZone-M enabled microcontrollers. It allows an unprivileged attacker in the Non-Secure world to precisely interrupt and observe the execution of Secure world code at instruction granularity.
- Overview
- Repository Structure
- Hardware Requirements
- Prerequisites
- Quick Start
- Building and Deployment
- Running the Evaluation
- Tools and Utilities
- Extending M-Step
- Troubleshooting
- Citation
- License
M-Step exploits the interrupt mechanism in ARM Cortex-M processors to achieve single-stepping of Secure world code from the Non-Secure world. The framework includes:
- Core M-Step Algorithm: Precise timer-based interrupt injection for single-stepping
- Side-Channel Primitives: Multiple observation channels including:
Mstp-Nemesis: Reveals interrupt-latencies, Nemesis.Mstp-Cache: Reveals cache activity, PRIME+PROVE.Mstp-BUSted: Reveals memory accesses, BUSted.Mstp-Zoom: Amplifies interrupt-latency leakage.
- Analysis Tools: Trace visualization, VCD generation for GTKWave, and automated key extraction
- Proof-of-Concept Attacks: End-to-end RSA key extraction from Mbed TLS
m-step/
├── copilot/ # Build automation scripts and TF-M configurations
├── evaluation/ # Evaluation scripts and datasets
├── m-step/ # M-Step framework source code
├── ns-world-bare/ # Baremetal Non-Secure world runtime
├── s-world/ # Secure world runtime (TF-M, Mbed TLS, MCUboot)
├── flake.nix # Nix development environment
- Target Board: NUCLEO-L552ZE-Q (STM32L5 series with TrustZone-M)
The development environment uses Nix for reproducible builds. Install Nix and add your user to the nix-users group:
sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --no-daemonEnable experimental features by adding to ~/.config/nix/nix.conf or /etc/nix/nix.conf:
experimental-features = nix-command flakes
Download and install STM32CubeProgrammer (requires ST account).
Verify installation:
STM32_Programmer_CLI --versionEnsure STM32_Programmer_CLI is in your PATH.
Create /etc/udev/rules.d/99-stlink.rules with the following content:
# ST-LINK V3 (STM32L5 Discovery / Nucleo)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374e", MODE="0666", GROUP="plugdev"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE="0666", GROUP="plugdev"
Reload udev rules:
sudo udevadm control --reload-rules
sudo udevadm triggerNote: Without these rules,
sudois required for every deployment.
git clone --recurse-submodules https://github.com/M-Step-Framework/m-step.git
cd m-stepnix developThis provides a reproducible shell with all required dependencies (ARM toolchain, CMake, Python packages, GTKWave, etc.).
Note: Run
nix developin every new terminal session.
# Navigate to the baremetal NS world
cd ns-world-bare
# Configure the build system
./0-config.sh
# Compile the Secure and Non-Secure images
./1-compile.sh
# Deploy to the target board
./2-deploy.sh# Start the serial monitor
./3-monitor.sh -o trace.txtThe copilot.sh script provides a unified interface for building and deploying:
cd copilot
# Configure and build the Secure world
./copilot.sh -c s -p mstp
./copilot.sh -b s -p mstp
# Configure and build the Non-Secure world
./copilot.sh -c ns -p mstp
./copilot.sh -b ns -p mstp
# Deploy to target
./copilot.sh -d -p mstp
# Monitor serial output
./copilot.sh -m output.txt| Profile | Description |
|---|---|
bare |
Minimal TF-M configuration |
crypto |
TF-M with crypto services |
mstp |
Full M-Step evaluation setup |
On first deployment, you may need to configure the board's option bytes.
Uncomment the regression.sh line in (copilot.sh) or run manually:
${BUILD_S}/api_ns/regression.shcd evaluation
./1-run-all-tests.sh| Test | Command | Paper Reference |
|---|---|---|
| M-Step Metrics | ./evaluation/t1-mstp_metrics/1-run-test.sh |
Table 5 |
| DIV Instruction Covert Channel | ./evaluation/t2-covert-udiv/1-run-test.sh |
Figure 6a |
| Instruction Timing Covert Channel | ./evaluation/t3-covert-inst/1-run-test.sh |
Figure 6b |
| ICache-based Covert Channel | ./evaluation/t4-covert-cache/1-run-test.sh |
Figure 6c |
| Bus Contention Covert Channel | ./evaluation/t5-covert-cont/1-run-test.sh |
Figure 6d |
| End-to-End PoC Attacks | ./evaluation/t6_pocs/1-run-pocs.sh |
Section 6.3 |
| Trace visualization tests | ./evaluation/t7-printf-gtkwave/1-run-test.sh |
Figure 8 |
cd evaluation/graphs
./1-draw-graphs.sh./1-run-all-tests.sh -cCaptures UART output from the target board:
python3 m-step/mstp-monitor/monitor.py -o trace.txtConverts M-Step traces to VCD format for visualization in GTKWave:
cd m-step/mstp-visualizer
# Generate VCD file
./1-gen-vcd.sh -t /path/to/trace.txt -elf /path/to/tfm_s.elf -o ./outputs
# Open in GTKWave
./2-gtkwave.sh -i ./outputs/trace.vcd- OpenOCD: Hardware debugging configurations
- GDB-Py: Python-enhanced GDB scripts
- Renode: MCU emulation for trace analysis
# List connected boards
STM32_Programmer_CLI -l
# Connect via minicom
minicom -D /dev/ttyACM0 -b 115200
# Or via screen
screen /dev/ttyACM0 115200See m-step/mstp-eval/README.md for detailed instructions on:
- Creating new test files
- Defining test configurations
- Customizing M-Step parameters
Key parameters in m-step/mstp/inc/mstp.h:
| Parameter | Description |
|---|---|
BASE_CLK |
Timer value for interrupt injection |
STREAK_THRESHOLD |
Zero-step detection threshold |
BASE_ISR_TIME |
Interrupt handler overhead |
M-Step supports multiple features which can be enabled on demand via plugins:
| Plugin | Location | Description |
|---|---|---|
| Mstp-Nemesis | m-step/mstp |
Reveals interrupt-latencies, Nemesis [57]. |
| Mstp-Cache | m-step/mstp-cache |
Reveals cache activity, PRIME+PROBE [40, 42]. |
| Mstp-BUSted | m-step/mstp-busted |
Reveals memory accesses, BUSted [46]. |
| Plugin | Location | Description |
|---|---|---|
| Mstp-Zoom | m-step/mstp |
Amplifies interrupt-latency leakage §5.2. |
| Plugin | Location | Description |
|---|---|---|
| Mstp-Production | m-step/mstp |
Single-step for production code. |
| Mstp-Debug | m-step/mstp-debug |
Single-step with debug information. |
| Mstp-Metrics | m-step/mstp-metrics |
Single-step performance metrics. |
| Mstp-Emulator | m-step/mstp-debug |
MCU emulator with side-channel information. |
| Mstp-Visualizer | m-step/mstp-visualizer |
Interactive interface to visualize M-Step traces. |
| Mstp-opDecoder | m-step/mstp-opdecoder |
Runtime library to decode Armv8-M opcodes. |
| Mstp-Test | m-step/mstp-test |
Evaluation and regression testing framework. |
Build Fails with missing tool/dependence:
Probably you forget to enter a nix development shell.
nix developBuild fails with missing headers:
Ensure all submodules are initialized.
git submodule update --init --recursiveIf you use M-Step in your research, please cite our paper:
@inproceedings{rodrigues2026mstep,
title = {{M-Step}: A Single-Stepping Framework for Side-Channel Analysis on {TrustZone-M}},
author = {Rodrigues, Cristiano and Bognar, Marton and Pinto, Sandro and Van Bulck, Jo},
booktitle = {35th USENIX Security Symposium (USENIX Security 26)},
year = {2026},
note = {To appear},
publisher = {USENIX Association}
}This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
Questions or Issues? Please open an issue on GitHub.