# Connection-gate findings (clean-room) **Status:** observed behaviour only — derived from running the client and reading the repack's own files. No EA source used. Unconfirmed values are marked `TODO/CONFIRM` rather than guessed. ## Components (observed) | Component | Role | |---|---| | `FIFA23.exe` | Game. Statically links EA's **Ebisu SDK** (online) and **DirtySDK/ProtoSSL** (transport). Loads at fixed base `0x140000000` — no ASLR seen across launches. | | `_ProtoSSLSendPacket` @ `FIFA23.exe+0xEFA530` | DirtySDK TLS record assembler — plaintext in, encrypts in place. Already located + hooked. | | `anadius64.dll` | anadius EA-app/Origin **LSX server** emulator (ASLR'd). Provides offline DRM / entitlements / persona so the game *launches*; deliberately keeps it **offline**. | | `FakeEAACLauncher` | Anti-cheat bypass only. Irrelevant to the online gate. | ## Observed online-startup flow 1. Ebisu SDK opens LSX socket(s) to anadius; a **challenge/response handshake** completes — captured XML: `` / `` / ``, `sender="EALS"`, `ContentId 16115019`. 2. River/PIN telemetry `` is emitted. 3. **No further socket traffic.** Clicking Ultimate Team → "connecting to the EA Servers…" → **zero** network attempts (no Blaze DNS, no `connect`, nothing on `send`/`recv`/`WSASend`/`WSARecv`) → falls back to offline. ## Conclusion: the decision is upstream and in-process - The online/offline verdict is delivered through anadius's **in-process detoured Ebisu calls**, not socket messages. (No `GetAuthCode`/`GoOnline`/ entitlement query appears on any socket, sync or async.) - The game therefore **never reaches DirtySDK/ProtoSSL for Blaze** — it aborts before any `ProtoSSLConnect(gosredirector…)`. The gate is an **Ebisu-SDK connection-state / online-session check upstream of the transport.** - `ONLINE_ACCESS` is a `Blaze::Nucleus::EntitlementType` (enum value `1`). anadius's `GoOnline` LSX handler (`anadius64.dll+0x2BB90`) is a success stub; `anadius64.dll+0xB6B1` is a large entitlement/profile builder that *does* reference `ONLINE_ACCESS`. Reverse-engineering that entitlement-status logic is the **wrong fight** (see strategy). ## Strategy (decided) Do **not** make anadius report "online." anadius exists to keep the game offline, and it can't be removed without breaking launch/DRM. Instead: > Let the game run its **real** online flow and answer that flow ourselves via > the hook + brain. Target the Ebisu connection-state check the FUT-entry path > polls; make the game *pass* it so it issues the real `ProtoSSLConnect` to the > Blaze redirector → our redirect + ProtoSSL hook capture the real frames. This deletes the "reverse-engineer anadius's entitlement logic" problem. ## Next RE step (converges with the ProtoSSL hook) 1. Locate and **read-only hook `ProtoSSLConnect`** (same DirtySDK module and technique that found `_ProtoSSLSendPacket`). Confirms the game never initiates the Blaze connection (pins the gate strictly upstream) and gives us the exact symbol that will flip from "never called" to "called" on success. 2. Locate the Ebisu **connection-state getter** the FUT-entry / "connecting" UI polls. Candidate string anchors (observed): `ONLINE_STATUS_EVENT`, `GoOnline` result handling, the "connecting to the EA Servers" UI trigger. 3. Determine the minimal intervention to make that getter report **connected** (out-hook it in our `version.dll`, winning over anadius's detour) so the game proceeds to `ProtoSSLConnect`. - `TODO/CONFIRM`: whether out-hooking the getter is sufficient, or secondary checks (auth-token presence) also gate the attempt. --- ## M1 results (read-only investigation) Method: `protossl-scan` (xref / disasm / callers, app-module-restricted) against the live client, plus the existing `connect`/DNS/LSX hooks. Observed behaviour only — no EA source. ### Point 1 — is `ProtoSSLConnect` reached on the "connecting" abort? **NO — gate is upstream. CONFIRMED.** - The existing `connect` / `GetAddrInfoW` / `getaddrinfo` hooks show the client makes **zero** network attempts during the "connecting to the EA Servers" abort: no DNS for any `gosredirector.*` host, no `connect` to any external address. - The DirtySDK/ProtoSSL transport is therefore never reached — the abort is entirely upstream and in-process. - `ProtoSSLConnect` has no debug string and sits behind the DirtySDK API, so an explicit hook on it isn't needed to prove this; the behavioural evidence is conclusive. `TODO/CONFIRM`: locate `ProtoSSLConnect` by signature later, as a positive M2 trip-wire (it should fire once we flip the gate). ### Surface mapped (clean-room) - **Redirector host table** (`FIFA23.exe` .rdata, pointer table @ `+0x83FC858`): `spring18.gosredirector.{sdev,stest,scert}.ea.com` + production `spring18.gosredirector.ea.com`. - **Redirector request/response config** (same region): `X-BLAZE-ERRORCODE`, **`Authorization:`**, `` — the redirector request carries an **Authorization header (a Nucleus token)**. - **Enum-name tables** (serialization only, NOT decision code): `ONLINE_ACCESS` (`Blaze::Nucleus::EntitlementType` = 1), `ONLINE_STATUS_EVENT`, … These are reflection tables keyed by enum *value*; string-xref of them is a dead end for the decision (the decision compares values, not strings). ### Point 2 — name the connection-state function: **PARTIAL.** - The exact connection-state decision is behind heavy C++ vtable indirection (the redirector config's two code pointers resolved to a virtual-dispatch thunk @ `FIFA23.exe+0x27BD4C0` and a `ret 0` stub @ `+0x4F3CBC0`). The memory-scan toolkit (string / pattern / xref / callers) cannot efficiently navigate this. - **Pinning the exact function needs a static disassembler with decompilation (Ghidra / IDA) on `FIFA23.exe`.** `protossl-scan` remains the bridge to the live process (mapping static addresses to the ASLR'd runtime, confirming hits, installing hooks). - `TODO/CONFIRM`: name the connection-state getter by module+offset via Ghidra. ### Point 3 — gate count: **TWO gates (state + token). Evidence-backed.** - The online-connect path **reads/requires an auth (Nucleus) token**: the redirector request carries an `Authorization:` header, and the SDK surface has `GetAuthCode` / `FakeAuth` / ``. So it is **not** a single connection-state boolean flip — even with the state forced "online", the client needs a valid token to build the redirector request. - **Conclusion for M2: plan for two gates** — (a) the connection-state decision, and (b) supplying an auth token the client accepts. - `TODO/CONFIRM` the exact abort point (no-token vs state-says-offline vs both) — needs Ghidra-level control-flow tracing. ### Recommendation Load `FIFA23.exe` into **Ghidra** to (a) name the connection-state getter precisely and (b) confirm the gate mechanism, then return to `protossl-scan` + the hook to map those addresses onto the live process and install the M2 hook.