Tool for analyzing osu! replay, currently worked for osu!mania.
Analyzes .osr replay files for cheat signatures using binary forensics and statistical analysis.
# Single replay
python3 analyze.py replay.osr
# Compare two replays on the same map (detects timing assists)
python3 analyze.py replay_a.osr replay_b.osr
# Batch scan
python3 analyze.py *.osr
# JSON output
python3 analyze.py --json replay.osr
# Adjust sensitivity (lower = stricter, default 0.5)
python3 analyze.py --threshold 0.4 replay.osr
# Disable colors
python3 analyze.py --no-color *.osr| Check | Weight | Detects | How |
|---|---|---|---|
| Y-Value | 5.0x | Replay editors, bots | Real client writes scroll velocity as precise floats (14.83517). Editors/bots write round integers (9, 30). |
| Per-Column CV | 2.5x | Timing assists, relax hacks | Measures inter-onset interval coefficient of variation per key column. Human: 0.5-2.0+. Bot/assist: <0.35. |
| Frametime | 1.5x | Frame-locking, timewarp | Normal systems: 2-5ms stdev in frame deltas. Frame-locking tools: <1.2ms stdev, 70%+ frames at exactly 16-17ms. |
| Compression | 1.0x | Generated/edited replays | Generated replays have lower entropy (compress to 15%+). Legit replays: 7-10%. |
| Hold Duration | 0.5x | Input injection | High rate of <30ms key holds indicates tool artifacts. |
- CHEATED (score >= 0.5) — Strong cheat indicators detected
- SUSPICIOUS (score >= 0.3) — Some anomalies, warrants manual review
- LEGIT (score < 0.3) — No significant cheat indicators
When given exactly 2 replays on the same beatmap, the tool runs a relative comparison that detects cheats invisible to individual analysis:
python3 analyze.py legit_play.osr suspect_play.osrThis catches timing assists — tools that help with key press timing but don't modify the replay binary. They pass Y-value and compression checks individually, but show dramatic per-column CV drops (30-60%) when compared to a clean play on the same map.
The tool parses the osu! replay binary format:
[1 byte] mode (3 = mania)
[4 bytes] version (e.g. 20220424)
[string] beatmap MD5
[string] player name
[string] replay hash
[2 bytes each] 300, 100, 50, geki (MAX), katu (200), miss counts
[4 bytes] total score
[2 bytes] max combo
[1 byte] perfect combo flag
[4 bytes] mods bitfield
[string] life bar graph
[8 bytes] timestamp (Windows ticks)
[4 bytes] replay data length
[n bytes] LZMA-compressed replay data
Replay data decompresses to comma-separated frames: w|x|y|z
| Field | Meaning |
|---|---|
w |
Time delta (ms since last frame) |
x |
Key state bitfield (bit per column) |
y |
Scroll velocity (the forensic field) |
z |
Unused |
Python 3.7+ with standard library only (no pip dependencies).
- Mania generates extra sub-frames on key events, creating bimodal frametime distributions. The tool isolates game tick frames (>=14ms) to avoid false positives.
- osu! lazer replays (
solo-replay-*prefix) have tighter frame pacing than stable — the tool accounts for this. - The threshold is tunable. Use
--threshold 0.4to be stricter or--threshold 0.6to be more lenient.