bc6612697a
Add the reverse-engineering work for FIFA 23 online integration: - tools/protossl-scan: read-only memory scanner that confirms the DirtySDK/ProtoSSL transport, cross-references strings to code (xref/xref-str), and disassembles the enclosing function (disasm). Located _ProtoSSLSendPacket at FIFA23.exe+0xEFA530 (plaintext TLS record assembler) via the "_ProtoSSLSendPacket" debug string xref. - openfut-hook: version.dll proxy (forwards all 17 real exports) that injects into FIFA 23 and installs an inline detour on _ProtoSSLSendPacket, plus connect/DNS (getaddrinfo) capture and local LSX/redirect listeners. Logs to C:\openfut\hook.log. - CLAUDE.md: bridge project context + the gate-sequence task roadmap. Findings so far: with the anadius offline emulator the game never attempts the online Blaze connection (local auth gate), so capture of live Blaze frames is blocked pending an online-session fake. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
191 lines
8.6 KiB
Markdown
191 lines
8.6 KiB
Markdown
# 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.
|