igneum/packaging/windows/host-gate.py

126 lines
5.8 KiB
Python

#!/usr/bin/env python3
"""The window host gate (0.3.22; PC 2, 7 October 2026: a 0.3.21 installer carried a mingw-built "Igneum Miner.exe" whose
version resource read 0.3.22.0 and which crashed in ntdll seconds after starting its engine). Before a host enters a
payload, three facts must hold or the payload is refused:
1. the exe's version resource (FileVersion and ProductVersion) equals the installer's version (as "a.b.c" or "a.b.c.0");
2. the exe carries no mingw-w64 signature (the GNU runtime strings "Mingw-w64", "libgcc", "GCC: (GNU", "libstdc++-6.dll",
"libwinpthread-1.dll"): the host is the MSVC build (app\\windows\\BUILD-APP.bat) or nothing;
3. when a pin file is given (packaging/windows/host.sha256: one sha256 per line, the cut's MSVC host), the exe's sha256
is in it.
host-gate.py <Igneum Miner.exe> <version> [<pin file>] exit 0 = pass, 1 = refused (every reason printed)
host-gate.py --self-test known-bad and known-good blobs
No dependency; reads the version strings straight from the resource's UTF-16LE text, which is how every PE carries them."""
import hashlib
import re
import sys
MINGW_MARKS = [b"Mingw-w64", b"mingw-w64", b"libgcc", b"GCC: (GNU", b"libstdc++-6.dll", b"libwinpthread-1.dll"]
def utf16(s):
return s.encode("utf-16-le")
def version_strings(blob):
"""FileVersion and ProductVersion from the VS_VERSIONINFO StringFileInfo block: the UTF-16 key, 0 to 3 NUL words of
padding, then the UTF-16 value up to its NUL."""
out = {}
for key in ("FileVersion", "ProductVersion"):
m = re.search(re.escape(utf16(key)) + rb"\x00\x00(?:\x00\x00){0,3}((?:[^\x00]\x00|\x00[^\x00]){1,40}?)\x00\x00", blob)
if m:
try:
out[key] = m.group(1).decode("utf-16-le").strip()
except UnicodeDecodeError:
out[key] = ""
return out
def norm(v):
parts = [p for p in re.split(r"[.,\s]+", v.strip()) if p != ""]
while len(parts) < 4:
parts.append("0")
return ".".join(parts[:4])
def check(blob, version, pins=None):
reasons = []
vs = version_strings(blob)
want = norm(version)
for key in ("FileVersion", "ProductVersion"):
have = vs.get(key)
if have is None:
reasons.append(f"no {key} in the version resource")
elif norm(have) != want:
reasons.append(f"{key} reads {have}, the installer is {version}")
marks = [m.decode() for m in MINGW_MARKS if m in blob]
if marks:
reasons.append("a mingw-w64 build (" + ", ".join(marks) + "): the host must be the MSVC build")
if pins is not None:
sha = hashlib.sha256(blob).hexdigest()
if sha not in pins:
reasons.append(f"sha256 {sha[:12]} is not the cut's pinned MSVC host ({', '.join(p[:12] for p in pins) or 'no pin'})")
return reasons
def read_pins(path):
pins = []
with open(path, encoding="utf-8") as f:
for line in f:
line = line.split("#", 1)[0].strip().lower()
if re.fullmatch(r"[0-9a-f]{64}", line):
pins.append(line)
return pins
def fake_pe(file_version, product_version, extra=b""):
"""A blob with a version resource shaped like a real one (the strings, the padding, the NULs)."""
return (b"MZ" + b"\x00" * 64 + utf16("FileVersion") + b"\x00\x00\x00\x00" + utf16(file_version) + b"\x00\x00"
+ utf16("ProductVersion") + b"\x00\x00\x00\x00" + utf16(product_version) + b"\x00\x00" + extra)
def self_test():
# known-bad first: the take-4 host's shape, 0.3.22.0 inside a 0.3.21 installer, mingw-built
bad = fake_pe("0.3.22.0", "0.3.22.0", b"...Mingw-w64 runtime failure:...libgcc_s_seh-1.dll...")
r = check(bad, "0.3.21", pins=[])
assert any("FileVersion reads 0.3.22.0" in x for x in r), r
assert any("mingw-w64 build" in x for x in r), r
assert any("not the cut's pinned" in x for x in r), r
# a right version but a mingw build is still refused
r = check(fake_pe("0.3.21.0", "0.3.21.0", b"GCC: (GNU) 13-posix"), "0.3.21")
assert r == ["a mingw-w64 build (GCC: (GNU): the host must be the MSVC build"], r
# known-good: the version equal in both forms, no GNU strings, the sha pinned
good = fake_pe("0.3.21.0", "0.3.21", b"Microsoft (R) C/C++ Optimizing Compiler")
assert check(good, "0.3.21") == [], check(good, "0.3.21")
assert check(good, "0.3.21", pins=[hashlib.sha256(good).hexdigest()]) == []
assert check(good, "0.3.21", pins=["0" * 64]) != [], "a pin that is not this exe refuses"
# no resource at all is refused (nothing to compare)
r = check(b"MZ" + b"\x00" * 200, "0.3.21")
assert r == ["no FileVersion in the version resource", "no ProductVersion in the version resource"], r
print("self-test passed: a 0.3.22.0 mingw host fails a 0.3.21 installer on all three counts, a right-version mingw host fails, a pinned MSVC host passes, a resource-less blob fails")
def main(argv):
if len(argv) >= 2 and argv[1] == "--self-test":
self_test()
return 0
if len(argv) < 3:
print(__doc__)
return 2
exe, version = argv[1], argv[2]
pins = read_pins(argv[3]) if len(argv) > 3 else None
with open(exe, "rb") as f:
blob = f.read()
reasons = check(blob, version, pins)
vs = version_strings(blob)
sha = hashlib.sha256(blob).hexdigest()
if reasons:
print(f"host-gate: REFUSED {exe} for {version} (FileVersion {vs.get('FileVersion')}, ProductVersion {vs.get('ProductVersion')}, sha256 {sha[:12]}):")
for r in reasons:
print(f" - {r}")
return 1
print(f"host-gate: ok {exe} is {version} (FileVersion {vs.get('FileVersion')}, ProductVersion {vs.get('ProductVersion')}), no mingw signature, sha256 {sha[:12]}" + (" pinned" if pins is not None else ""))
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))