Skip to main content

Unified rfcat helper for sub-GHz RF work

Project description

rfox

Unified rfcat-py3 helper for sub-GHz RF work. One CLI, one interactive menu, one capture format. Built on top of rfcat / rflib so it works with any YARDStickOne, RfCat-compatible CC1111 dongle, or DonsDongle.

./rfox                                      # interactive menu
./rfox decode --hex aabbccdd -m manchester  # direct CLI

⚠️ Legal & ethics — read this first

rfox is a dual-use security research tool. Several of its commands — notably jam, scanjam, rolljam, brute, and fuzz — actively transmit RF energy and can interfere with, disable, or attempt to gain unauthorised access to wireless systems. In most jurisdictions this is illegal unless you own the target equipment or have explicit, written authorisation to test it.

You are responsible for understanding and complying with the law in your country. As a non-exhaustive starting point:

  • United States — 47 U.S.C. § 333 prohibits "wilful or malicious interference" with any radio communication. The FCC enforces this and has fined private individuals six-figure amounts for jamming. The Computer Fraud and Abuse Act (CFAA) covers unauthorised access to electronic systems.
  • United Kingdom — the Wireless Telegraphy Act 2006 makes unlicensed intentional interference an offence; the Computer Misuse Act 1990 covers unauthorised access.
  • European Union — RED (2014/53/EU) and national transposition acts regulate spectrum use; most member states have similar criminal prohibitions on jamming.
  • Australia, Canada, Japan, … — similar regimes exist almost everywhere.

Use rfox only for:

  • security research on equipment you own;
  • formally authorised penetration testing engagements (with a written scope-of-work / authorisation letter from the asset owner);
  • CTF challenges and educational exercises in shielded enclosures (RF isolation chamber, Faraday cage / bag) where transmissions cannot leak into licensed bands;
  • compliance and interoperability testing in a controlled lab environment.

Do not use rfox to:

  • attack, disrupt, or interfere with infrastructure, vehicles, premises, devices, or services that are not yours, or for which you do not hold written authorisation;
  • jam, intercept, or replay communications belonging to other people;
  • bypass access controls (gates, garage doors, vehicles, alarms, locks) on property you do not own;
  • target safety-critical, life-safety, public-safety, or aviation systems under any circumstances.

By using this software, you acknowledge that you alone are responsible for ensuring your use is lawful and authorised. The authors and contributors provide rfox without warranty of any kind (see LICENSE) and are not liable for any direct or indirect harm, legal action, regulatory penalty, equipment damage, or data loss arising from its use or misuse.

If any of this is unclear, stop and consult a qualified lawyer in your jurisdiction before using the offensive commands.


Why rfox

rfcat ships a powerful Python library (rflib) and an interactive shell, but day-to-day RF work tends to be the same handful of recipes — capture a key fob, replay it, sweep a band, decode some Manchester, find the rolling counter — repeated with slightly different parameters. The community RfCatHelpers project showed how useful those recipes are as standalone scripts, but each one re-implements the same dongle init, defines its own incompatible CLI, and uses its own ad-hoc capture format.

rfox consolidates that workflow into:

  • one tool with consistent flags everywhere (-f is always Hz, -r is always bps, -m is always one of OOK / 2FSK / GFSK / MSK / 4FSK);
  • an interactive menu for when you don't remember the flags — it walks you through every option with the default shown;
  • one capture file format (libpcap, DLT_USER0, RFCT pseudo-header) so anything you capture in one mode can be replayed, decoded, diffed, or CRC-checked by any other command;
  • named profiles (~/.rfcat/profiles.json) and built-in presets for common protocols, so you stop re-typing six flags for every command.

The interactive menu and the CLI share a single dispatcher, so they can never drift apart — adding a new command exposes it in both modes automatically.


Installation

rfox is a standalone tool that depends on rfcat-py3 for the underlying rflib library.

pip install rfox

Optional dependencies:

pip install 'rfox[specan]'      # enables `rfox specan` (PySide6)

For development:

git clone https://github.com/qu-crypt/rfox.git
cd rfox
python3 -m venv .venv && source .venv/bin/activate
pip install -e .

System libraries:

  • libusb-1.0 (Linux: apt install libusb-1.0-0, macOS: brew install libusb, Windows: see the rfcat README)
  • non-root USB access on Linux requires the udev rules from the rfcat-py3 repo's etc/udev/

Verify:

./rfox --help
./rfox devices         # lists attached dongles

Quick start

Five things you'll almost certainly want to do:

# 1. Sweep a band looking for activity
./rfox sweep --start 433e6 --stop 434e6 --step 50e3 --ascii-bar

# 2. Capture five presses of a 433 MHz remote into a pcap
./rfox replay capture --preset ev1527 -n 5 -o /tmp/garage.pcap

# 3. Replay them
./rfox replay replay --input /tmp/garage.pcap --use-capture-cfg

# 4. Find the rolling-counter byte (or rule it out)
./rfox diff --input /tmp/garage.pcap

# 5. Identify the protocol's checksum
./rfox crc --input /tmp/garage.pcap

No dongle? The analysis subcommands work entirely on captures or hex strings:

./rfox decode --hex aabbccdd -m auto
./rfox find-sync --hex aaaaaad391deadbeef
./rfox crc --hex 12345612fd
./rfox diff --hex aabbcc00 --hex aabbcc01 --hex aabbcc02

Command reference

group command what it does needs hw
dongle devices list connected RfCat dongles
specan open the PySide6 spectrum analyser
RX scan RX loop, hex-print frames, optional pcap log
sweep RSSI sweep across --start..--stop, optional CSV
logger headless RX → append every frame to a pcap
TX transmit binary string → OOK (raw or PWM-encoded)
tx-hex raw bytes given as hex on the CLI
jam one frequency for N seconds ⚠️
scanjam two dongles: scan + reactive-jam ⚠️ ✓✓
brute iterate a key space and transmit each value ⚠️
fuzz bit/byte-mutate a seed frame, retransmit ⚠️
capture/replay replay capture record N frames to a pcap
replay replay replay a pcap
rolljam jam → capture 1 → unjam → capture 2 → replay 1 ⚠️ ✓✓
analysis decode manchester/diff-manchester/PWM/raw decoders
find-sync candidate sync words in a capture
find-repeats repeating bit patterns
crc try CRC-8/CRC-16 polynomials over capture tails
diff bit-by-bit diff (find rolling-counter fields)
decode-wav OOK decoder for WAV recordings
workflow profile {save,show,list,delete} named radio configs
preset {list,show} built-in protocol presets

Commands marked ⚠️ are the ones you should only use on equipment you own or are formally authorised to test. See the disclaimer above.

✓✓ means the command requires two dongles.

Each command also has full --help:

./rfox replay capture --help
./rfox find-sync --help

Capture file format

Every capture/replay command shares one libpcap file (magic 0xa1b2c3d4, link type DLT_USER0 = 147). Each packet payload starts with a 24-byte RFCT pseudo-header recording the radio configuration at capture time, followed by the raw on-air bytes:

struct rfct_pseudo_hdr {        // little-endian
    uint8_t  magic[4];          // "RFCT"
    uint8_t  version;           // 1
    uint8_t  modulation;        // 0=OOK 1=2FSK 2=GFSK 3=MSK 4=4FSK
    uint32_t freq_hz;
    uint32_t drate_bps;
    uint32_t chanbw_hz;
    int16_t  rssi_dbm10;        // dBm * 10, signed
    uint16_t sync_word;         // 0 if none
    uint8_t  payload[];
};

Read with the dataclass-based reader:

from rflib.rfox import pcap

for frame in pcap.read("garage.pcap"):
    print(frame.ts, frame.cfg.summary(), frame.payload.hex())

Or open it in Wireshark / tshark — frames will appear as data under USER0. A future Lua dissector could decode the pseudo-header field by field, but the raw bytes are usable today with any pcap parser.


Profiles & presets

Save a configuration once, reuse it forever:

./rfox profile save mygate -f 433.92e6 -r 2400 -m OOK --chanbw 325000
./rfox replay replay --input cap.pcap --profile mygate

Or jump straight to a built-in:

./rfox preset list
./rfox scan --preset ev1527
./rfox tx-hex --preset keyfob315 --hex aabbcc

CLI flags override the profile/preset, so --preset ev1527 --freq 433.95e6 works.

Built-in presets:

name freq drate mod typical use
ev1527 433.92 MHz 2400 OOK generic 433 MHz remotes
pt2262 433.92 MHz 1200 OOK older garage / gate openers
keeloq 433.92 MHz 2000 OOK rolling-code keyfobs
keyfob315 315 MHz 2400 OOK US automotive key fobs
srd868 868.35 MHz 4800 2FSK EU short-range devices
ism915 915 MHz 38 400 2FSK US ISM band
tpms433 433.92 MHz 19 200 2FSK tyre-pressure sensors

Adding a new command

Drop a module under rflib/rfox/commands/, expose three functions:

HELP = "one-line description shown in --help and the menu"

def add_args(parser):
    """Attach argparse args. Use _common.add_radio_args / add_dongle_args."""

def prompt(args):                # optional
    """Walk the user through args interactively."""

def run(args):
    """Do the work. Return an exit code."""

Register it in rflib/rfox/commands/__init__.py. The CLI dispatcher and the interactive menu both pick it up automatically.

Use _common.cfg_from_args(args) to honour --preset / --profile before merging in CLI overrides — that's how every existing command keeps its behaviour consistent.


Tests

python -m unittest tests.test_rfox

The pcap roundtrip, presets, profiles, and analysis subcommands (decode, find-sync, find-repeats, crc, diff, decode-wav) are covered without hardware. The hardware-using TX commands are smoke-tested by patching open_dongle to return FakeRfCat.


Versioning & stability

rfox is versioned independently of rfcat. Anything in rflib.rfox.commands is part of the public CLI; flag names and the pcap pseudo-header layout are stable within a major version. Anything under rflib.rfox (other than the public command modules) is internal and may change without notice.


Contributing

Pull requests welcome. Please:

  1. Open an issue first for non-trivial changes.
  2. Add a test under tests/test_rfox.py that exercises your code without hardware (use FakeRfCat for TX commands).
  3. Match the existing argparse flag style (-f/--freq is Hz, -r/--drate is bps, etc.).
  4. Don't add commands that are exclusively useful for unauthorised attacks.

By contributing, you agree your contribution is licensed under the MIT License (see LICENSE).


License

rfox's own source — the entry script, the rflib/rfox/ package, and tests/test_rfox.py — is released under the MIT License. See LICENSE.

It builds on top of rfcat-py3, which is distributed under the MIT License.


Acknowledgements

  • @atlas0fd00m for the original rfcat and rflib.
  • @qu-crypt for the Python 3 port (rfcat-py3) and dongle firmware.
  • @AndrewMohawk — the original RfCatHelpers project that mapped out the most useful day-to-day recipes and motivated this tool.
  • The Ubertooth, GNU Radio, and HackRF communities for decades of prior art in sub-GHz tooling.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rfox-1.0.1.tar.gz (38.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rfox-1.0.1-py3-none-any.whl (42.5 kB view details)

Uploaded Python 3

File details

Details for the file rfox-1.0.1.tar.gz.

File metadata

  • Download URL: rfox-1.0.1.tar.gz
  • Upload date:
  • Size: 38.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rfox-1.0.1.tar.gz
Algorithm Hash digest
SHA256 427d34ad20c7fac219285fa6c2e4f663f5033129d4d756c4c2563f4c1c9915ff
MD5 f1fa78f9b8e4f617e51ae946ef31cfdd
BLAKE2b-256 c6ad71a334f2ec421dbbabeb1b6b735e46657464fbf5d53cba87800b646ee790

See more details on using hashes here.

Provenance

The following attestation bundles were made for rfox-1.0.1.tar.gz:

Publisher: ci.yml on qu-crypt/rfox

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rfox-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: rfox-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 42.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rfox-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 61c61804915b2cb6858b208ac6bef8e2328e9e995bf72cf74a48cf06e83873b4
MD5 4026f46fe5bdfb1af8fd0ba34244962a
BLAKE2b-256 77fe84dc2489dd04097ab861f8ea22cada64d942e2dabc818d783ed23a376a17

See more details on using hashes here.

Provenance

The following attestation bundles were made for rfox-1.0.1-py3-none-any.whl:

Publisher: ci.yml on qu-crypt/rfox

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page