# OpenFUT Bridge — Claude Code project context Read this first. It's the standing context for every task in this project. Each working session will give you ONE bounded task plus a verification clause; this file is the background that stays true across all of them. ## What this project is OpenFUT is an **offline FIFA 23 FUT (Ultimate Team) emulator** for single-player game preservation. EA permanently shut down FIFA 23's online servers in October 2025, which removed FUT. This project lets a legitimately-owned copy run FUT against a **local emulated backend** instead of EA's (dead) servers. It has two repos: - **OpenFUT Core** — the game-independent FUT economy backend (already largely built). - **OpenFUT Bridge** — the FIFA 23 integration / reverse-engineering layer (this work). ## Hard constraints (do not violate) - **Clean-room only.** Everything is derived from observing the running client's own behaviour. NEVER use, reference, or reproduce leaked EA source code (e.g. the 2021 FIFA 21 / Blaze leak). If a task seems to need it, stop and say so. Clean-room provenance is the legal foundation of the whole project. - **Mark uncertainty, don't invent.** Several things are genuinely unconfirmed: the Fire2 packet framing, ProtoSSL non-blocking return values, and FIFA 23's Blaze component/command IDs. When you don't know a value, leave a clearly labelled `TODO/CONFIRM` rather than guessing a confident-looking number. - **Verify against the client.** The dead servers mean responses are *synthesized and tested against the live offline client*, never captured from EA. The client is the oracle: a gate is "done" when the client advances to the next command. ## Architecture ``` FIFA 23 client (offline, native Windows) | ProtoSSLConnect / ProtoSSLSend / ProtoSSLRecv (in-process) openfut_hook.dll — fakes the connection, captures requests, injects responses | plain localhost TCP, length-prefixed frames (no TLS) blaze_brain (Rust) — decodes requests, crafts Blaze responses <-- iteration surface | OpenFUT Core — supplies real FUT economy data for the FUT gates ``` Why in-process (not a localhost TLS server): FIFA 23's ProtoSSL uses modern TLS with cert pinning, so a fake server gets its cert rejected. Hooking ABOVE the crypto (ProtoSSLSend/Recv take/return plaintext) sidesteps TLS entirely. ## The entry sequence (the gates to reach FUT) The client runs these in order; each must be satisfied before the next fires: 1. **LSX** (port 3216, plaintext loopback) — launcher→game bootstrap. 2. **Blaze redirector** — returns a server host/port. 3. **Blaze preauth** (UTIL) — config / component list. 4. **Blaze login** (AUTHENTICATION) — persona, session key, UID. 5. **Blaze postauth** (UTIL) — telemetry/ticker; "fully online". 6. **FUT entry check** — FIFA-specific eligibility/entitlement wall. 7. **FUT hub load** — club/squad over REST; hand off to OpenFUT Core. Gates 2–5 are largely static/replayable (the client validates little). Gates 6–7 need internally-consistent data and connect to OpenFUT Core. ## Environment - Native Windows boot (chosen for predictable PE/hooking behaviour over Proton). - FIFA 23, with EA Anticheat in its offline/neutralized state. Do NOT assume a task is safe to hook unless EAAC is confirmed neutralized. - Rust is the primary language. Hook = `cdylib`, Windows target. Brain = portable. - Self-hosted Gitea (git.aleshym.co, org Quaternions). Self-hosted CI runner. ## How to work here - One rung at a time. Don't run ahead into a gate that depends on an unconfirmed earlier answer. - When decoding a frame, work from REAL captured bytes the user pastes in — not from a guessed layout. Ask for the bytes if they're not provided. - End each change with how the user verifies it on the client. # OpenFUT Bridge — Task prompts (run in order) Each task is its own Claude Code session. Paste the task, attach the named starting file(s), and don't move to the next until the verification clause passes. The project CLAUDE.md is assumed to be in context. --- ## TASK 1 — Confirm the transport (read-only memory scan) **Goal:** prove whether FIFA 23 uses EA DirtySDK / ProtoSSL before we build any hook around it. Read-only; no hooking, patching, or injection. **Do this:** Write a standalone Windows console program in Rust (target `x86_64-pc-windows-msvc` or `-gnu`) that: 1. Finds the running FIFA 23 process by name (and accepts a PID argument). 2. Enumerates its modules and committed memory regions (e.g. `EnumProcessModules` / `VirtualQueryEx`), readable regions only. 3. Reads memory with `ReadProcessMemory` in chunks (with small overlap so a marker spanning a chunk boundary is still found). 4. Searches for these ASCII markers and prints each hit with its absolute address: `protossl:`, `ProtoSSLSend`, `ProtoSSLRecv`, `ProtoSSLConnect`, `gosredirector`, `DirtySDK`, `blaze`. 5. Prints a summary: which markers were found, and a clear verdict line ("ProtoSSL present" vs "no ProtoSSL markers found"). Keep it dependency-light (the `windows` crate is fine). Comment it for a Rust beginner. It must only read. **Verification:** with FIFA 23 running and sitting at the main menu, the program prints whether the ProtoSSL markers are present. If `protossl:` and the send/recv strings appear, the transport is confirmed and we proceed. If nothing appears after the menu has loaded, STOP — we rethink the transport, don't build the hook. **Note:** reach the main menu before scanning; the networking code/strings may not be paged in at the title screen. --- ## TASK 2 — Loadable DLL shell (prove we can get code in) **Goal:** a `version.dll` proxy that loads into FIFA 23 and runs our code, before any hook logic exists. This isolates "can we inject at all" from "is the hook correct". **Do this:** Create a Rust `cdylib` (Windows target) that: 1. Exports the functions a real `version.dll` exports, forwarding each to the system `version.dll` (proxy/sideload pattern). List the needed exports and implement the forwarding. 2. In `DllMain`, on `DLL_PROCESS_ATTACH`, spawns a thread (NOT work in DllMain itself — loader lock) that writes a line to a log file in a known path, e.g. `C:\openfut\hook.log`, with a timestamp. 3. Provide the `Cargo.toml` (`crate-type = ["cdylib"]`) and the exact build command. Clean-room: this is generic proxy/loader scaffolding, nothing EA-derived. **Verification:** drop the built DLL next to the FIFA 23 executable, launch the game, and confirm `hook.log` gets the timestamped line. Game still reaches the menu normally. If it crashes or the line never appears, fix the proxy/forwarding before continuing. **Caution:** confirm EAAC is in its offline/neutralized state before loading the DLL. Do not load it into an anticheat-active session. --- ## TASK 3 — One landing hook on ProtoSSLSend **Goal:** prove we can hook a ProtoSSL function and see real outbound frames. Just one function, and it calls the original (passive observation). **Do this:** Extend the Task 2 DLL: 1. Add the `retour` crate. Resolve the `ProtoSSLSend` address — first pass: use the absolute address Task 1 reported, converted to a module-relative offset plus the live module base. (We'll switch to a byte-pattern scan later for patch-resilience; leave a TODO for that.) 2. Install a `retour` inline detour on `ProtoSSLSend` with signature `extern "C" fn(*mut c_void, *const u8, i32) -> i32` (x64 = one calling convention; `extern "C"` is correct). 3. In the detour: log `length` and the first ~32 bytes of the buffer as hex, then CALL THE ORIGINAL and return its result (do not block or alter traffic yet). Mark the ProtoSSL return-value conventions and the eventual pattern-scan as `TODO/CONFIRM` per the project rules. **Verification:** launch the game, attempt to go online / load FUT, and confirm `hook.log` shows ProtoSSLSend calls with non-trivial byte dumps — these are the client's real outbound Blaze frames (still TLS-bound on the wire, but plaintext here, which is the whole point). Seeing real frames = hooking works, and we now have actual bytes to decode in later tasks. Paste a few of those captured frames into the next session. --- ## What to attach to each task - Task 1: nothing (fresh program), or the Linux `protossl_scan.rs` as a logic reference to port. - Task 2: nothing, or your existing `version.dll` proxy shell if you have one. - Task 3: the Task 2 DLL, plus the `openfut_hook_sketch.rs` as the structural reference, plus the address Task 1 reported. Once Task 3 yields real captured frames, later tasks (the brain handlers per gate) should always include the actual pasted bytes — decoding real frames is far more reliable than guessing the Fire2 layout.