70a64e3709
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.
54 lines
1.5 KiB
Python
54 lines
1.5 KiB
Python
#!/usr/bin/env python3
|
|
# Dump the FUT atom name table (atom index -> key string) from CardsDLL.
|
|
# Table at VA 0x1802d2760 is an array of char* pointers into .rdata.
|
|
import struct, sys
|
|
|
|
DLL = "/tmp/fut/cardsdll.dll"
|
|
data = open(DLL, "rb").read()
|
|
|
|
# (VA_start, size, file_off) from objdump -h
|
|
SECTIONS = [
|
|
(0x180001000, 0x1e3f62, 0x400), # .text
|
|
(0x1801e5000, 0xa4094, 0x1e4400), # .rdata
|
|
(0x18028a000, 0x54000, 0x288600), # .data
|
|
]
|
|
|
|
def va_to_off(va):
|
|
for start, size, off in SECTIONS:
|
|
if start <= va < start + size:
|
|
return off + (va - start)
|
|
return None
|
|
|
|
def read_cstr(va, maxlen=128):
|
|
off = va_to_off(va)
|
|
if off is None:
|
|
return None
|
|
end = data.find(b"\x00", off, off + maxlen)
|
|
if end < 0:
|
|
return None
|
|
try:
|
|
return data[off:end].decode("ascii")
|
|
except UnicodeDecodeError:
|
|
return None
|
|
|
|
TABLE_VA = 0x1802d2760
|
|
off = va_to_off(TABLE_VA)
|
|
atoms = {}
|
|
for i in range(0, 1200):
|
|
ptr = struct.unpack_from("<Q", data, off + i * 8)[0]
|
|
if ptr == 0:
|
|
s = None
|
|
else:
|
|
s = read_cstr(ptr)
|
|
if s is None:
|
|
# allow a few gaps then stop if we run off the end
|
|
if i > 40 and all(struct.unpack_from("<Q", data, off + (i + k) * 8)[0] == 0 for k in range(4)):
|
|
break
|
|
continue
|
|
if s.isprintable() and 1 <= len(s) <= 40:
|
|
atoms[i] = s
|
|
|
|
for i in sorted(atoms):
|
|
print(f"{i}\t0x{i:x}\t{atoms[i]}")
|
|
print(f"# total {len(atoms)} atoms", file=sys.stderr)
|