Init. commit
This commit is contained in:
99
HumanAI-Forensic-Hard/scripts/probe_vc_xts.py
Normal file
99
HumanAI-Forensic-Hard/scripts/probe_vc_xts.py
Normal file
@@ -0,0 +1,99 @@
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from typing import Iterable, List, Tuple
|
||||
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
|
||||
|
||||
def decrypt_xts_sector(ct: bytes, xts_key: bytes, sector_no: int) -> bytes:
|
||||
tweak = int(sector_no).to_bytes(16, "little", signed=False)
|
||||
cipher = Cipher(algorithms.AES(xts_key), modes.XTS(tweak))
|
||||
dec = cipher.decryptor()
|
||||
return dec.update(ct) + dec.finalize()
|
||||
|
||||
|
||||
def looks_like_boot_sector(pt: bytes) -> List[str]:
|
||||
hits: List[str] = []
|
||||
if len(pt) < 512:
|
||||
return hits
|
||||
if pt[510:512] == b"\x55\xaa":
|
||||
hits.append("55aa")
|
||||
sig = pt[3:11]
|
||||
if sig == b"NTFS ":
|
||||
hits.append("NTFS")
|
||||
if sig == b"EXFAT ":
|
||||
hits.append("EXFAT")
|
||||
if sig.startswith(b"FAT"):
|
||||
hits.append(sig.decode("ascii", errors="ignore"))
|
||||
if pt[0] in (0xEB, 0xE9) and pt[2] == 0x90:
|
||||
hits.append("jmp")
|
||||
return hits
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description="Probe VeraCrypt container using AES-XTS keys")
|
||||
ap.add_argument("container", type=Path)
|
||||
ap.add_argument("--key-a", required=True, help="32-byte hex key A")
|
||||
ap.add_argument("--key-b", required=True, help="32-byte hex key B")
|
||||
ap.add_argument(
|
||||
"--offsets",
|
||||
default="0,0x10000,0x20000",
|
||||
help="Comma-separated file offsets to try (default: 0,0x10000,0x20000)",
|
||||
)
|
||||
ap.add_argument(
|
||||
"--tweak-bases",
|
||||
default="auto",
|
||||
help="Comma-separated sector numbers to try as tweak base, or 'auto' for 0 and offset/512",
|
||||
)
|
||||
args = ap.parse_args()
|
||||
|
||||
key_a = bytes.fromhex(args.key_a)
|
||||
key_b = bytes.fromhex(args.key_b)
|
||||
if len(key_a) != 32 or len(key_b) != 32:
|
||||
raise SystemExit("Keys must be 32 bytes each (64 hex chars)")
|
||||
|
||||
offsets: List[int] = []
|
||||
for part in args.offsets.split(","):
|
||||
part = part.strip()
|
||||
if not part:
|
||||
continue
|
||||
offsets.append(int(part, 0))
|
||||
|
||||
data = args.container.read_bytes()
|
||||
|
||||
key_orders: List[Tuple[str, bytes]] = [
|
||||
("A||B", key_a + key_b),
|
||||
("B||A", key_b + key_a),
|
||||
]
|
||||
|
||||
for off in offsets:
|
||||
if off + 512 > len(data):
|
||||
continue
|
||||
ct = data[off : off + 512]
|
||||
|
||||
if args.tweak_bases.strip().lower() == "auto":
|
||||
tweak_bases = sorted({0, off // 512})
|
||||
else:
|
||||
tweak_bases = []
|
||||
for part in args.tweak_bases.split(","):
|
||||
part = part.strip()
|
||||
if not part:
|
||||
continue
|
||||
tweak_bases.append(int(part, 0))
|
||||
|
||||
for base in tweak_bases:
|
||||
for label, xts_key in key_orders:
|
||||
pt = decrypt_xts_sector(ct, xts_key, base)
|
||||
hits = looks_like_boot_sector(pt)
|
||||
if hits:
|
||||
print(
|
||||
f"[+] offset=0x{off:X} tweak={base} order={label} hits={','.join(hits)} sig={pt[3:11]!r}"
|
||||
)
|
||||
print(pt[:64].hex())
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
|
||||
Reference in New Issue
Block a user