Skip to main content

ScanCrypt — get back the data the ransomware never touched

License: Apache 2.0 CI

Most ransomware is in a race: encrypting terabytes takes hours, so to finish before it's caught it only scrambles part of each large file — the first chunk, or stripes through it — then renames it so everything looks equally dead. It usually isn't.

ScanCrypt scans an encrypted file or disk, measures exactly which bytes were never actually encrypted, and pulls those bytes back out — no decryption key, no ransom. It is not a decryptor; it's a ransomware-aware partial-recovery tool. Databases, VM disks, and backup archives are typically mostly intact underneath.

Free and open source (Apache-2.0), read-only, by IronSights · scancrypt.org · Plain-English guide for victims

Honest by design. Recoverability is always reported as most, not all, with the measured percentage. A partial file list is flagged as partial, never passed off as complete. Family IDs are labelled validated vs from public reporting. Fully-encrypted and small files are out of scope. Provided AS IS, no warranty; use only on systems you are authorised to examine.


Install

Just want to run it? Download the app from the releases pagescancrypt-gui.exe (Windows) is a single portable file, nothing to install, fully offline. No terminal needed. New to this? Read the plain-English guide.

From source (any OS):

python3 -m venv .venv
source .venv/bin/activate            # Windows: .venv\Scripts\activate
pip install -e ".[ntfs]"             # ".[ntfs]" adds VHDX/VHD/VMDK + NTFS support
scancrypt --help                     # or:  python -m rprt --help

dissect.hypervisor + dissect.ntfs (pulled in by [ntfs]) are what let ScanCrypt read files out of a virtual disk. Everything else works without them.


Quickstart

1. How much of a file/disk is recoverable?

scancrypt "SQL_DATA_D.vhdx"
size        108.5 GB
pattern     front-only
recoverable 100.0%
encrypted   0.0002%   258 KB at the front
family      Makop / Phobos  (validated)

Add --report triage.html for a shareable HTML report, --json out.json for machine output. Scans stay fast even on huge disks — a 322 GB VM images in seconds, because finding the encryption boundary doesn't require reading the whole file.

2. Recover files from a virtual disk (the headline workflow)

Ransomware often encrypts a VM disk's header, so it won't mount. ScanCrypt rebuilds the disk from the block map that survived and reads the files straight out — names and folders intact.

scancrypt "SQL_DATA_D.vhdx" --list-volume            # see what's inside
scancrypt "SQL_DATA_D.vhdx" --recover-files ./out    # copy the files out

Recover only specific files (near-instant, no full walk):

printf '/Program Files/.../DATA/production.mdf\n' > paths.txt
scancrypt "SQL_DATA_D.vhdx" --recover-files ./out --only-paths paths.txt

If part of the disk didn't survive, the file list says so (… (partial)) instead of pretending it's complete.

3. Check a recovered SQL Server database

scancrypt recovered.mdf --validate-sql
253,478 valid SQL Server page(s)  (90.6%)   verdict: sql-data-present
database name: production_db

A page-level integrity check (a structural analogue to DBCC), so you know what you got back before handing it to a DBA.

4. Triage a whole share at once

scancrypt /mnt/encrypted_share --report incident.html --csv incident.csv

One incident-wide figure — "across N files totalling X TB, this fraction is recoverable for free" — with a per-file breakdown for a client or insurer.

5. Extract the intact bytes of a single large file

scancrypt victim.bin --extract recovered.bin

Common options

Flag What it does
--report FILE standalone HTML triage report (add --hash to embed a SHA-256)
--json FILE full machine-readable report
--list-volume list every file in a virtual disk's NTFS volume
--recover-files DIR recover files from a VHDX/VHD/VMDK (rebuilds an encrypted-header disk)
--only-paths FILE with --recover-files, restrict to listed paths
--validate-sql page-level check of a recovered SQL Server MDF/NDF
--fingerprint emit a privacy-safe family signature stub + pre-filled issue link (no file contents)
--extract FILE write the intact byte ranges of a single file
--carve DIR carve loose files from the recoverable region (needs PhotoRec)
--boundary-only accept the fast front-boundary result; never do a full-disk read
--full force a full block-by-block scan (precise map, reads the whole file)
--audit-log FILE hash-chained, tamper-evident audit trail (+ --case-id, --examiner, --evidence-id)

Scan a raw disk in place (Windows, elevated prompt): scancrypt \\.\PhysicalDrive1 --json triage.json

Evidence-grade run and later verification:

scancrypt disk.img --extract out.bin --audit-log audit.jsonl \
    --case-id CASE-0001 --examiner "A. Analyst" --evidence-id DISK-01
python -c "from rprt import forensics; print(forensics.verify_log('audit.jsonl'))"

How it works (four read-only stages)

  1. Map the encryption. An entropy scan brackets where the encryption starts and stops, then binary-searches down to the byte. It stays cheap on huge disks and only escalates to a full read when the evidence points to a genuine second encrypted region — not to the scattered high-entropy blocks (databases, compressed content) that are normal on any disk.
  2. Tell ciphertext from compression. Encrypted and compressed data both look random; a chi-square test plus archive-header checks separate real ciphertext from an ordinary zip, image, or database blob, so recoverable data isn't written off.
  3. Report the number. A recoverable percentage, an entropy map, the strain, and the limits stated plainly — per file, or rolled up across a whole share.
  4. Recover. Extract intact byte ranges; pull files out of a virtual disk (even one whose header was destroyed); validate a recovered SQL database; carve loose files. Hashes are recorded throughout.

Recovery is family-agnostic — a wrong or unknown family guess never affects what comes back; identification only names the strain and sets expectations. Validated families (matched against real samples) vs public-reporting-only ones are labelled as such.


Honest limits

  • Not decryption — it recovers bytes that were never encrypted; the rest stays locked.
  • Recovery is most, not all; the report gives a measured figure, not a promise every file opens.
  • Small files are usually encrypted end-to-end. The value is in big files: databases, VM disks, backups, media.
  • Periodic/intermittent patterns recover less cleanly than front-only.
  • No warranty, no liability. Authorised systems only.

For developers

Dev setup

python3 -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
pytest

Run the GUI locally (works on macOS/Linux for development): python -m rprt.gui

Build the Windows app

Must run on Windows (PyInstaller doesn't cross-compile):

python -m venv .venv; .venv\Scripts\activate
pip install -e ".[dev]"
python build_scripts\build_windows.py     # -> dist\rprt-gui.exe (single file, no installer)

CI runs the suite on Ubuntu + Windows on every push and builds rprt-gui.exe; pushing a v* tag attaches it to a GitHub release.

Module map

Module Responsibility
engine.py core scan / classify / boundary-search / extract
stats.py chi-square randomness test (encrypted vs compressed)
signatures.py · ransomnote.py ransomware fingerprinting from extension/footer and from ransom notes
formats.py container/filesystem detection on the recoverable region (VHDX, ZIP/OOXML, NTFS/FAT, …)
ntfs.py read files out of an NTFS volume inside a partially-encrypted / header-encrypted virtual disk
sqlpages.py page-level SQL Server MDF/NDF recovery-quality check
carve.py orchestrates PhotoRec over the recoverable region
batch.py incident-wide directory triage + rollup
report.py standalone HTML triage report (inline CSS + SVG entropy map)
forensics.py before/after integrity proof + hash-chained audit log + case metadata
source.py read-only input abstraction (files, images, raw Windows devices)
gui.py · cli.py PySide6 desktop app · command-line entry point

Help ScanCrypt recognise a strain it doesn't name yet

Point it at one encrypted file:

scancrypt "somefile.newcrypt" --fingerprint

It prints a privacy-safe stub — extension, the family's trailing magic-candidate bytes, the encryption pattern, and any nearby ransom note — as a ready-to-paste signatures.yaml block and a pre-filled GitHub issue link. It reads no file contents, so a victim can submit safely. (In the app: Help improve ScanCrypt… after a scan.)

Contributions welcome — especially new verified family signatures (see CONTRIBUTING.md).


ScanCrypt does not break, weaken, or bypass cryptography, and it does not recover fully-encrypted data. Need an incident handled end to end — full extraction, database rebuilds, forensic reporting? IronSights does that as a paid engagement; the tool stays free.

Download files

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

Source Distribution

scancrypt-1.0.0.tar.gz (150.0 kB view details)

Uploaded Source

Built Distribution

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

scancrypt-1.0.0-py3-none-any.whl (122.7 kB view details)

Uploaded Python 3

File details

Details for the file scancrypt-1.0.0.tar.gz.

File metadata

  • Download URL: scancrypt-1.0.0.tar.gz
  • Upload date:
  • Size: 150.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for scancrypt-1.0.0.tar.gz
Algorithm Hash digest
SHA256 8130befc3960918a8945e267a5133a4334ea2fcb86856047467babf4551a0e5e
MD5 2db3780593b53e25106570abf2ca7abe
BLAKE2b-256 69e109645965045d82025d73a2cd270831577841d40e3fc533bbab6ccf6164c3

See more details on using hashes here.

Provenance

The following attestation bundles were made for scancrypt-1.0.0.tar.gz:

Publisher: publish.yml on ironsightscyber/scancrypt

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

File details

Details for the file scancrypt-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: scancrypt-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 122.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for scancrypt-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 53efa67d0c0826dd0d8d75640b557cc101fe6df4fcc2e6f2c15eb30bc4938c24
MD5 2c88c379d6d6863520e493b1eb5668c2
BLAKE2b-256 4922757cc6e4d734434d85fe2865149222297430b053642bfb79fadbb5a478eb

See more details on using hashes here.

Provenance

The following attestation bundles were made for scancrypt-1.0.0-py3-none-any.whl:

Publisher: publish.yml on ironsightscyber/scancrypt

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

Release history Release notifications | RSS feed

1.1.0

2 files

1.0.1

2 files

This release

1.0.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page