#!/usr/bin/env python3
"""Ad-hoc verification for redteam/tools/stealer build.

Checks:
  1. Artifact exists, PE32+ x86-64, sha256 matches OPLOG record
  2. cargo test host target: all green
  3. cargo xwin clippy msvc target -D warnings: clean
  4. Strings sweep: 0 stealer IOC strings in binary
  5. No build-host path leaks (/root/, ir-assessment)
  6. Imports: only kernel32/ntdll/crypt32/api-ms-win-core; no injection/network APIs
  7. Chrome decrypt path: synthetic v10 GCM blob round-trip via unit test already
     covered; here we verify the binary embeds no plaintext SQL queries
  8. Source hygiene: obf! used for all sensitive literals (grep source)

Ad-hoc verification, NOT a canonical test suite (project has none for tools/).
"""
import hashlib
import re
import subprocess
import sys
from pathlib import Path

D = Path("/root/ir-assessment/redteam/tools/stealer")
EXE = D / "target/x86_64-pc-windows-msvc/release/stealer.exe"
FAILS = []


def check(name, ok, detail=""):
    print(f"{'PASS' if ok else 'FAIL'}  {name}" + (f"  [{detail}]" if detail else ""))
    if not ok:
        FAILS.append(name)


def run(cmd, cwd=D, timeout=300):
    return subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, timeout=timeout)


print("=== stealer ad-hoc verification ===\n")

# 1. artifact
check("artifact exists", EXE.exists())
data = EXE.read_bytes()
check("PE32+ magic", data[:2] == b"MZ" and data[int.from_bytes(data[0x3c:0x40], "little"):][:4] == b"PE\x00\x00")
f = run(["file", str(EXE)])
check("file(1) says PE32+ x86-64", "PE32+" in f.stdout and "x86-64" in f.stdout, f.stdout.strip().split(",", 1)[0])
sha = hashlib.sha256(data).hexdigest()
print(f"      sha256 = {sha}")
oplog = (D / "OPLOG.md").read_text()
check("sha256 recorded in OPLOG.md", sha in oplog)

# 2. host tests
t = run(["cargo", "test", "--target", "x86_64-unknown-linux-gnu"])
m = re.search(r"test result: ok\. (\d+) passed; 0 failed", t.stdout)
check("cargo test host: all pass, 0 failed", bool(m), m.group(0) if m else t.stdout[-200:])

# 3. clippy msvc
c = run(["cargo", "xwin", "clippy", "--target", "x86_64-pc-windows-msvc", "--", "-D", "warnings"], timeout=600)
check("clippy msvc -D warnings clean", c.returncode == 0, c.stderr.strip().splitlines()[-1] if c.returncode else "")

# 4. IOC strings sweep
strs = run(["strings", str(EXE)]).stdout
ioc_patterns = [
    r"origin_url", r"username_value", r"password_value", r"host_key",
    r"encrypted_value", r"encrypted_key", r"os_crypt", r"Login Data",
    r"Google\\Chrome", r"Telegram Desktop", r"KeePass", r"Electrum",
    r"credit_cards", r"COMPUTERNAME", r"SELECT .* FROM logins", r"SELECT .* FROM cookies",
]
hits = [p for p in ioc_patterns if re.search(p, strs, re.I)]
check("0 stealer IOC strings in binary", not hits, f"hits={hits}" if hits else "")

# 5. path leaks
leaks = [l for l in strs.splitlines() if "/root/" in l or "ir-assessment" in l]
check("no build-host path leaks", not leaks, f"{leaks[:3]}" if leaks else "")

# 5b. VERSIONINFO resource present (fake metadata)
strs16 = run(["strings", "-e", "l", str(EXE)]).stdout
check("VERSIONINFO: Nimbus metadata present", "Nimbus Systems Ltd." in strs16 and "Nimbus Sync Agent" in strs16)
check("VERSIONINFO: version 3.2.1.0", "3.2.1.0" in strs16)

# 5c. Authenticode signature present (self-signed expected)
sig = run(["osslsigncode", "verify", "-in", str(EXE)])
check("Authenticode signature present", "Signature Index" in sig.stdout)
check("signature subject = Nimbus", "Nimbus Systems Ltd." in sig.stdout)

# 6. imports
imp = run(["llvm-readobj-16", "--coff-imports", str(EXE)]).stdout
dlls = set(re.findall(r"Name: (\S+\.dll)", imp, re.I))
allowed = {"kernel32.dll", "ntdll.dll", "crypt32.dll", "api-ms-win-core-synch-l1-2-0.dll"}
check("DLL imports within allowlist", dlls <= allowed | {d.lower() for d in allowed}, f"got {sorted(dlls)}")
bad_syms = re.findall(r"Symbol: (\w*(?:CreateRemoteThread|WriteProcessMemory|VirtualAllocEx|QueueUserAPC|WinHttp|InternetOpen|WSAStartup|send|recv)\w*)", imp)
check("no injection/network symbols imported", not bad_syms, f"{bad_syms}" if bad_syms else "")

# 7. no plaintext SQL in binary (spot)
check("no plaintext 'SELECT' in binary", "SELECT origin_url" not in strs)

# 8. source hygiene: sensitive literals obf!'d in source
harvest = (D / "src/harvest.rs").read_text()
raw_sql = re.findall(r'conn\.prepare\(\s*"SELECT', harvest)
check("SQL queries use obf!() in source", not raw_sql)
check("stealth mode implemented", "--stealth" in (D / "src/main.rs").read_text())
check("zeroize dependency declared", "zeroize" in (D / "Cargo.toml").read_text())

print()
if FAILS:
    print(f"RESULT: {len(FAILS)} FAILURES: {FAILS}")
    sys.exit(1)
print("RESULT: ALL PASS (ad-hoc verification, not canonical suite)")
sys.exit(0)
