#!/usr/bin/env python3 """Profile a cryptominer's configuration from static strings. Extracts stratum pool endpoints, wallet addresses, algorithm identifiers, miner family strings, and resource-control/stealth settings. Reads bytes statically, defangs pool endpoints, and 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,}") RE_STRATUM = re.compile(r"stratum\+(?:tcp|ssl)://[^\s\"'<>]+", re.I) RE_MONERO = re.compile(r"\b4[0-9AB][0-9A-Za-z]{93}\b") RE_BTC = re.compile(r"\b(?:bc1[0-9a-z]{20,60}|[13][a-km-zA-HJ-NP-Z1-9]{25,34})\b") RE_ETH = re.compile(r"\b0x[a-fA-F0-9]{40}\b") ALGOS = ["rx/0", "rx/wow", "cn/r", "cn/2", "cn-heavy", "argon2", "kawpow", "ethash", "randomx", "cryptonight"] MINER_IDS = ["xmrig", "xmr-stak", "minerd", "cpuminer", "nbminer", "phoenixminer", "t-rex", "lolminer", "nanominer"] RESOURCE_KEYS = ["max-cpu-usage", "cpu-priority", "donate-level", "background", "max-threads-hint", "huge-pages", "idle", "watchdog"] def _strings(data: bytes) -> str: return "\n".join(m.decode("latin-1", "ignore") for m in ASCII_RE.findall(data)) def _defang(s: str) -> str: return s.replace("stratum", "stratum-x").replace("://", "[://]").replace(".", "[.]") def profile(path: str) -> dict: blob = _strings(Path(path).read_bytes()) low = blob.lower() pools = sorted({_defang(p) for p in RE_STRATUM.findall(blob)}) wallets = { "monero": sorted(set(RE_MONERO.findall(blob)))[:10], "bitcoin": sorted(set(RE_BTC.findall(blob)))[:10], "ethereum": sorted(set(RE_ETH.findall(blob)))[:10], } wallets = {k: v for k, v in wallets.items() if v} algos = sorted({a for a in ALGOS if a in low}) miners = sorted({m for m in MINER_IDS if m in low}) resource = sorted({r for r in RESOURCE_KEYS if r in low}) return { "pool_endpoints": pools, "wallet_addresses": wallets, "algorithms": algos, "miner_family": miners, "resource_controls": resource, "is_likely_cryptominer": bool(pools or (miners and algos)), } def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description="Profile a cryptominer") sub = parser.add_subparsers(dest="cmd", required=True) p = sub.add_parser("profile") p.add_argument("file") args = parser.parse_args(argv) print(json.dumps(profile(args.file), indent=2)) return 0 if __name__ == "__main__": sys.exit(main())