Rootless Rowhammer research toolkit with DRAMA bank targeting. No root required.
- Rootless operation: Uses DRAMA timing side-channel for bank detection (no
/proc/self/pagemap) - Multiple attack modes: double-sided, single-sided, and many-sided hammering
- Configurable patterns: zeros, ones, alternating (0x55), alternating inverse (0xAA)
- Auto-calibration: Automatic threshold detection for bank conflict detection
- Well-tested: Comprehensive pytest test suite
- Python 3.8+
- GCC (for compiling
hammer_core.c) - Linux x86_64 or ARM64 (uses
clflush/dc ivac,rdtsc/cntvct_el0instructions)
# Clone and install
pip install -e .
# Build the C extension (if not already built)
gcc -O2 -shared -fPIC -o hammer_core.so hammer_core.cOr install with dev dependencies for testing:
pip install -e ".[dev]"gcc -O2 -shared -fPIC -o hammer_core.so hammer_core.c# Auto-calibrate threshold, probe 512 pages, hammer 2M iters
rowhammer
# Just calibrate (find your threshold), then exit
rowhammer --calibrate
# Aggressive: 512MB buffer, 1024 probe pages, 5M iters
rowhammer --size 512 --probe 1024 --iters 5000000
# All-ones pattern (look for 0-bit flips)
rowhammer --pattern ones --iters 3000000
# Manual threshold (skip calibration)
rowhammer --threshold 380
# Many-sided attack with 8 aggressors
rowhammer --mode many --aggressors 8| Flag | Default | Description |
|---|---|---|
--size |
256 | Buffer MB |
--probe |
512 | Pages to probe for conflicts |
--samples |
100 | Timing samples per pair in DRAMA phase |
--threshold |
auto | Conflict threshold in cycles (0 = calibrate) |
--iters |
2,000,000 | Hammer iterations per pair |
--pairs |
8 | Max aggressor pairs to hammer |
--pattern |
zeros | zeros / ones / alt (0x55) / altinv (0xAA) |
--mode |
double | double / single / many |
--aggressors |
4 | Number of aggressors for many mode |
--calibrate |
— | Calibrate threshold only, then exit |
--verbose |
— | Print each conflict pair |
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run with coverage
pytest --cov=rowhammer --cov-report=term-missingrowhammer-toolkit/
├── src/rowhammer/ # Python package
│ ├── __init__.py
│ ├── __main__.py # CLI entry point
│ ├── core.py # Core functionality
│ └── lib.py # C extension wrapper
├── tests/ # Test suite
│ ├── conftest.py
│ ├── test_core.py
│ ├── test_lib.py
│ └── test_cli.py
├── hammer_core.c # C extension source
├── hammer_core.so # Compiled extension
├── pyproject.toml # Package configuration
└── README.md
Two addresses in the same DRAM bank cause a row activation conflict when accessed back-to-back after clflush. This is measurable:
same bank → ~400-600 cycles (conflict; serialised row access)
diff bank → ~150-250 cycles (parallel; no conflict)
hammer_core.c uses rdtsc (cycle counter, no syscall) for sub-ns precision timing.
Probe N random pages, measure all O(N²/2) pairs. Pairs above the conflict threshold go into an adjacency graph — each connected component is a set of addresses mapping to the same DRAM bank.
Pick pairs with the highest conflict latency — these tend to straddle a victim row. Hammer them with clflush + mfence in a tight C loop.
After hammering, scan the buffer byte-by-byte for any deviation from the fill pattern. Report virtual address and which bits changed.
Python layer (src/rowhammer/)
├── mmap buffer allocation (huge pages if available)
├── DRAMA conflict graph (O(N²) pair timing)
├── Threshold auto-calibration
├── Aggressor pair selection (highest-latency pairs)
└── Flip scanner + reporting
C layer (hammer_core.so)
├── clflush + mfence + lfence
├── rdtsc cycle-accurate timer
├── measure_pair_median() ← core DRAMA primitive
├── hammer_pair() ← double-sided loop
├── hammer_single() ← single-sided loop
├── hammer_many() ← N-sided loop
└── scan_flips() ← byte-level deviation scan
- Pessl et al., "DRAMA" (USENIX Security 2016) — timing-based bank detection
- Kim et al., "Flipping Bits in Memory" (ISCA 2014) — original rowhammer
- Frigo et al., "TRRespass" (IEEE S&P 2020) — many-sided attacks
MIT