reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Scan a sample for destructive wiper primitives and classify wiper vs ransomware.
|
||||
|
||||
Detects raw-disk/MBR overwrite primitives, backup/recovery destruction commands, and weighs them
|
||||
against ransomware (encryption/extortion) indicators to classify intent. Reads bytes statically;
|
||||
executes nothing.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ASCII_RE = re.compile(rb"[\x20-\x7e]{4,}")
|
||||
UTF16_RE = re.compile(rb"(?:[\x20-\x7e]\x00){4,}")
|
||||
|
||||
RAW_DISK = ["\\\\.\\physicaldrive", "\\\\.\\c:", "deviceiocontrol", "ioctl_disk",
|
||||
"createfilemapping", "setfilepointer", "\\device\\harddisk"]
|
||||
BOOT_TAMPER = ["this program cannot be run", "mbr", "\\\\.\\physicaldrive0", "bootmgr is missing"]
|
||||
RECOVERY_DENIAL = ["vssadmin delete shadows", "vssadmin.exe delete", "wbadmin delete",
|
||||
"bcdedit /set", "recoveryenabled no", "wevtutil cl", "delete catalog",
|
||||
"shadowcopy delete"]
|
||||
MASS_DELETE = ["deletefile", "removedirectory", "shfileoperation", "writefile", "f0 fill",
|
||||
"overwrite"]
|
||||
RANSOM_INDICATORS = ["cryptencrypt", "cryptdecrypt", "bcryptencrypt", "readme.txt", "decrypt",
|
||||
".onion", "bitcoin", "ransom", "your files have been encrypted",
|
||||
"aes", "rsa public key"]
|
||||
|
||||
|
||||
def _strings(data: bytes) -> str:
|
||||
parts = [m.decode("ascii", "ignore") for m in ASCII_RE.findall(data)]
|
||||
parts += [m.decode("utf-16-le", "ignore") for m in UTF16_RE.findall(data)]
|
||||
return "\n".join(parts).lower()
|
||||
|
||||
|
||||
def scan(path: str) -> dict:
|
||||
blob = _strings(Path(path).read_bytes())
|
||||
raw = sorted({r for r in RAW_DISK if r in blob})
|
||||
boot = sorted({b for b in BOOT_TAMPER if b in blob})
|
||||
recovery = sorted({r for r in RECOVERY_DENIAL if r in blob})
|
||||
deletion = sorted({d for d in MASS_DELETE if d in blob})
|
||||
ransom = sorted({r for r in RANSOM_INDICATORS if r in blob})
|
||||
destructive_score = len(raw) * 2 + len(boot) * 2 + len(recovery) + len(deletion)
|
||||
ransom_score = len(ransom)
|
||||
if destructive_score >= 3 and ransom_score <= 1:
|
||||
classification = "likely_wiper"
|
||||
elif ransom_score >= 3:
|
||||
classification = "likely_ransomware"
|
||||
elif destructive_score and ransom_score:
|
||||
classification = "destructive_with_ransom_facade"
|
||||
else:
|
||||
classification = "inconclusive"
|
||||
return {
|
||||
"raw_disk_primitives": raw,
|
||||
"boot_record_tampering": boot,
|
||||
"recovery_denial": recovery,
|
||||
"mass_deletion": deletion,
|
||||
"ransomware_indicators": ransom,
|
||||
"destructive_score": destructive_score,
|
||||
"ransomware_score": ransom_score,
|
||||
"classification": classification,
|
||||
}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="Analyze wiper malware")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
p = sub.add_parser("scan")
|
||||
p.add_argument("file")
|
||||
args = parser.parse_args(argv)
|
||||
print(json.dumps(scan(args.file), indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user