Skip to content

5. FaultyCMD Usage

Carlos Alatorre edited this page Jul 14, 2026 · 1 revision

Warning

If you are moving from previous FaultyCat firmware and tools, you will need to first update the FaultyCat's firmware. See Update Firmware.

To start using FaultyCMD, you can open a new terminal session and use the command:

faultycmd

You will see the main view of the CLI:

╭─ Electronic Cats - PWNLAB ─────────────────────────────────────────────────────────────────────────╮
│                                                                                                    │
│        :=--             --=-       |                                                               │
│        -====-         -=====       |                                                               │
│        :===================-       |                                                               │
│         ===================:       |                                                               │
│    -   :==--===========--==-   -   |  faultycmd                                                    │
│   -===:===-   :=====-   -==-.-=--  |  vX.X.X                                                       │
│  --    ====-   :===-   -====    -- |  One pulse closer to a root shell.                            │
│  -=:   :===================-   .=- |                                                               │
│   ---=-- -===============-  -=---  |                                                               │
│   ---       --=======--        --  |                                                               │
│                                                                                                    │
╰────────────────────────────────────────────────────────────────────────────────────────────────────╯
Usage: faultycmd.exe [OPTIONS] COMMAND [ARGS]...

  faultycmd: All in one FaultyCat tools environment.

Options:
  --ignore-version-mismatch  Bypass the firmware/host version parity check on
                             every connect. Unsafe — only use for development
                             against a hand-built UF2.
  --help                     Show this message and exit.

Commands:
  campaign    Run automated parameter sweeps.
  completion  Install shell tab completion for faultycmd.
  crowbar     Control the crowbar (voltage glitch on the target).
  devices     List FaultyCat interfaces detected on this machine.
  emfi        Control the EMFI module (electromagnetic fault injection).
  i2c         Scan and probe the target's I2C bus (rides the scanner CDC).
  la          Protocol-agnostic logic analyzer (captures GP0..GP7).
  scanner     Scan the target's SWD pinout.
  tui         Launch the interactive dashboard.
  uart        Control and bridge the Target UART passthrough.
  update      Download and flash the firmware build matching this host...
  verify      Run a communication smoke test against every detected...

Usage

The correct usage of faultycmd is the following:

faultycmd [OPTIONS] COMMAND [ARGS]
[OPTIONS] Description
--version Show the current version of faultycmd running
--ignore-version-mismatch Bypass the firmware/host version parity check on every connect. Unsafe — only use for development against a hand-built UF2
--help Show the available OPTIONS and COMMAND
COMMAND Description
campaign Run automated parameter sweeps
completion Install shell tab completion for faultycmd (Linux and macOS only)
crowbar Control the crowbar (voltage glitch on the target)
devices List FaultyCat interfaces detected on this machine
emfi Control the EMFI module (electromagnetic fault injection)
i2c Scan and probe the target's I2C bus (rides the scanner CDC)
la Protocol-agnostic logic analyzer (captures GP0..GP7)
scanner Scan the target's SWD pinout
tui Launch the interactive dashboard
uart Control and bridge the Target UART passthrough
update Download and flash the firmware build matching this host
verify Run a communication smoke test

Checking the connected devices

Before performing any operation, it is recommended to verify that the system correctly detects the FaultyCat. To do this, run the command:

faultycmd devices

Important

If faultycmd is not able to see the FaultyCat connected, this may indicate there is a problem with the serial port permissions for your user.

Example of expected output when having a FaultyCat with the compatible firmware connected:

╭─ Electronic Cats - PWNLAB ─────────────────────────────────────────────────────────────────────────╮
│                                                                                                    │
│        :=--             --=-       |                                                               │
│        -====-         -=====       |                                                               │
│        :===================-       |                                                               │
│         ===================:       |                                                               │
│    -   :==--===========--==-   -   |  faultycmd devices                                            │
│   -===:===-   :=====-   -==-.-=--  |  vX.X.X                                                       │
│  --    ====-   :===-   -====    -- |  Your silicon's worst Tuesday.                                │
│  -=:   :===================-   .=- |                                                               │
│   ---=-- -===============-  -=---  |                                                               │
│   ---       --=======--        --  |                                                               │
│                                                                                                    │
╰────────────────────────────────────────────────────────────────────────────────────────────────────╯
Found 4 FaultyCat interface(s)
╭──────┬─────────────┬────────╮
│   IF │ role        │ device │
├──────┼─────────────┼────────┤
│ 0x00 │ emfi        │ COMXX  │
│ 0x02 │ crowbar     │ COMXX  │
│ 0x04 │ scanner     │ COMXX  │
│ 0x06 │ target-uart │ COMXX  │
╰──────┴─────────────┴────────╯
✓ Firmware: vX.X.X.X  (board match)

Note

Ports are automatically assigned by the operating system.

Then run the following command to run a communication smoke test against every detected interface (EMFI ping+status, crowbar ping+status, scanner shell help, target-UART CDC open). Use this right after flashing new firmware or wiring up a board for the first time. Add -q or --quiet for just the PASS/FAIL summary.

faultycmd verify

Update Firmware

Downloads the .uf2 asset from the latest ElectronicCats/faultycat-firmware GitHub release and flashes it over the RP2040's UF2 bootloader. If the board is not already in boot mode, a remote 1200-baud trigger is tried first (the same "magic baud" convention as picotool reboot -f -u), no button press needed. Only if no FaultyCat CDC is detected do you get prompted to put the board in boot mode manually (it enumerates as an RPI-RP2 USB drive).

Usage:

faultycmd update

Campaign (Automated Parameter Sweeps)

Instead of firing one individual shot at a time, Campaign mode automates a continuous search across an entire parameter space. Used for a parameter-space search during an actual fault-injection attack.

Usage:

faultycmd campaign [OPTION] COMMAND [ARGS]
[OPTIONS] Description
--engine Engine to run the sweep on; use emfi or crowbar (default: crowbar)
--port Override the port
--help Show the available OPTIONS and COMMAND
COMMAND Description
configure Define the sweep ranges
drain Download the accumulated sweep results
start Start the sweep
status Show the state of the running sweep
stop Stop the running sweep
watch Follow the sweep live until it completes
ARG Description
Configuration [ARGS] -
--delay Delay range in µs (START:END:STEP, or a fixed value). This argument is required
--width Pulse width range (µs on EMFI, ns on crowbar). This argument is required
--power Power range. On crowbar: 1=low, 2=high. Ignored on EMFI. This argument is required
--settle-ms Settle time between shots in ms (default: 0). This argument is required
Drain [ARGS] -
--max Records per request (max 18). [default: 18]
Watch [ARGS] -
--every-ms Update interval in ms (default: 200)

Example:

faultycmd campaign --engine crowbar configure --delay 1000:5000:100 --width 100:500:50 --power 1:2:1 --settle-ms 10
faultycmd campaign --engine crowbar start
faultycmd campaign --engine crowbar watch          # live table until done
faultycmd campaign --engine crowbar drain --max 18 # pull buffered results
faultycmd campaign --engine crowbar stop           # abort early

Each axis is START:END:STEP (or a single fixed value, e.g., --power 2). Watch follows the sweep live in a Rich table; drain pulls whatever results have accumulated in the firmware's ring buffer (max 18 per request) without waiting for completion.


Crowbar (Voltage Glitch)

The Crowbar technique forces the target chip to misbehave by briefly shorting its power supply (VCC to GND) using a power N-MOSFET.

This causes a sudden, momentary drop (a voltage dip) in the target chip's power.

The sudden drop violates the setup and hold time requirements of the target chip's flip-flops, causing internal bits to flip right as they try to latch.

The ultimate goal is to make the target chip skip an instruction or fail open during a crucial security check (like authentication or a bootloader lifecycle gate).

Usage:

faultycmd crowbar [OPTION] COMMAND [ARGS]
[OPTIONS] Description
--port Override the crowbar port
--help Show the available OPTIONS and COMMAND
COMMAND Description
arm Arm the crowbar
configure Configure the parameters for the next glitch
disarm Disarm the crowbar
fire Wait for the trigger and fire the glitch
ping Verify communication with the crowbar
status Show the current state of the crowbar
ARG Description
Configuration [ARGS] -
--trigger Options: immediate, ext_rising, ext_falling, ext_pulse_pos, ext_pulse_neg (default: immediate)
--output Options: lp = low power, hp = high power (real glitch). Default: hp
--delay-us Delay after the trigger in µs (default: 0)
--width-ns Pulse width in ns (8 to 50000). Default:200
Fire [ARGS] -
--trigger-timeout-ms Max time to wait for the trigger in ms. Default: 60000

Usage example:

faultycmd crowbar ping
faultycmd crowbar configure --trigger immediate --output hp --delay-us 0 --width-ns 200
faultycmd crowbar arm
faultycmd crowbar fire
faultycmd crowbar status
faultycmd crowbar disarm

--output lp is low power (safe to test the link); --output hp is the real glitch.


EMFI

The Electromagnetic Fault Injection (EMFI), unlike voltage glitching techniques that manipulate the power delivery network, EMFI operates remotely by utilizing localized magnetic fields to disrupt internal chip operations.

Usage:

faultycmd emfi  [OPTION] COMMAND [ARGS]
[OPTIONS] Description
--port Override the EMFI port
--help Show the available OPTIONS and COMMAND
COMMAND Description
arm Arm the module (charge the high-voltage capacitor)
capture Read the analog capture from the last fire
configure Configure the parameters for the next EMFI fire
disarm Disarm the EMFI module
fire Wait for the trigger and fire the EMFI pulse
ping Verify communication with the EMFI module
status Show the current state of the EMFI module
ARG Description
Capture [ARGS] -
--offset Start position within the buffer (default: 0)
--length Bytes to read (max 512 per request). Default: 512
--out Output file (if omitted, prints as hex)
Configuration [ARGS] -
--trigger Options: immediate, ext_rising, ext_falling, ext_pulse_pos, ext_pulse_neg (default: immediate)
--delay-us Delay after the trigger in µs (default: 0)
--width-us Pulse width in ns (1 to 50). Default:5
--charge-timeout-ms Max armed time in ms (0 = 60 s default). Default: 0
Fire [ARGS] -
--trigger-timeout-ms Max time to wait for the trigger in ms. Default: 60000

Usage example:

faultycmd emfi ping                                    # check the link
faultycmd emfi configure --trigger immediate --delay-us 0 --width-us 5                           # set pulse params
faultycmd emfi arm                                      # charge the HV cap
faultycmd emfi fire --trigger-timeout-ms 60000           # wait + fire
faultycmd emfi status                                    # read back state
faultycmd emfi disarm                                     # safe the module
faultycmd emfi capture --length 512 --out capture.bin     # read analog capture

I2C Tools

Auto-discovery of SDA/SCL across all 9 scanner-header channels.

Usage:

faultycmd i2c  [OPTION] COMMAND [ARGS]
[OPTIONS] Description
--port Override the scanner port
--help Show the available OPTIONS and COMMAND
COMMAND Description
probe Rescan I2C addresses on known SDA/SCL pins (skip the full sweep)
scan Detect the target's I2C SDA/SCL pins and ACKed addresses
ARG Description
Probe [ARGS] -
--timeout-s Max probe time in seconds (default: 5.00).
--scan-timeout-s BMax time for the auto-discovery i2c scan (only used if SDA/SCL are omitted). [default: 30.0]
Scanner [ARGS] -
--timeout-s Max scan time in seconds (default: 30.0)

Usage example:

faultycmd i2c scan                          # sweep all 8 header pins for SDA/SCL + ACKed addrs
faultycmd i2c probe 0 1                      # rescan addresses on known pins (skip full sweep)
faultycmd i2c probe                          # SDA/SCL omitted -> auto-discovers via `scan` first

I2C has no fixed pin pair; any of the 8 scanner-header channels can carry SDA/SCL, so the probe accepts omitting the pin arguments to auto-discover them via a full I2C scan first.


Logic Analyzer (Protocol-Agnostic)

The Logic Analyzer captures the raw digital states of the full 8-pin GP0->GP7 scanner-header bank simultaneously. Because it is protocol-agnostic, the firmware does not interpret the hardware channels automatically; any digital signal wired to these pins can be captured and decoded.

Usage:

faultycmd la  [OPTION] COMMAND [ARGS]
[OPTIONS] Description
--port Override the scanner control port (CDC2)
--help Show the available OPTIONS and COMMAND
COMMAND Description
capture Capture a raw GP0..GP7 logic trace with the firmware logic analyzer. Records all 8 scanner-header channels simultaneously at --interval-us µs per sample. Export with --vcd for PulseView/GTKWave, or decode a wired bus on-device with --decode i2/uart (channels selected via --sda/--scl or --rx).
pulseview Arm the firmware's SUMP/OLS mode for a live PulseView capture. Sends la sump enter and disconnects immediately — the firmware then speaks the classic SUMP serial protocol on this same port until it's explicitly released, which sigrok's stock "Openbench Logic Sniffer" (ols) driver expects with no further setup. The full GP0..GP7 bank is captured; pick the decoder you need (I2C/UART/SPI/…) inside PulseView. By default, this also launches PulseView on this same port right away, blocks until you close it, and then forces the firmware back to the text shell (see ScannerClient.force_exit_sump — an explicit protocol byte, not a DTR drop, so it's instant and doesn't depend on how the host OS handles the port close). Pass --no-pulseview to skip launching/waiting and drive PulseView yourself; in that case, nothing releases the port automatically, so re-run this command (with --no-pulseview) once you're done to force the release.
ARG Description
Capture [ARGS] -
--interval-us Sample interval in microseconds (firmware minimum/fastest: 1us — sample_interval_us=0 is treated as 1 by the firmware). [default: 1]
--samples Samples to capture. This shell command streams continuously from the firmware's ring buffer with no hard sample-count ceiling (unlike la pulseview's bounded SUMP_OLS_MAX_SAMPLES=16384 capture) — going well past the default is fine as long as the host keeps draining USB fast enough to avoid an OVERFLOW. [default: 16384]
--binary or --hex Stream raw sample bytes instead of a hexdump — halves USB bytes-on-wire, useful at fast --interval-us. (default: hex)
decode Optionally decode the capture on-device: i2c (SDA/SCL) or uart (RX). [default: none]
--sda I2C SDA channel (--decode i2c). [default: 0]
--scl I2C SCL channel (--decode i2c). [default: 1]
--rx UART RX channel (--decode uart). [default: 0]
--baud UART baud rate (--decode uart). [default: 115200]
--vcd Export the raw GP0..GP7 capture to a VCD file (GTKWave/PulseView/sigrok).
--timeout-s Max capture time in seconds. [default: 10.0]
--trigger or --no-trigger Block the capture window's start until the trigger channel goes low, then back it up with pre-trigger history so a decoder has an idle line to sync on (firmware trig=<ch>, see LA_CAPTURE_TRIGGER_IMPLEMENTATION_PLAN.md). Defaults to on for --decode uart (the motivating case) and off otherwise, so a plain GPIO/raw capture keeps today's immediate-start behavior.
--trigger-ch Trigger channel. Defaults to --rx under --decode uart; required for --trigger with --decode none/i2c.
--trigger-timeout-s Max time to wait for the trigger before giving up (default: same as --timeout-s).
Pulse View [ARGS] -
--pulseview or --no-pulseview Launch PulseView on this port, wait for it to close, then release the port back to the text shell (default: on).

Usage example:

faultycmd la capture --samples 4096 --vcd out.vcd            # raw capture, export to VCD
faultycmd la capture --decode i2c --sda 0 --scl 1             # on-device I2C decode
faultycmd la capture --decode uart --rx 0 --baud 115200        # on-device UART decode
faultycmd la pulseview                                         # arm SUMP/OLS mode, auto-launch PulseView
faultycmd la pulseview --no-pulseview                          # arm only, open PulseView yourself

I2C has no fixed pin pair; any of the 8 scanner-header channels can carry SDA/SCL, so the probe accepts omitting the pin arguments to auto-discover them via a full i2c scan first.

PulseView use

Important

PulseView usage is exclusive to Linux installations and must first be set up as indicated here: PulseView AppImage Setup (Linux only)

Learn more about PulseView and how the firmware manages the communication here: faultycat-TUI/docs/PULSEVIEW_SETUP.md

Usage:

faultycmd la pulseview

If pulseview is in your PATH, this automatically arms the firmware and opens PulseView. To skip the auto-launch and open it manually, add the --no-pulseview flag.

Finding your pins (I2C)

Unlike the on-device analyzer (la capture), PulseView does not automatically know which pins are SDA and SCL, it simply streams all 8 channels (GP0 to GP7).

Before starting, if you do not know your pin layout, run a scan:

faultycmd i2c scan

It will output something like Auto-discovered sda=GPX scl=GPX. Note these channel numbers for the GUI configuration.

PulseView manual connection

Note

Skip this section if faultycmd la pulseview successfully opened and connected PulseView for you.

If opening PulseView manually, connect it to the hardware using these steps:

  1. Find the port: Run faultycmd devices. Look for the row with role = scanner and copy its device path (e.g., /dev/ttyACMX on Linux or COMX on Windows).

  2. Connect in PulseView: Click the Connect to Device icon (top left).

  3. Select Driver: Choose Open Bench Logic Sniffer (ols).

  4. Select Port: Choose Serial Port and enter the port path found in Step 1.

  5. Scan & Confirm: Click Scan for devices, then OK. You will see 8 channels (0–7) appear.

Once connected, continue with the channel/decoder setup in Configure channels and decoders.

Configure channels & decoders

Because PulseView cannot load channel settings from the command line, you must configure your workspace once by hand. PulseView will remember these settings for next time.

  1. Disable unused channels: In the left-hand channel list, uncheck everything except the two pins you identified during your pin scan (e.g., channels 0 and 1). Tip: Right-click them to rename them to SDA and SCL for clarity.

  2. Add the decoder: Click the Add protocol decoder button (or press Ctrl+D), search for I2C, and add it.

  3. Map the pins: Assign the decoder's SCL and SDA inputs to your active channels.

  4. Save: Close PulseView normally. The GUI configuration is saved automatically.

Sample rates & capture windows

The FaultyCat hardware has a fixed ceiling of a 1 MHz sample rate and a maximum capacity of 16,384 samples per capture window.

To decode digital signals reliably, you need to sample significantly faster than the signal's base speed to capture sharp edge transitions. Because the sample capacity is fixed, higher sample rates result in shorter capture windows:

Signal Type Recommended Samplerate Resulting Capture Window Approximate Capacity
UART at 1152000 baud 500 kHz ~32.98 ms ~375 bytes
I2C Fast-Mode at 400 kHz 1MHz (Hardware limit) ~16.4 ms ~725 bytes
Set a trigger

Because the capture window is very short (16–33 ms), clicking "Run" blindly will usually just capture empty silence before your data arrives. Always use a trigger:

  1. Set the Edge: In the channel list, click the small trigger icon next to the line that initiates data (e.g., the UART RX line, or the I2C SDA line). Select Falling Edge (since both protocols idle High and pull Low to start).

  2. Adjust Pre-Trigger: Adjust the pre-trigger capture ratio in the top toolbar. This ensures PulseView captures a tiny bit of the idle line before the trigger event, helping the decoder align properly.

  3. Run: Click Run. PulseView will patiently wait indefinitely until data actually crosses the wire before using its sample budget.


Scanner (SWD Pin Discovery)

An automated hardware interrogation and bus-scanning utility. A scanner's primary role is to discover, map, and verify physical connection states on a target microcontroller before and after an attack window.

Usage:

faultycmd scanner  [OPTION] COMMAND [ARGS]
[OPTIONS] Description
--port Override the scanner port
--help Show the available OPTIONS and COMMAND
COMMAND Description
scan-swd Detect the target's SWD pins
ARG Description
SWD scanner [ARGS] -
--targetsel Optional hex value. Discovery sweeps the whole bus by default
--timeout-s Max scan time ib seconds (default:30)

Usage example:

faultycmd scanner scan-swd --timeout-s 30

TUI

The Text User Interface (TUI) serves as the primary interactive, terminal-based visual dashboard for FaultyCat v3. It acts as an abstraction layer above the raw host Command Line Interface (CLI), allowing operators to configure parameters, fire pulses, and monitor hardware states in real time using keyboard-driven controls and modals.

In the TUI, you can basically perform and configure the same things as when using the command line interface.

Usage:

faultycmd tui

The letters that open the modals (e, b, p, n) are mnemonics on the engine name: EMFI, crowBar, camPaign, scaN SWD.

Key Action
q quit (if a modal is open, closes it first)
r reconnect (closes and reopens the 4 CDCs — handy after re-plugging the board)
c clear the campaign live log
s stop the running sweep (without opening a modal)
e EMFI modal (configure / arm / fire / disarm / capture)
b Crowbar modal (configure / arm / fire / disarm)
p Campaign modal (sweep parameters + start / stop / drain)
n Scan SWD modal (single button that fires scan swd over CDC2)

Important

While the TUI is open, it holds CDC0 (EMFI) and CDC1 (crowbar/campaign) exclusively, and CDC2 (scanner) read-only for the diag tail. Don't run faultycmd scanner/i2c/uart/la commands or open a serial terminal against the same ports from a second window at the same time; they all ride the same CDC2 text shell.

Scan SWD modal (n)

A single-button modal that runs scan swd over the CDC2 text shell (P(8,2)=56 permutations, 30 s timeout). While the scan is running, the CDC2 diagnostic stream is paused so it doesn't contaminate the output, and it resumes when the scan finishes. The raw firmware lines (MATCH / NO_MATCH / ERR) appear on the modal's status line.

Supported platforms

System Status Notes
Linux ✓ verified Ports under /dev/ttyACM*. If you hit Permission denied when opening them, add your user to the dialout group (sudo usermod -aG dialout $USER) and log out / back in. Install via wheel from a Release.
Windows 10/11 ✓ verified (2026-05-25) COM* ports enumerated by usbser.sys (in-box driver). Requires firmware v3.0-f11-0d or later — earlier versions failed to enumerate because of bugs in the descriptor and in the init order. Easiest install path: download faultycmd_vX.Y.Z.W.exe from the Release — no Python install needed. If you prefer pip, use a venv so Scripts/ ends up on PATH; otherwise, python -m faultycmd ... works without PATH changes.
macOS ⚠ not validated The cross-platform logic (pyserial parsing) should be enough, but no hardware on hand to confirm. Install via wheel from a Release.

Subsequent sessions

cd /path/to/host/faultycmd-py
# Activate the venv for your shell (step 1 of Quick start)
faultycmd tui

To leave the venv: deactivate.

Trigger polarity (EMFI / Crowbar)

Both engines expose the same five trigger modes on the wire:

Trigger Wire id PIO program (WAITs) Event that fires the glitch
immediate 0 (none) starts immediately on fire
ext_rising 1 WAIT 0, WAIT 1 rising edge
ext_falling 2 WAIT 1, WAIT 0 falling edge
ext_pulse_pos 3 WAIT 0, WAIT 1, WAIT 0 falling edge at the end of a LOW→HIGH→LOW pulse
ext_pulse_neg 4 WAIT 1, WAIT 0, WAIT 1 rising edge at the end of a HIGH→LOW→HIGH pulse

Notes:

  • The idle level of the trigger line is set once when the firmware boots, in main.c (ext_trigger_init(EXT_TRIGGER_PULL_DOWN)): LOW-idle for the whole system. Services do not change it on every arm.
  • As a consequence, ext_falling and ext_pulse_neg require the external source to drive the line HIGH between events. Without that active stimulation, the internal pull-down and the v2 board's level-shifter keep the line LOW, and the first WAIT 1 waits forever.
  • Latency from the trigger event to the crowbar/EMFI pin is the same in all four edge modes (~56 ns). If you measure from the start of the pulse instead of from the final edge that fires the glitch, you add the pulse width to the reading — that's the cursor position on your scope, not firmware overhead.
  • ext_pulse_pos and ext_pulse_neg are inverses. Pick the one that matches the idle level your source produces between events; otherwise, the first WAIT hangs.

Trigger timeout (EMFI / Crowbar fire)

Every call to fire accepts a trigger_timeout_ms that bounds how long the firmware waits for the external trigger before cancelling with *_ERR_TRIGGER_TIMEOUT. The defaults and semantics are identical for EMFI and Crowbar:

  • Default: 60 000 ms (1 minute). Enough for manual triggers without having to go back to the CLI to adjust the value.
  • 0 means wait forever. The firmware honours it in tick_waiting; a disarm cancels the wait, releases the PIO, and resets the state.

Where to configure it:

  • TUI (e / b): the modal form exposes a trigger-timeout-ms field. It is read on every fire, so it can be tweaked between shots without reapplying the configuration. The value is persisted alongside the rest of the form in last_config.json.

Clone this wiki locally