Read-only M1 investigation results appended to connection-gate-findings.md: - Confirmed ProtoSSLConnect is never reached on the "connecting" abort (gate is upstream/in-process) via the existing connect/DNS hooks. - Mapped the surface: redirector host table (gosredirector.* per env), the redirector request config (X-BLAZE-ERRORCODE, Authorization:, <errorCode>), and the enum-name serialization tables (ONLINE_ACCESS, ONLINE_STATUS_EVENT). - Key answer: the online-connect path requires a Nucleus auth token (the redirector request carries an Authorization header) => TWO gates (state + token), not a single boolean flip. - The exact connection-state function is behind C++ vtable indirection; pinning it needs Ghidra. protossl-scan stays the live-process bridge. protossl-scan: add `callers` mode (find call/jmp sites to a function) and restrict xref/callers scans to the app modules (FIFA23.exe/anadius64.dll) for speed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7.0 KiB
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
- Ebisu SDK opens LSX socket(s) to anadius; a challenge/response handshake
completes — captured XML:
<Challenge>/<ChallengeResponse>/<ChallengeAccepted>,sender="EALS",ContentId 16115019. - River/PIN telemetry
<session type=boot>is emitted. - No further socket traffic. Clicking Ultimate Team → "connecting to the EA
Servers…" → zero network attempts (no Blaze DNS, no
connect, nothing onsend/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_ACCESSis aBlaze::Nucleus::EntitlementType(enum value1). anadius'sGoOnlineLSX handler (anadius64.dll+0x2BB90) is a success stub;anadius64.dll+0xB6B1is a large entitlement/profile builder that does referenceONLINE_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
ProtoSSLConnectto 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)
- 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. - Locate the Ebisu connection-state getter the FUT-entry / "connecting" UI
polls. Candidate string anchors (observed):
ONLINE_STATUS_EVENT,GoOnlineresult handling, the "connecting to the EA Servers" UI trigger. - 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 toProtoSSLConnect.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/getaddrinfohooks show the client makes zero network attempts during the "connecting to the EA Servers" abort: no DNS for anygosredirector.*host, noconnectto any external address. - The DirtySDK/ProtoSSL transport is therefore never reached — the abort is entirely upstream and in-process.
ProtoSSLConnecthas 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: locateProtoSSLConnectby 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+ productionspring18.gosredirector.ea.com. - Redirector request/response config (same region):
X-BLAZE-ERRORCODE,Authorization:,<errorCode>— 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+0x27BD4C0and aret 0stub @+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-scanremains 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 hasGetAuthCode/FakeAuth/<GameToken>. 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/CONFIRMthe 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.