fifa17-python: commit working FUT backend deployment (client/server split)
Freeze the running offline FUT backend into version control as fifa17-recon/docker/fifa17-python/ - declarative and rebuildable from a fresh checkout: * OPENFUT_BIND / OPENFUT_ADVERTISE client/server split in the responders (lsx, blaze, roster, utas, pow) + entrypoint.sh; OPENFUT_ADVERTISE is required for remote mode (compose and entrypoint fail without it) * docker-compose.yml reproducing the frozen baseline container exactly (env, ports incl. the 8085->8080 POW-content remap, /state bind, restart) * .env.example / .env for site config - the LAN IP is never hardcoded in source * tools/ + data/ staged from openfut-fut-backend:python-baseline-2026-08-10, verified byte-identical to the running container at freeze time * client_arm.sh (the 105 client-side arming counterpart) * Dockerfile bakes /app/SHA256SUMS.txt so any image is self-identifying * docs/BASELINE-python-2026-08-10.md: frozen image/container/hash record, restore instructions and rebuild-equivalence procedure Secrets (redir key/cert, .env) and runtime state (docker/state) stay gitignored. The live container is untouched pending the .105 launcher audit.
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Minimal minidump reader: exception code/address + module list, so a FIFA 17
|
||||
CrashDump can be mapped to <module>+RVA (and thence to a Ghidra address)."""
|
||||
import struct, sys
|
||||
|
||||
p = sys.argv[1]
|
||||
d = open(p, "rb").read()
|
||||
assert d[:4] == b"MDMP", "not a minidump: %r" % d[:4]
|
||||
ver, nstreams, dirrva = struct.unpack_from("<IiI", d, 4)[0], *struct.unpack_from("<II", d, 8)
|
||||
nstreams, dirrva = struct.unpack_from("<II", d, 8)
|
||||
|
||||
streams = {}
|
||||
for i in range(nstreams):
|
||||
st, size, rva = struct.unpack_from("<III", d, dirrva + i * 12)
|
||||
streams.setdefault(st, []).append((size, rva))
|
||||
print("streams:", sorted(streams))
|
||||
|
||||
|
||||
def mstring(rva):
|
||||
(ln,) = struct.unpack_from("<I", d, rva)
|
||||
return d[rva + 4: rva + 4 + ln].decode("utf-16-le", "replace")
|
||||
|
||||
|
||||
mods = []
|
||||
if 4 in streams:
|
||||
size, rva = streams[4][0]
|
||||
(n,) = struct.unpack_from("<I", d, rva)
|
||||
off = rva + 4
|
||||
for i in range(n):
|
||||
base, sz, csum, ts, nrva = struct.unpack_from("<QIIII", d, off)
|
||||
mods.append((base, sz, mstring(nrva)))
|
||||
off += 108
|
||||
print("modules:", len(mods))
|
||||
|
||||
exc_addr = None
|
||||
if 6 in streams:
|
||||
size, rva = streams[6][0]
|
||||
tid, _pad = struct.unpack_from("<II", d, rva)
|
||||
code, flags, recptr, addr, nparams = struct.unpack_from("<IIQQI", d, rva + 8)
|
||||
exc_addr = addr
|
||||
NAMES = {0xC0000005: "ACCESS_VIOLATION", 0xC000001D: "ILLEGAL_INSTRUCTION",
|
||||
0xC0000094: "INT_DIVIDE_BY_ZERO", 0xC0000096: "PRIV_INSTRUCTION",
|
||||
0x80000003: "BREAKPOINT", 0xC00000FD: "STACK_OVERFLOW",
|
||||
0xC0000374: "HEAP_CORRUPTION", 0xC0000135: "DLL_NOT_FOUND"}
|
||||
print("\n=== EXCEPTION ===")
|
||||
print(" thread : %#x" % tid)
|
||||
print(" code : %#010x %s" % (code, NAMES.get(code, "?")))
|
||||
print(" address : %#018x" % addr)
|
||||
params = [struct.unpack_from("<Q", d, rva + 8 + 32 + i * 8)[0] for i in range(min(nparams, 15))]
|
||||
print(" params : %s" % [hex(x) for x in params])
|
||||
if code == 0xC0000005 and len(params) >= 2:
|
||||
print(" -> %s at %#x" % ({0: "READ from", 1: "WRITE to", 8: "EXECUTE at"}.get(params[0], "access"),
|
||||
params[1]))
|
||||
|
||||
if exc_addr is not None:
|
||||
hit = [m for m in mods if m[0] <= exc_addr < m[0] + m[1]]
|
||||
print("\n=== FAULTING MODULE ===")
|
||||
if hit:
|
||||
base, sz, name = hit[0]
|
||||
short = name.split("\\")[-1]
|
||||
print(" %s base=%#x size=%#x" % (short, base, sz))
|
||||
print(" RVA = %#x" % (exc_addr - base))
|
||||
print(" ghidra (PE base 0x180000000) = %#x" % (0x180000000 + (exc_addr - base)))
|
||||
else:
|
||||
print(" address %#x is in NO loaded module (bad indirect call / corrupt ptr)" % exc_addr)
|
||||
|
||||
print("\n=== modules of interest ===")
|
||||
for base, sz, name in mods:
|
||||
s = name.split("\\")[-1].lower()
|
||||
if any(k in s for k in ("cards", "fifa", "dbdata", "core", "game")):
|
||||
print(" %-28s base=%#014x size=%#x" % (name.split("\\")[-1], base, sz))
|
||||
Reference in New Issue
Block a user