Skip to content

Adding a New Signature

CodingJeffRoblox edited this page Sep 23, 2026 · 1 revision

Adding a New Signature

A practical guide for contributors who want to add a new recoverable file format. This is one of the explicitly welcomed contribution areas — read How It Works first for the weak-magic/strong-magic distinction this guide assumes.

Everything lives in byterescue/recovery/signatures.py. Every entry in the SIGNATURES dict needs matching logic in carve() — nothing is listed "for show."

1. Add a SIGNATURES entry

Each entry is keyed by format name and describes:

Field Meaning
extensions File extensions this format is known by
header The magic bytes that mark a candidate's start
footer The magic bytes that mark its end, or None if the format has no reliable footer
carver Which branch of carve() handles this format
min_size / max_size Sanity bounds; max_size=None means no cap (only safe when a real footer/length exists)
reliable Whether this format's end offset can be proven, not just estimated
container_based Whether the format has real internal structure to validate against (vs. a flat blob)
false_positive_risk Your honest assessment of how often the header magic alone could appear by coincidence
notes Anything a future reader needs to know about why the carving works the way it does

2. Decide which family it belongs in

  • Short/weak magic (2-4 bytes, or a magic that could plausibly appear inside unrelated binary data)? Your carve() branch must do a real structural check and reject outright (return nothing, not a guessed result) when that check fails. Look at the bmp, zip, or mp4 branches for the pattern — each one rejects a coincidental-magic false positive rather than reporting a broken result.
  • Long/distinctive magic (unlikely to appear by coincidence) with no reliable end marker? Accept it but cap its size and mark it unverified — see the capped branch used for GZIP/7-Zip/FLAC/GIF/TIFF/ RAR/OLE/MKV.
  • Has both a distinctive magic and a real footer/length field? That's the best case — verify the real end (see PNG's checksummed IEND, or SQLite's page-size × page-count) rather than searching for a footer string that could itself appear elsewhere.

3. Implement carve(name, data, i)

Add a branch dispatched by your carver value. It receives the format name, the full data buffer, and the candidate's start index i, and must return either a carved result (with whatever end offset your logic actually proved or estimated) or nothing, if a weak-magic candidate fails its structural check.

4. Wire up validate(name, blob, verified)

If your format can be checked with a real parser (Pillow, zipfile, sqlite3, wave, decompression, or similar), add that check here so carved results get a genuine Passed/Partial/Failed/Unknown validation — see How It Works for why this is kept separate from carving itself.

5. Update the tests and docs

  • Add a synthetic fixture to tests/fixtures.py — never a real file, hand-built bytes that exercise the format's actual structure (see the existing JPEG-with-embedded-thumbnail or multi-entry-ZIP fixtures for the level of realism expected).
  • Add carving-correctness and false-positive-rejection cases to tests/test_signatures.py — see Testing.
  • Add your format's row to Recovery Signatures, stating plainly whether its end offset is proven or estimated. Don't round up a heuristic to "verified."

Guiding principle

Every row in Recovery Signatures is a claim about how trustworthy a result is. Overstating a format's reliability is worse than not supporting it — mark it unverified/heuristic if that's genuinely all the format allows, and say so in notes.

Clone this wiki locally