12 Commits

Author SHA1 Message Date
funman300 7dcf610b71 openfut-hook: RE instrumentation for the Blaze dial-gate investigation
In-process, read-only probes and transport observation built while closing
the online/FUT route from both the memory and network sides.

- probe.rs / dial_notification.rs: menu-time ctx dump, connMgr enumerator,
  synthetic dial-notification + direct-call dial trigger, and the
  [element+0x40] container write-watchpoint. All env-gated, one-shot,
  VirtualQuery-guarded; none alter game state by default.
- transport_watch.rs + connect/connectex/hooks/lib: M0 transport observation
  (grep-friendly TRANSPORT_WATCH logging on the existing getaddrinfo/connect/
  WSAConnect/ConnectEx detours) and an IPv6 (v4-mapped) EA-redirect so the
  game's IPv6 :443 dials land on the bridge instead of the dead servers.

Findings: the game never initiates a Blaze connection offline; the dial
handler is registered by a self-registering, message-driven state machine
whose container stays empty with no Blaze exchange. See openfut-bridge
docs/closure-and-preservation.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:58:17 -07:00
funman300 ff4b5a87f5 probe: ungate the forcing experiment (manual-only)
install_force_connect() is no longer auto-called from install_probes_deferred,
so normal probe builds don't poke the online flow. Kept for reference; re-enable
the call to reproduce the 2026-07-02 forcing experiment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 18:45:08 -07:00
funman300 493b9e0573 probe: run-4 connect-state lifecycle spread (8 targets)
Expands to 8 entry probes across the connect-state lifecycle (ctor, controller
accessor, four vtable steps) to distinguish entered-but-stalled from never-entered.
Result: ctor fires x4, everything else 0 — subsystem created but dormant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 18:03:50 -07:00
funman300 c1d1f03ec8 probe: retarget to game-side connect layer + add guarded session-context sampler
Replaces the anadius-connectivity probes with the game-side Nucleus-connect
functions (nucleusConnectREST/Trusted, connect-state tick) and adds a
VirtualQuery-guarded sampler thread that reads X=[0x14acd02c0] -> M=[X+0x360]
-> ctx=[M+0x778] once/sec to observe the session context directly. Per-slot
log cap prevents per-frame handlers flooding the log. Run 3 result: ctx is
non-null but the connect functions are never called (see bridge findings).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 17:56:31 -07:00
funman300 3c3dc32fc6 probe: add behavior-preserving mid-function detour to capture the live OnlineStatusEvent listener
The OnlineStatusEventT::HandleMessage dispatch resolves its game-side
listener only at runtime (call [rax+0x28]). openfut_listener_stub patches
FIFA23.exe+0x274d4d7 to replicate the four dispatch instructions while
logging the resolved vtable/fn, then resumes. Alignment-safe (saves/rounds
rsp before the log call). Result: listener = FIFA23.exe+0x2751060 = ret 0,
a no-op default vtable slot -> the online->auth transition is state-polled,
not callback-driven.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 17:25:33 -07:00
funman300 feaff0443f hook: in-process RE instrumentation + LSX redirect + capture tooling
Hook-side tooling for the LSX/Blaze reverse-engineering effort:

- probe.rs (new, `probe` feature): passive logging detours on FIFA's online-flow
  functions via the unhook/rehook pattern (no trampoline/relocation, works on
  RIP-relative prologues). Deferred install waits for anadius64.dll to load, then
  logs enter/return for GoOnline + GetInternetConnectedState (anadius) and the
  OnlineStatusEvent/Login deserializers (FIFA23.exe). Revealed that our pushed LSX
  events reach FIFA and parse OK, while GoOnline never fires — localizing the online
  gate to FIFA's game-side event consumer.
- connect_hook.rs: redirect FIFA's LSX connect :3216 → :3217 so it lands on the
  native openfut-bridge LSX server (slips past anadius's in-process :3216 intercept);
  gated off under the `capture_baseline` feature.
- recv_hook.rs: boundary-safe trampolines + LSX peer filtering for the
  capture_baseline path (log anadius's real LSX frames when the redirect is off).

Build the instrumented DLL with `--features probe` (or `--features capture_baseline`
for the anadius-baseline capture). Both features are off by default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 16:59:27 -07:00
funman300 87241acc1a feat(hook): expand IAT hook coverage with TLS bypass, connect/recv hooks, and logging
Adds connect_hook, connectex_hook, recv_hook, ssl_patch, tls_bypass, lsx, ea_stub,
and origin_spy modules to intercept EA's TLS and socket layers in addition to
getaddrinfo. Adds DLL-level logging to C:\openfut_hook.log for debugging. Also
patches windows-sys feature flags to include Cryptography and Threading APIs needed
by the new hooks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 10:36:17 -07:00
funman300 3b965f1f3f feat: add setcap step to Setup tab for port 443 binding
Adds Step 2 in the Setup tab: grants cap_net_bind_service to the bridge
binary via pkexec/sudo so it can bind port 443 directly. On success,
automatically updates bridge_listen_addr to 0.0.0.0:443 — no iptables
rules required. Step re-detects cap state on each frame so it stays
accurate after a rebuild clears the capability.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 09:20:04 -07:00
funman300 099241d9ca fix: correct default hook DLL path
The default hook_dll_path was constructed relative to Documents/OpenFUT/
but the launcher repo lives at Documents/openfut-launcher/, causing the
Setup tab to always show "DLL not built yet" even after building.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 21:52:14 -07:00
funman300 dfa2c9afc7 feat: make hook redirect IP configurable from launcher
The DLL now reads openfut.cfg from its own directory on DLL_PROCESS_ATTACH
and uses the IP it contains as the redirect target instead of hardcoding
127.0.0.1. Falls back to 127.0.0.1 if the file is absent.

The launcher writes openfut.cfg alongside version.dll when deploying, and
the Setup tab exposes a "Redirect IP" field with an "Update" button that
rewrites openfut.cfg in-place without redeploying the DLL. Useful when
running the emulator on a different machine on the LAN.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 21:08:44 -07:00
funman300 9b5da57f12 feat: replace hosts file with DLL injection hook
Adds openfut-hook/, a Windows DLL (cdylib, x86_64-pc-windows-gnu) that
patches the IAT of FIFA 23 at load time to redirect getaddrinfo calls
for fut.ea.com / utas.*.fut.ea.com to 127.0.0.1, sending all FUT
traffic to the local bridge — no /etc/hosts changes needed.

Deployment: the launcher copies openfut_hook.dll into the FIFA 23 game
folder as version.dll (a DLL FIFA loads but delegates to system).
Proton picks up the local copy automatically when you set:
  WINEDLLOVERRIDES="version=n,b" %command%
in Steam launch options.

Also updates cert install to try the Wine/Proton cert store (wine
certutil) before falling back to the Linux system CA store, and removes
all hosts file code from setup.rs / app.rs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 21:05:35 -07:00
funman300 fc894a7f77 feat: initial OpenFUT Launcher
GUI desktop app (egui/eframe) that manages the openfut-core and
openfut-bridge services with a single window.

- Dashboard: start/stop each service independently or together; live
  status indicators; quick-status for cert and hosts
- Logs: real-time stdout/stderr from both processes, colour-coded by
  level, follow mode and manual clear
- Setup: add/remove EA hostname redirects in /etc/hosts (pkexec/sudo);
  install the bridge TLS cert into the system CA store
- Config: all binary paths and env vars editable in-app; persisted to
  ~/.config/openfut-launcher/config.json

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 20:02:02 -07:00
1034 changed files with 5414 additions and 681706 deletions
-25
View File
@@ -1,25 +0,0 @@
# OpenFUT Docker stack configuration. Copy to .env and adjust.
# All values have sensible defaults in docker-compose.yml; override as needed.
# --- Container registry (Gitea) ---
# Images resolve to ${REGISTRY}/${NAMESPACE}/<image>:${TAG}
# e.g. git.aleshym.co/openfut/openfut-core:latest
REGISTRY=git.aleshym.co
NAMESPACE=openfut
TAG=latest
# --- Networking ---
# Where the bridge (FIFA client entry point) is published. 0.0.0.0 = all
# interfaces so LAN clients can connect. Set to a specific IP to restrict.
BRIDGE_PUBLISH=0.0.0.0
# Where core's REST API is published. 127.0.0.1 keeps it host-local (the bridge
# still reaches it over the internal docker network). Set 0.0.0.0 to expose it.
CORE_PUBLISH=127.0.0.1
# --- Behaviour ---
# Bridge returns placeholder JSON + captures unknown routes when true.
PLACEHOLDER_MODE=true
# --- Logging (RUST_LOG filters) ---
CORE_LOG=openfut_core=info,tower_http=info
BRIDGE_LOG=openfut_bridge=info,tower_http=info
+4 -36
View File
@@ -1,38 +1,6 @@
# Rust build artifacts
target/
**/target/
# SQLite databases
*.db
*.db-shm
*.db-wal
# Environment files
.env
.env.local
# Captures (runtime data, not source)
openfut-bridge/captures/
# Python
__pycache__/
*.pyc
# Editor
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Frozen baseline archives / inspects / manifests
/docker-backups/
gate-evidence/
# Raw Fire2 frame captures — forensic evidence, may contain session material.
# Sanitize with `blaze-sanitize` before anything leaves this machine.
*.ofcap
captures/
# runtime SQLite DB (created when services run from this dir)
openfut.db
openfut.db-shm
openfut.db-wal
-12
View File
@@ -1,12 +0,0 @@
[submodule "openfut-core"]
path = openfut-core
url = https://git.aleshym.co/funman300/OpenFUT-Core.git
[submodule "openfut-bridge"]
path = openfut-bridge
url = https://git.aleshym.co/funman300/OpenFUT-Bridge.git
[submodule "openfut-launcher"]
path = openfut-launcher
url = https://git.aleshym.co/funman300/openfut-launcher.git
[submodule "fifa-blaze"]
path = fifa-blaze
url = https://git.aleshym.co/funman300/fifa-blaze.git
-163
View File
@@ -1,163 +0,0 @@
# AGENTS.md — OpenFUT
**Read this first.** It is the entry point for AI-assisted work on OpenFUT. It supersedes the
root `README.md` and `CLAUDE.md`, which are **stale** (they describe an earlier FIFA 23 plan).
## Project
OpenFUT is a preservation / private-server project that restores **offline, single-player FIFA
Ultimate Team (FUT)** after EA retired the online servers. You must own the game legitimately; the
project does not bypass ownership checks — it only re-serves the dead online services locally.
**Current active target: FIFA 17 (PC).** A clean-room emulation of the full online + FUT stack
was proven working end-to-end on **2026-08-01** (auth → Blaze login → device-trust → FUT hub).
This lives in `fifa17-recon/`. The FIFA 17 work is explicitly the **Rosetta Stone for FIFA 23**
(identical Blaze/LSX/UTAS wire format), so FIFA 23 remains the eventual second target.
Three moving parts, kept strictly separate:
- **The FIFA client** — the retail game (FIFA 17 now). Unmodified except live cert-verify patches.
- **The emulation layer** — Python responders in `fifa17-recon/tools/` (LSX, Blaze, UTAS, roster)
that impersonate EA's online services on localhost. This is where all reverse engineering lives.
- **OpenFUT Core** — a game-independent REST FUT economy backend (`openfut-core/`), feature-complete
and tested. Knows nothing about FIFA. Intended to eventually back the emulation layer's FUT data.
> The emulation layer and Core are **not yet wired together.** The FIFA 17 UTAS server currently
> serves its own hardcoded/JSON payloads, not Core's API. See `docs/PROJECT_STATE.md`.
## Repository map
Monorepo. `openfut-core`, `openfut-bridge`, `openfut-launcher`, `fifa-blaze` are **git submodules**
(each with independent history — use `tea`/Gitea, not `gh`). `fifa17-recon/` is a plain directory.
| Path | What it is | Status |
|---|---|---|
| `fifa17-recon/` | **The live path.** FIFA 17 offline FUT emulation: Python responders, cert patcher, runbook, RE write-ups. | Working |
| `openfut-core/` | Rust (Axum + SQLite) FUT economy backend. Game-independent REST API. | Working, tested |
| `openfut-bridge/` | Rust FIFA 23 in-process hook / proxy RE effort. | Blocked (see below) |
| `fifa-blaze/` | Rust Blaze protocol emulator scaffold for FIFA 23 (capture stub). | Milestone 1 stub |
| `openfut-launcher/` | Rust egui/eframe desktop launcher (targets FIFA 23 hook flow). | Legacy plan |
| `docs/` | **Mirrors** of the vault (`OpenFUT-Vault`), which is canonical. Direction pivots + context. | — |
| `tools/` | Host-side RE helpers (file-watch-diff, exporters, squad-injector) from the FLE-bridge idea. | Legacy plan |
| `setup.sh` | FIFA 23 full-stack orchestrator (core+bridge). | Legacy plan |
**Legacy vs live:** the project pivoted twice — (1) FIFA 23 Blaze backend → (2) FIFA 23 as a match
renderer driven by an FLE Lua bridge (`docs/direction.md`) → (3) **FIFA 17 full online emulation,
which succeeded and is now the primary path** (`fifa17-recon/`). Treat `openfut-bridge`,
`openfut-launcher`, `fifa-blaze`, `tools/`, `setup.sh`, and `docs/direction.md` as historical unless
a task explicitly targets the FIFA 23 port.
## Architecture (live path)
```
FIFA 17 client (Wine/Proton, base 0x140000000)
│ autopatch.py NOPs two ProtoSSL cert-verify gates in /proc/PID/mem
├─ LSX 127.0.0.1:4216 → lsx_responder_v2.py (Origin login/profile/authcode)
├─ TLS 127.0.0.1:42127 → blaze_responder_v3b.py (Blaze redirector, via DNAT of 159.153.51.20)
├─ Blaze 42130 / Nucleus 42131 → blaze_responder_v3b.py (Fire2/Heat2 binary + login)
├─ easw.easports.com (→127.0.0.1) :8099 → utas_server.py (UTAS/RS4 FUT API + device-trust)
└─ roster :8081 → roster_server.py (FUT roster-update XML)
OpenFUT Core (openfut-core, :8080) ── clean REST FUT economy ── NOT YET CONNECTED to the above
```
Host arming (`root_arm.sh` via `pkexec`, volatile across reboot): `ptrace_scope=0`,
`route_localnet=1`, iptables DNAT `159.153.51.20→127.0.0.1:42127`, `/etc/hosts easw.easports.com`.
## Development commands (verified)
**FIFA 17 emulation** (from `fifa17-recon/tools/`):
- Start everything (idempotent; re-run after reboot): `./openfut-fut.sh start`
- Status / stop / restart: `./openfut-fut.sh status | stop | restart`
- Then launch the game fresh (`~/Desktop/launch-fifa17.sh`) and pick Ultimate Team.
- Logs: `/tmp/{lsx,blaze,roster,utas,autopatch}.log`
- Full procedure + gate-ladder troubleshooting: `fifa17-recon/FUT-RUNBOOK.md`
**OpenFUT Core** (from `openfut-core/`): `cargo run` (creates `openfut.db`) · `cargo test`
(full in-memory integration suite; requires `data/`) · `cargo test <name>` for one ·
`cargo clippy -- -D warnings` · `cargo fmt`. Env: `LISTEN_ADDR` (127.0.0.1:8080), `DATABASE_URL`
(sqlite://openfut.db), `DATA_DIR` (data).
**Other Rust crates** (`openfut-bridge`, `fifa-blaze`, `openfut-launcher`): standard
`cargo run/build/test/clippy/fmt` from within each. `fifa-blaze` is a workspace (`--bin blaze-server`).
**CI:** only `openfut-core` has it (`.gitea/workflows/ci.yml`): `fmt --check`, `clippy -D warnings`,
`build --locked`, `test --locked` on push/PR to main. No CI on the other crates or the recon dir.
There is **no install step, no Docker, no JS/TS frontend, no typecheck** in this repo. Do not invent them.
## Coding conventions
- **Rust (Core):** Axum 0.7 + SQLx 0.7 (SQLite, compile-time-checked queries). Strict layering —
`routes/` (handlers, extract state, call services) → `services/` (own **all** DB access + logic)
→ `models/` (pure `Serde`/`FromRow` data). Errors via `AppError` (`src/error.rs`) with
`IntoResponse`. One file per domain across `routes/`, `services/`, `models/`. **Single-profile
design:** every service reads "the active profile" as the first DB row — intentional, don't
parameterize it. Content is data-driven: JSON under `data/` loaded at startup into Arc registries
in `AppState`. Add content by dropping JSON files, not code. Migrations are numbered SQL in
`migrations/`. Keep `clippy -D warnings` and `fmt` clean (CI enforces).
- **Python (recon):** stdlib-only servers, no framework. Each responder is a standalone script with
the reverse-engineered contract documented in its module docstring (byte offsets, VAs, symbol
names). When changing a responder, preserve byte-exactness — the client is the oracle.
- **Clean-room, always.** Every finding derives from binaries we own + live observation. **Never**
use, reference, or reproduce leaked EA source. If a task seems to need it, stop and say so.
## AI-agent rules
1. Read this file before exploring the repo.
2. Read the vault file relevant to the task (`../OpenFUT-Vault/`), not the whole tree. Repo
`docs/` files are mirrors of the vault — consult them for the same content, but treat the
vault as canonical.
3. Don't scan the whole repository unless the knowledge base is clearly stale — if you find it
stale, update the vault, then its repo `docs/` mirror.
4. Search the specific directory (`fifa17-recon/`, `openfut-core/src/<layer>/`) before a repo-wide search.
5. Update the vault when architecture materially changes (and sync the matching `docs/` mirror).
6. Don't refactor or rewrite unrelated working code.
7. Prefer small, testable changes; run the narrowest relevant test first (`cargo test <name>`).
8. **Never invent EA/FIFA/Blaze protocol behavior.** Values you don't know are `TODO/CONFIRM`, not
confident guesses. The live client is the only oracle for whether a gate is satisfied.
9. Clearly separate discovered behavior from hypotheses; record findings in
`../OpenFUT-Vault/02 Reverse Engineering/FIFA 17/Protocol Findings.md` under the right confidence
tier — never silently promote a hypothesis to a fact.
10. Root `README.md` / `CLAUDE.md` and `openfut-bridge/CLAUDE.md` describe superseded FIFA 23 plans;
prefer vault + repository evidence over them when they conflict.
## AI Session Bootstrap
Future agents should start with:
1. Read `AGENTS.md`.
2. Read the vault README (`../OpenFUT-Vault/README.md`) to locate the canonical files.
3. Identify the subsystem the task affects and read the corresponding vault file: Architecture,
Project State, Roadmap/Current Priorities, or Protocol Findings.
4. Inspect only the relevant source directories.
5. Check `../OpenFUT-Vault/02 Reverse Engineering/FIFA 17/Protocol Findings.md` before assuming
anything about FIFA/EA behavior.
6. Check `../OpenFUT-Vault/06 Agent Memory/Project State.md` before assuming a feature exists.
7. Implement the smallest coherent change.
8. Run the narrowest relevant tests.
9. Update the vault (and its repo `docs/` mirror) only if the change makes existing knowledge
inaccurate.
Do not reread the entire repository during every session.
## OpenFUT Knowledge Base
**The OpenFUT Vault is the canonical project knowledge base.** Repo `docs/` files mirror it; the
vault wins on any disagreement. Consult it before starting substantial work and update it after
durable discoveries.
Vault location: `../OpenFUT-Vault/` — start at `../OpenFUT-Vault/README.md`.
Canonical files:
- Dashboard: `00 Dashboard/OpenFUT.md`
- Architecture: `01 Architecture/Architecture.md` (repo mirror `docs/ARCHITECTURE.md`)
- RE findings: `02 Reverse Engineering/FIFA 17/Protocol Findings.md`
(repo mirror `docs/research/KNOWN_FINDINGS.md`)
- Direction history: `04 Decisions/Direction History.md`
- Project State: `06 Agent Memory/Project State.md` (repo mirror `docs/PROJECT_STATE.md`)
- Current Priorities: `06 Agent Memory/Current Priorities.md`
- Known Issues: `06 Agent Memory/Known Issues.md`
- Important Discoveries: `06 Agent Memory/Important Discoveries.md`
- Roadmap: `08 Roadmap/Roadmap.md` (repo mirror `docs/ROADMAP.md`)
When editing knowledge that exists in both places, edit the vault first, then update the matching
`docs/` mirror so they stay in sync.
-219
View File
@@ -1,219 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
> ⚠️ **Stale (FIFA 23).** This file's status and targets predate the FIFA 17 pivot. Prefer [`docs/PROJECT_STATE.md`](./docs/PROJECT_STATE.md) (canonical). The working target is **FIFA 17**; the canonical server is `fifa17-recon/docker/fifa17-python` (`docker compose up -d`). `openfut-bridge` (FIFA 23) is superseded; `openfut-core` remains the shared backend.
## Repository Layout
This is a monorepo containing three independent Rust crates as git submodules:
| Submodule | Role |
|---|---|
| `openfut-core/` | Game-independent offline FUT backend (Axum + SQLite) |
| `openfut-bridge/` | FIFA 23 integration layer and reverse-engineering proxy |
| `openfut-launcher/` | Native GUI launcher (egui/eframe) for starting/stopping services and managing setup |
Each submodule has its own `Cargo.toml`, `src/`, `tests/`, and `target/`. Commands must be run from within the submodule directory or with `--manifest-path`.
## Common Commands
All commands run from within the relevant submodule directory.
### openfut-core
```bash
# Run (dev mode; creates openfut.db in current dir)
cargo run
# Run (release)
cargo build --release && ./target/release/openfut-core
# Test (full integration suite against in-memory SQLite)
cargo test
# Run a single test
cargo test test_health_endpoint
# Lint
cargo clippy -- -D warnings
# Format
cargo fmt
```
### openfut-bridge
```bash
# Run (Core must be running first on port 8080)
cargo run
# Test
cargo test
# Run a single test
cargo test test_bridge_health_endpoint
# Lint / format same as core
cargo clippy -- -D warnings
cargo fmt
```
### openfut-launcher
```bash
# Run (native GUI window)
cargo run
# Build release
cargo build --release
# Build the hook DLL (Windows cross-compile, required for FIFA 23 integration)
cd openfut-hook
cargo build --release --target x86_64-pc-windows-gnu
```
### Full-stack via setup.sh (Linux, from repo root)
```bash
./setup.sh quickstart # build + start + hosts + NAT + TLS cert (first-time)
./setup.sh start # start both services in background
./setup.sh stop # stop both + clean up hosts/NAT
./setup.sh status # show running state
./setup.sh logs # tail both logs
./setup.sh watch-domains # find unknown EA domains hitting the bridge
```
### Environment variables
**Core** (`openfut-core/`):
| Variable | Default |
|---|---|
| `LISTEN_ADDR` | `127.0.0.1:8080` |
| `DATABASE_URL` | `sqlite://openfut.db` |
| `DATA_DIR` | `data` |
**Bridge** (`openfut-bridge/`):
| Variable | Default |
|---|---|
| `BRIDGE_LISTEN_ADDR` | `127.0.0.1:8443` |
| `CORE_URL` | `http://127.0.0.1:8080` |
| `CAPTURES_DIR` | `captures` |
| `PLACEHOLDER_MODE` | `true` |
| `TLS_ENABLED` | `true` |
## Architecture
```
FIFA 23 client
│
▼
openfut-bridge (port 8443)
│
├── Known route → openfut-core (port 8080)
└── Unknown route → placeholder JSON + saved to captures/
│
SQLite database
│
data/ (JSON)
```
**Core** has zero knowledge of FIFA 23. It exposes a clean REST API and stores everything in SQLite. **Bridge** has zero game logic — it only translates FIFA 23's wire protocol into Core API calls.
## openfut-core internals
**Module map:**
| Path | Purpose |
|---|---|
| `src/main.rs` | Entry point: tracing, config, pool, migrations, seed, serve |
| `src/lib.rs` | `build_app(pool, data_dir)` — used by integration tests |
| `src/app.rs` | Router construction, `AppState` definition |
| `src/config.rs` | `Config` struct from env vars |
| `src/db.rs` | Pool init + migration runner |
| `src/error.rs` | `AppError` enum + `IntoResponse` impl |
| `src/models/` | Pure data types (`Serde` + SQLx `FromRow`) |
| `src/services/` | Business logic; all DB access lives here |
| `src/routes/` | Axum handler functions; one file per domain |
| `src/seed/` | First-run starter pack grant |
| `src/modding/` | Generic JSON directory loader |
| `data/` | Moddable JSON content: cards, packs, objectives, SBCs, events |
| `migrations/` | SQLx SQL migrations (numbered sequentially) |
**`AppState`** is cloned into every handler via `State<AppState>`. It holds the SQLite pool and Arc-wrapped in-memory registries loaded at startup from `data/` (`CardDb`, `Vec<PackDefinition>`, etc.).
**Layer discipline:** routes extract state and call services; services own all DB access and data-loading logic; models are pure data.
**Single-profile design:** Only one profile per database. All services fetch "the active profile" by selecting the first row — this is intentional.
## openfut-bridge internals
**Module map:**
| Path | Purpose |
|---|---|
| `src/main.rs` | Entry point: config, TLS setup, serve |
| `src/lib.rs` | Library root — re-exports modules |
| `src/config.rs` | `Config` struct |
| `src/proxy.rs` | `catch_all_handler` — the central routing brain |
| `src/mapper.rs` | `map_to_core(method, path)` — FIFA 23 → Core path translation |
| `src/capture.rs` | `CapturedRequest` struct + disk serialization |
| `src/shaper.rs` | Response body transformation (Core → FIFA 23 wire format) |
| `src/tls.rs` | Self-signed cert generation + rustls acceptor |
| `src/routes/` | Bridge admin endpoints (`/_bridge/*`) |
| `captures/` | JSON files written for every intercepted request |
**Request flow:** all traffic hits `catch_all_handler` → `mapper::map_to_core()` → if known, proxy to Core; if unknown, return placeholder JSON and write to `captures/`.
**Adding a new FIFA 23 endpoint:**
1. Capture it in `captures/` or `/_bridge/unknown`
2. Document it in `docs/endpoint-map.md`
3. Add a mapping in `src/mapper.rs` (`EXACT` array or `prefix_routes()`)
4. Implement the handler in Core if needed
## openfut-launcher internals
A native desktop GUI (egui/eframe) that wraps Core and Bridge as managed child processes. It is the recommended way to run OpenFUT on a desktop — no terminal or `setup.sh` required.
**Module map:**
| Path | Purpose |
|---|---|
| `src/main.rs` | Entry point: eframe window setup |
| `src/app.rs` | `LauncherApp` — main UI state + four tabs (Dashboard, Logs, Setup, Config) |
| `src/config.rs` | `LauncherConfig` — persisted settings (binary paths, ports, game dir) |
| `src/process.rs` | `ServiceHandle` — spawns/kills Core and Bridge child processes, tracks status |
| `src/logs.rs` | `LogBuffer` — ring buffer collecting stdout/stderr from child processes |
| `src/setup.rs` | Hook DLL deployment, TLS cert installation into Wine/Proton cert store |
| `openfut-hook/` | Windows DLL (`version.dll`) injected into FIFA 23 via Proton to redirect EA hostnames to the local bridge (cross-compiled with `x86_64-pc-windows-gnu`) |
**Setup flow the launcher automates:**
1. Deploy `openfut_hook.dll` → FIFA 23 game dir as `version.dll` (intercepts network calls inside Wine/Proton, no `/etc/hosts` changes needed)
2. Configure redirect IP written into `openfut.cfg` alongside the DLL
3. Install bridge's self-signed TLS cert into the Wine/Proton cert store
4. Start Core then Bridge (Dashboard tab shows live status)
## Testing approach
**Core** uses a single `tests/integration_test.rs` that spins up a full Axum app against an in-memory SQLite database (`build_app(pool, "data")`). Tests use raw HTTP via `tower::ServiceExt::oneshot`. The `data/` directory is always required at test time (tests run from `openfut-core/`).
**Bridge** tests are in `tests/proxy_test.rs`. They build a bridge app in `placeholder_mode: true` pointing at a dummy Core URL — no live Core required.
## Modding / data files
All game content lives in `openfut-core/data/`. Files are JSON arrays loaded at startup. To add content, drop a JSON file into the right subdirectory and restart Core:
```
data/cards/ ← CardDefinition[]
data/packs/ ← PackDefinition[]
data/objectives/ ← ObjectiveDefinition[]
data/sbcs/ ← SbcDefinition[]
data/events/ ← EventDefinition[]
data/achievements/← AchievementDefinition[]
```
## Version control
All three submodules (`openfut-core`, `openfut-bridge`, `openfut-launcher`) have their own independent git history. Use `tea` (Gitea CLI) for remote operations, not `gh`.
Generated
+228 -2475
View File
File diff suppressed because it is too large Load Diff
+14 -31
View File
@@ -1,31 +1,14 @@
[workspace]
resolver = "2"
members = [
"openfut-core",
"openfut-protocol-blaze",
"openfut-adapter-fifa17",
"openfut-blaze-host",
"openfut-host-config",
"openfut-http",
"openfut-tls",
"openfut-redirector-host",
"openfut-roster-host",
"openfut-utas-host",
"openfut-identity",
"openfut-import-fifa17",
"openfut-bridge",
"openfut-launcher",
# The two companion services the launcher used to shell out to Python for.
"openfut-lsx",
"openfut-autopatch",
"fifa-blaze/crates/blaze-proto",
"fifa-blaze/crates/server",
]
# openfut-hook is a Windows-only version.dll proxy injected into the FIFA client.
# It MUST build with its own [profile.release] (panic="abort" — unwinding across
# the DllMain/FFI boundary into the game process is UB — plus strip + opt-level="s").
# Cargo ignores a non-root member's profile and forbids per-package `panic` overrides,
# so the hook is deliberately EXCLUDED from this workspace to build as its own root
# (this also lands its artifact in openfut-hook/target/, matching the launcher's
# config.rs default hook_dll_path). Build: cargo build --release --target x86_64-pc-windows-gnu.
exclude = ["openfut-launcher/openfut-hook"]
[package]
name = "openfut-launcher"
version = "0.1.0"
edition = "2021"
[dependencies]
eframe = "0.29"
egui = "0.29"
tokio = { version = "1", features = ["full"] }
anyhow = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
dirs = "5"
chrono = { version = "0.4", features = ["serde"] }
-265
View File
@@ -1,265 +0,0 @@
# OpenFUT — project handoff
Self-contained briefing for an assistant with **no access to this repo or machine**.
Everything needed to understand the project and reason about its open problems is here.
---
## 1. What this is
**OpenFUT** is a clean-room, fully offline re-implementation of the server backend for
**FIFA 17 Ultimate Team (FUT)**. EA's servers for FIFA 17 are long dead. The goal is to
make the retail game's FUT mode fully playable again — open packs, build squads, use the
transfer market, play matches and earn rewards — by emulating every server the client
talks to, on localhost.
Nothing is decompiled *into* the project. The game's binaries are read to learn the
**wire format** (which JSON keys, of which types, each response must contain), and the
servers are written from scratch in Python against that spec.
The client is unmodified retail FIFA 17 running under Wine/Proton on Linux.
---
## 2. Architecture — four independent servers
FIFA 17 does not talk to one backend. It talks to four, on different protocols, and all
four must be satisfied in sequence before FUT loads.
```
FIFA 17 (Wine/Proton)
│
├─ LSX / Origin :4216 XML over TCP. Local Origin client emulation.
│ Login, entitlements, persona.
├─ Blaze :42127 redirector (TLS) → :42130 game server, :42131 nucleus
│ EA's binary "Fire2/TDF" RPC protocol. Session, auth,
│ and — critically — the CLIENT-CONFIG STORE.
├─ UTAS / RS4 :8099 The FUT REST API. JSON over HTTP. ~45 endpoints.
│ Club, squads, packs, market, matches. The bulk of it.
└─ POW / EASFC :8094 (+ :8080 content) A third HTTP API, discovered late.
Online status bar, level, EASFC credits, catalogue.
```
Plus two helpers: a **roster** server (:8081) serving a roster-update XML the FUT
loading screen blocks on, and **autopatch**, which patches the running process's
ProtoSSL certificate verification so the client accepts our self-signed TLS.
### How the client is redirected
Three mechanisms, in decreasing order of preference:
1. **Blaze client-config keys** — the cleanest. Blaze serves a key/value config store
and the client reads its own service URLs from it. `FUT_RS4_APIURL_<MODULE>` and
`FUT_RS4_URL_<CALL>` point the FUT API at `127.0.0.1:8099`; `FIFA_POW_URL` points
the EASFC layer at `127.0.0.1:8094`. **No root, no DNS games.**
2. **`/etc/hosts`** — for hosts baked into the binary (`easw.easports.com`,
`gosredirector.ea.com`).
3. **iptables DNAT** — for a hardcoded IP (`159.153.51.20` → the Blaze redirector).
---
## 3. The wire format, and why it is unforgiving
FUT responses are JSON, but the client does **not** use a general JSON object model. Each
response class has a hand-written SAX-style deserializer that walks tokens and dispatches
on a **hashed key id** (an "atom"). This has three consequences that dominate the project:
**Atoms.** Every JSON key name maps to a 16-bit atom id via FNV-1a. There is a recovered
table of ~900 (id → name). A response is really "which atoms does deserializer X read,
and of what type".
**Type fidelity is fatal.** Feeding a scalar where the parser expects an object or array
does not error — it **desyncs the token reader and the game hard-freezes** in a busy loop
at `0x1801c7f1a`. This is the single most common way to break the game, and it has bitten
this project repeatedly. Arrays must be arrays; nested objects must be objects.
**Unknown keys are usually skipped safely** — most deserializers route an unrecognised
atom to a value-skip handler (`FUN_180135ff0`), so extra fields are inert. This document
previously named `FutMoveCard` (`0x180128600`) as an exception with no skip handler at
all. **That was wrong**, and the retraction is in §5a: it has two skip-handler call sites
and parses seven atoms. No deserializer in this project is currently known to lack one.
Treat any future "this class has no skip handler" claim as unproven until the search is
shown to have covered the whole function.
### Working method
For any endpoint: find the response class's deserializer, extract the atom ids it
compares against, map them to names, note the getter used for each (int / string / bool /
nested), and build the minimal body. Omit nested members unless their shape is known —
omission is skip-safe, a wrong shape freezes the game.
---
## 4. What works today (live-verified)
| Area | Status |
|---|---|
| Boot to the FUT hub | ✅ |
| Club identity, coins, W/D/L record | ✅ |
| Active squad — renders 11 real players, chemistry links | ✅ |
| Squad building — `PUT /squad/<id>` fires, persists across relaunch | ✅ |
| Squad roster ("MY SQUADS") | ✅ |
| Transfer market — browse, bid, buy-now, sell, watchlist | ✅ |
| Packs — buy, reveal, Send to Club | ✅ (the workaround is retired, see §5a) |
| Quick sell — destroys cards, credits coins | ✅ |
| Match loop — create/ready/play/destroy + coin rewards | ✅ implemented, **never played in-game** |
| Online/EASFC status bar (no "servers unreachable") | ✅ when enabled |
| Seasons / tournaments / leaderboards / champions | ⚠️ routed with reversed schemas, never live-tested |
Current save state: 99 club items, 8,400 coins, 0-0-0 record.
**Design convention:** every risky change ships behind an environment flag, default set
to whatever is live-proven (`FUT_MASSINFO`, `FUT_USERINFO`, `FUT_MODES`,
`FUT_PACK_AUTOCLUB`, `FUT_POW`, `FUT_STORE_GROUPS`, …). This exists because two working
screens were broken by shipping "corrections" on by default.
---
## 5. Open problems
### 5a. "Send to Club" kills the FUT session — SOLVED 2026-08-04
Opening a pack shows the cards correctly; choosing **Send to Club** used to produce
*"there has been an error connecting to FIFA 17 Ultimate Team"* and a logout, seven
attempts running. The cards always moved server-side; only the acknowledgement was
rejected.
The cause was the response body. `PUT ut/%s/item` returns per-item **verdict** records,
not an acknowledgement, and the completion handler raises
`EVENT_CARDS_MOVE_CARD_FAILURE` when the record vector is empty or when `success != 1`.
Every body the project returned, `{}` included, reported the move as failed. The fix is
the real shape:
```json
{"itemData":[{"id":100000125,"pile":"club","success":true}, ...]}
```
Live: five cards to the club, session survived, cards persisted, no `ut/delete/auth`.
The autoclub workaround is retired.
Two corrections this closed, both worth carrying forward:
- The repo's claim that this deserializer had **no skip handler** and parsed only two
keys was false. It came from searching a truncated decompile. It implied the body
could not be at fault, which is what sent seven attempts after client-side state.
Never conclude an absence from a truncated or unverified-length extraction.
- The quick-sell asymmetry was not evidence of client state. Quick sell's callbacks
read only the transport status code and never touch the body.
### 5b. "MY CLUB" counter always reads 0 — UNSOLVED
The hub tab bar shows `MY CLUB 0` despite the club holding 99 items.
**Eliminated by live test:**
- **Not the item list** — the user opened MY CLUB, the client fetched the club and
**displayed all 99 players correctly**, and the counter still read 0.
- **Not `pileSizeClientData`** — the massinfo member that carries pile sizes as
`{"entries":[{"key":int,"value":int}]}`. A probe sent 16 entries with uniquely
identifiable values; the counter stayed 0.
- **Not lazy loading** — the club endpoint was fetched 6 times that session.
**Unexplored contrast:** the `ACTIVE SQUAD` tab in the same bar correctly shows `11/23`.
So some counters work. Whatever differs between that one and the club one is likely the
answer.
### 5c. Store tiles render "unknown" — DIAGNOSED, NOT FIXED
Pack tiles show `unknown` with zero item counts. The `"unknown"` string is an
unconditional **default** in a string constructor — the field simply never gets written.
The store renders *display groups*, and `displayGroup` is parsed **recursively by the same
element parser**. Sending it populated **froze the store** (the type-desync busy loop), so
it is behind a flag, default off. Doing it properly needs the group's own field set worked
out rather than a self-referential copy of the pack.
### 5d. Seasons and Draft refuse — UNSOLVED, and not obviously server-side
Selecting **single-player Seasons** raises *"There was a problem communicating with the
FIFA Ultimate Team servers"* while making **zero requests to any layer**. UTAS, Blaze and
POW logs show only pings and one census subscription across the whole failure window. No
response can be wrong because no request was made. POW is eliminated (same failure with it
enabled and disabled).
**Online Draft** hangs the client rather than crashing it (process alive, no dump). The
one suspicious thing on the wire is `GET ut/%s/squad/mode/draft/state`, which our generic
`/squad` route answers with a full active-squad object: 23 slots, nested `itemData`, a
33-integer formation string. The real class wants `roundsInfo` plus a state enum, so this
is a textbook type-desync candidate and the timing matches. **Nothing has isolated it**;
it is a suspect, not a cause.
Both matter beyond themselves, because they are the only two routes into a match, and the
`/match` request shape has therefore never been captured.
---
## 6. Notable reverse-engineering findings
- **Class → deserializer resolution.** A response class's name literal is preceded by a
**4-byte header**, and the constructing factory's `lea` points at *the header*, not the
text. Lookups must use `name_address - 4`. Six attempts failed on this off-by-four;
four of them returned zero results and nearly got recorded as "this class has no
deserializer".
- **The request-template table is a floor, not a ceiling.** Several real endpoints are
built by the caller appending a suffix and therefore never appear in the binary's URL
table: `squad/list`, `user/club`, `club/stats/*`, `clientdata/<key>`. Only live traffic
reveals them. This has caught the project three separate times.
- **The documentation lies.** The project's own `ENDPOINT_MAP.md` (~1,360 lines, ~100
reversed structs) has been wrong repeatedly: it claimed `FutMoveCard` parses
`chemistry` (it does not); it called seven store pack fields "skipped no-ops" (all are
parsed); it gave price-object keys as `amount`/`currency` (the parsers read
`externalPriceId`). **Verify against the decompiler before relying on any row.**
- **The online layer was hiding in an unpacked DLL.** "EA FC servers are unreachable"
comes from a third HTTP API implemented in a *loose, unpacked, string-rich* library —
not the packed executable, and not any layer previously emulated. It is redirectable
purely through the Blaze config store.
- **The main executable is Denuvo-packed.** Its code exists only in a live process. Live
memory is readable via `/proc/PID/mem` (the PE is mapped flat), which is how a crash
site was disassembled. Any logic living there cannot be reversed statically.
---
## 7. Tooling built
- A **PyGhidra harness** with helpers for decompiling, xrefs, vtables, byte scanning and
class→deserializer resolution. (Ghidra's Java/OSGi scripting is broken on this machine;
PyGhidra bypasses it entirely.)
- A **minidump reader** — exception record, fault-time registers, module map, and a stack
walk that recovers a usable backtrace.
- A **live code grabber** that reads and disassembles unpacked code out of a running
process.
- A **read-only live probe** pattern for polling client model state while playing.
- **Two test suites**: 380 live contract checks (freeze-safety: asserts every response
field's type against the reversed schema) and 51 pure unit checks for match rewards.
- A **traffic-replay audit** that diffs current responses against a known-good session —
this is what proves a change did not alter what the client sees.
---
## 8. Documentation in-repo
| File | Contents |
|---|---|
| `ENDPOINT_MAP.md` | ~100 reversed response structs, atoms, types, freeze risks |
| `FUT_RESPONSE_REBUILD_PLAN.md` | Squad family, massinfo, the service-layer call graph |
| `REBUILD_RESEARCH.md` | Complete API surface, gap analysis, POW layer, and every eliminated hypothesis with its evidence |
| `CARD_SYSTEM.md` | How card identity resolves locally from the game's own database |
| `REPACK_INTEL.md` | Origin/LSX emulation notes |
---
## 9. Where help would be most valuable
1. **The MY CLUB counter (§5b).** Given the client demonstrably *has* the items and
*renders* them, what else could a tab counter read from? Note that a sibling counter in
the same bar works correctly.
2. **Seasons refusing with zero requests to any server (§5d).** The client raises a
"problem communicating with the FIFA Ultimate Team servers" without contacting
anything. Nothing on the wire can be wrong because nothing went on the wire.
3. **Whether the remaining problems are fixable server-side at all**, or whether the
deciding logic lives in the Denuvo-packed executable and only live instrumentation can
settle it. Note that this question was asked about `Send to Club` too, and there the
answer turned out to be a plain wire fix, so treat "it must be client-side" as a
hypothesis needing evidence rather than a fallback explanation.
Useful framing: this project's failures have almost always come from proposing a fix
before testing the assumption under it. Hypotheses that come with a cheap way to
disconfirm them are worth far more than plausible ones.
-313
View File
@@ -1,313 +0,0 @@
# OpenFUT — Project Report
**Goal:** make FIFA 17 Ultimate Team fully playable offline, forever, by re-implementing
every server the game talks to.
**Status:** FUT boots, loads, and is playable. Packs, squads, the transfer market, coins
and progression all work. Two cosmetic/flow problems remain open.
**Timeline:** 2026-06-25 → 2026-08-04 · 44 commits · ~12,900 lines of Python across 39
tools · ~3,600 lines of reverse-engineering documentation.
---
## 1. What the project is
EA shut down FIFA 17's servers years ago, which kills Ultimate Team — the mode is entirely
server-driven. Your club, squads, packs, market and progression all live server-side, so
without a backend the mode is dead even though the game still installs and runs.
OpenFUT replaces that backend with local servers. The game is **unmodified retail
FIFA 17** running under Wine/Proton on Linux; nothing is patched into the game except a
single runtime tweak so it accepts our TLS certificate.
This is **clean-room work**. No EA code is copied or redistributed. The game's own
binaries are read to learn the *wire format* — which JSON keys, of which types, each
response must carry — and the servers are written from scratch against that specification.
---
## 2. Project history
The project changed target twice before finding its footing. That arc matters, because
each pivot was driven by hitting a hard wall.
**Phase 1 — FIFA 23 (June 2026).** Began as an offline FUT backend for FIFA 23: a Rust
core (`openfut-core`, Axum + SQLite), a protocol bridge (`openfut-bridge`), and a GUI
launcher. All three built and passed tests. The architecture was sound but the client
never got far enough to exercise it.
**Phase 2 — the FIFA 23 wall.** FIFA 23 refused to go online at all. Extensive reverse
engineering of the connection state machine, live-memory probing, and forcing the
"go online" gate directly all failed — the client's internal coherence checks were the
wall, not any single flag. Documented as a dead end rather than fought.
**Phase 3 — the FIFA 17 pivot (late July).** FIFA 17 turned out to be a far better target:
its network library is **unprotected and fully symboled**, exposing 979 RPC names. The
insight was to crack FIFA 17 first and port the understanding back.
That worked, quickly:
- **TLS pinning defeated** — the client's certificate verification is patched at runtime
in memory, so a self-signed cert is accepted.
- **Origin/LSX emulation** — the local Origin client protocol was reverse engineered,
including the repack's own crypto layer, beating "log in to Origin" and
"title version outdated".
- **Blaze cracked end to end** — EA's binary RPC protocol: redirector, second-hop
handshake, and the encoded pre-auth exchange. This was the big one.
- **Full FUT API mapped** — ~100 response structures reverse engineered to field level.
**Phase 4 — building the FUT backend (August).** With the protocol understood, the work
became making FUT actually *play*: card rendering, packs, the store, the transfer market,
squads, and match rewards. This is where the project stands.
---
## 3. Architecture
FIFA 17 does not talk to one backend. It talks to **four**, on different protocols, and
all four must be satisfied in sequence before FUT loads.
```
FIFA 17 (Wine/Proton)
│
├─ LSX / Origin :4216 XML/TCP — local Origin client emulation
│ login, entitlements, persona
├─ Blaze :42127 redirector (TLS) → :42130 game, :42131 nucleus
│ EA's binary Fire2/TDF RPC
│ session, auth, and the CLIENT-CONFIG STORE
├─ UTAS / RS4 :8099 the FUT REST API — JSON/HTTP, ~45 endpoints
│ club, squads, packs, market, matches
└─ POW / EASFC :8094 a third HTTP API (+ :8080 content)
online status, level, credits, catalogue
```
Plus **roster** (:8081), serving an XML file the FUT loading screen blocks on, and
**autopatch**, which patches certificate verification in the running process.
### Redirection, in order of preference
1. **Blaze client-config keys** — the client reads its own service URLs from a key/value
store that Blaze serves. Pointing FUT and EASFC at localhost needs **no root and no
DNS manipulation**. This is the clean mechanism and most redirection uses it.
2. **`/etc/hosts`** — for hostnames baked into the binary.
3. **iptables DNAT** — for one hardcoded IP address.
---
## 4. The wire format — and why it is unforgiving
FUT responses are JSON, but the client does not use a general JSON object model. Each
response class has a hand-written SAX-style deserializer that walks tokens and dispatches
on a **hashed key id** ("atom"). Three consequences dominate the project:
**Atoms.** Every JSON key maps to a 16-bit id via FNV-1a. A recovered table of ~900
id→name pairs is the Rosetta stone. A response spec is really "which atoms does this
deserializer read, of what type".
**Type fidelity is fatal.** A scalar where an object or array is expected does not error —
it **desyncs the reader and hard-freezes the game** in a busy loop. This is the primary
failure mode of the entire project.
**Unknown keys are usually skipped — but not always.** Most deserializers route
unrecognised atoms to a skip handler, making extra fields inert. At least one does not,
so any unexpected key desyncs it.
**Working method:** locate the deserializer, extract its atom set and per-atom getter
types, build the minimal body, and omit nested members whose shape isn't known — omission
is safe, a wrong shape freezes the game.
---
## 5. What works
| Capability | State |
|---|---|
| Boot: Origin → Blaze → FUT hub | ✅ |
| Club identity, coins, W/D/L record | ✅ |
| Active squad — 11 real players, ratings, chemistry | ✅ |
| Squad building — saves and survives relaunch | ✅ |
| Squad roster ("MY SQUADS") | ✅ |
| Transfer market — browse, bid, buy-now, list, watchlist | ✅ |
| Store — buy packs | ✅ |
| Packs — cards land in the club | ✅ via workaround (§6a) |
| Quick sell — credits coins | ✅ |
| Match loop — create/ready/play/destroy + rewards | ⚠️ built, **never requested by the client** (see below) |
| Online/EASFC status bar | ✅ when enabled |
| Seasons, tournaments, leaderboards, champions | ⚠️ routed, **never requested by the client** (see below) |
| Card identity (names, faces, ratings) | ✅ resolves from the game's own local database |
### "Untested" is two different things, and the difference matters
The server log records the User-Agent of every request. The real client identifies as
`ProtoHttp`; this project's own curl and Python probes do not. Separating them shows that
several endpoints previously filed as "built but untested" have in fact **never been
requested by the game at all**, and everything recorded against them was self-inflicted
traffic:
| endpoint | client requests | project probes |
|---|---|---|
| `/leaderboards/options` | 5 | 1 |
| `/clientdata/userHubData` | 13 | 2 |
| `/user/accountinfo` | 23 | 49 |
| `/season`, `/season/user` | **0** | 2 |
| `/tournament`, `/tournament/user` | **0** | 3 |
| `/leaderboards` (bare) | **0** | 2 |
| `/champion` | **0** | 2 |
| `/match` | **0** | 2 |
| `/clubUser` | **0** | 93 |
| `/user/list` | **0** | 180 |
| `/sbs` (SBC), `/draft/mode` | **0** | 0 |
`/clubUser` and `/user/list` are the starkest: 273 requests between them, none from the
game. Work was done on both on the assumption the client wanted them.
A zero in the client column does **not** mean the client never wants that endpoint. In
most cases it means **nobody has navigated to that part of the game yet**. It does mean no
claim about those endpoints has been tested against the client, and any analysis that does
not apply this filter is misleading by default.
**Requirement:** every capture and analysis tool in this project should apply the
User-Agent split by default rather than as an afterthought.
**Design convention.** Every risky change ships behind an environment flag whose default
is whatever is live-proven. This exists because shipping "corrections" on by default broke
two working screens — once freezing the store outright.
---
## 6. Open problems
### 6a. "Send to Club" ends the FUT session — SOLVED 2026-08-04
Opening a pack displayed the cards correctly, but choosing **Send to Club** produced
*"there has been an error connecting to FIFA 17 Ultimate Team"* and a logout, seven
attempts running. The cards always moved correctly server-side; only the
acknowledgement was rejected.
**It was the response body all along.** `PUT ut/%s/item` does not parse an
acknowledgement, it builds per-item **verdict** records, and the completion handler
raises `EVENT_CARDS_MOVE_CARD_FAILURE` when the record vector is empty or when
`success != 1`. Every body this project returned, `{}` included, therefore told the
client the move had failed, and the client ended the FUT session because that is what
that event does. Serving the real shape fixed it in one launch:
```json
{"itemData":[{"id":100000125,"pile":"club","success":true}, ...]}
```
Live result: five cards sent to the club, session survived, cards persisted, no
`ut/delete/auth` logout. Both flags are now defaults and the autoclub workaround is
retired.
**Why it took seven attempts,** which is the part worth keeping: the project had
recorded that this deserializer had *no skip handler* and parsed only two keys. That
was false, produced by searching a **truncated** decompile (the first 4,000 characters
of a 6,193-character function). It implied "the body cannot be the problem", which is
what redirected the investigation to client-side state. The quick-sell asymmetry that
seemed to confirm it has a mundane explanation: quick sell's callbacks read only the
transport status code and never touch the body, so its tolerance of `{}` said nothing
about this endpoint.
The general lesson, now a standing rule: **never conclude an absence from a truncated
or unverified-length extraction**, and treat every negative claim in the endpoint docs
as weaker than the corresponding positive one.
### 6b. "MY CLUB" counter reads 0
The hub shows `MY CLUB 0` despite 99 items. Not the item list (the client *displays* all
99), not the pile-size data (a 16-entry probe changed nothing), not lazy loading (fetched
6 times). Unexplored: the neighbouring `ACTIVE SQUAD` counter works correctly — the
difference between them is likely the answer.
### 6c. Store tiles read "unknown"
`"unknown"` is an unconditional default in a string constructor — the field is never
written. The store renders *display groups*, and that member is parsed recursively by the
same parser; sending it populated **froze the store**, so it is flagged off pending a
correct group schema.
### 6d. Large parts of the game have never been opened
Distinct from 6a to 6c, which are things that misbehave. Per the User-Agent table in
section 5, entire modes have never issued a single client request: Seasons, Tournaments,
FUT Champions, Draft, SBC, and the match loop itself. Their endpoints are routed and their
schemas are reversed, but no claim about any of them has been tested against the game.
This is not a bug list. It is unmeasured surface, and it is the cheapest information
available to the project because most of it costs nothing but navigating menus. It is
recorded here because "routed from a reversed schema" reads like a stronger claim than it
is, and section 7 warns that this project's notes have described things differently from
what is true.
*A multi-agent investigation into 6a and 6b is currently running.*
---
## 7. Notable findings
- **Class → deserializer resolution.** A response class's name literal is preceded by a
4-byte header and the factory points at *the header*. Six attempts failed on that
off-by-four; four returned nothing and were nearly recorded as "no deserializer exists".
- **The URL table is a floor, not a ceiling.** Several real endpoints are built by
appending a suffix at the call site and never appear in the binary's template table.
Only live traffic reveals them — this caught the project three separate times.
- **The project's own documentation has been wrong repeatedly** — fields described as
inert turned out to be parsed, and documented key names didn't match the parsers.
Verify against the decompiler, not the notes.
- **The online layer was hiding in plain sight.** "EA FC servers unreachable" comes from a
third HTTP API in a *loose, unpacked, string-rich* library — not the protected
executable, and not any previously emulated layer. Redirectable purely by config.
- **The main executable is Denuvo-packed**, so its code exists only in a live process.
Live memory is readable, which is how a crash site was disassembled — but logic living
there cannot be reverse engineered statically.
---
## 8. Tooling and quality
- **PyGhidra harness** with decompile / xref / vtable / byte-scan / class-resolution
helpers (Ghidra's own Java scripting is broken on this machine).
- **Minidump reader** — exception record, fault-time registers, module map, stack walk.
- **Live code grabber** — reads and disassembles unpacked code from a running process.
- **Read-only live model probes** for watching client state while playing.
- **Test suites:** 380 live contract checks (type/freeze safety per reversed schema) plus
51 pure unit checks. Both green.
- **Traffic-replay audit** — diffs current responses against a known-good session to prove
a change didn't alter what the client sees.
- **~3,600 lines of RE documentation** across six files, including every eliminated
hypothesis with its supporting evidence.
---
## 9. Roadmap
**Immediate (free, no code):** play a match — the reward loop is built and unit-tested but
has never run in-game. Enable the game-mode endpoints and see whether four more modes
light up.
**Near term:** close the two open problems, most likely via live instrumentation rather
than more static analysis. Implement SBC and Draft (schemas already recovered). Fix the
store display groups properly.
**Longer term:** the stated destination is porting this into the Rust `openfut-core`
behind a FIFA-17 bridge. Everything currently lives in Python prototypes; the
documentation is now good enough to write the port against.
---
## 10. Honest assessment
**What went well.** The FIFA 17 pivot was the decisive call — recognising that an
unprotected binary was worth more than persisting against a hardened one. Blaze, Origin
and the FUT API were all cracked end to end. The freeze-safety test suite has repeatedly
caught regressions before they reached the game.
**What went badly.** Progress has been slowest where fixes were proposed before the
assumption under them was tested. Both open problems absorbed many attempts built on
plausible but unverified theories; several were disproved in a single measurement that
could have been taken first. Two working screens were broken by shipping unverified
"corrections" on by default — which is precisely why the flag convention exists now.
**The most reliable technique** has been comparing a working case against a failing one:
diffing live traffic against a known-good session, and contrasting a succeeding endpoint
with its failing sibling. That has produced more answers than any amount of decompilation.
-98
View File
@@ -1,98 +0,0 @@
# OpenFUT
> ⚠️ **Status — see [`docs/PROJECT_STATE.md`](./docs/PROJECT_STATE.md) (canonical).** The working, actively-developed target is **FIFA 17**, not FIFA 23. Everything below this banner describes the **superseded FIFA 23 `bridge` lineage** and is kept for historical context.
>
> **Run the server (canonical):** `cd fifa17-recon/docker/fifa17-python && docker compose up -d` — see [`fifa17-recon/FUT-RUNBOOK.md`](./fifa17-recon/FUT-RUNBOOK.md). `openfut-core` is the shared offline backend (still used by the FIFA 17 path); `openfut-bridge` is the retired FIFA 23 integration.
**Offline Ultimate Team — like SPT, but for FIFA 23.**
OpenFUT replaces EA's retired FUT servers with a fully offline, single-player backend. You own FIFA 23 legitimately. You just want to keep playing after EA shut down the servers.
---
## Repositories
| Repo | Purpose |
|---|---|
| [`openfut-core`](./openfut-core) | Game-independent offline FUT backend |
| [`openfut-bridge`](./openfut-bridge) | FIFA 23 integration layer + reverse-engineering proxy |
---
## Architecture
```
FIFA 23 client
│
▼
┌─────────────────┐
│ openfut-bridge │ ← intercepts FUT traffic, maps routes, logs unknown
└────────┬────────┘
│
▼
┌─────────────────┐
│ openfut-core │ ← offline FUT backend: profiles, packs, squads, SBCs
└─────────────────┘
│
▼
SQLite database
```
**Core** is game-independent. It speaks a clean REST API and knows nothing about FIFA 23 internals.
**Bridge** is FIFA-specific. It speaks FIFA 23's wire protocol and translates it into Core API calls. Bridge is where all reverse engineering work happens.
---
## Current Status
| Feature | Status |
|---|---|
| Local profiles + clubs | ✅ Working |
| Coin system | ✅ Working |
| Pack generator | ✅ Working |
| Card collection | ✅ Working |
| Squad builder | ✅ Working |
| Objectives engine | ✅ Working |
| SBC engine | ✅ Working |
| Match rewards | ✅ Working |
| NPC transfer market | ✅ Working |
| Statistics | ✅ Working |
| FIFA 23 integration | 🔴 Reverse engineering in progress |
| Chemistry calculation | 🟡 In progress |
| Full Draft mode | 🟡 In progress |
| Squad Battles AI generator | 🟡 In progress |
| Objectives claim flow | 🟡 In progress |
---
## Running
```bash
# Start the offline backend
cd openfut-core
cargo run
# Start the proxy (for traffic capture / FIFA integration)
cd openfut-bridge
cargo run
```
Core listens on `http://127.0.0.1:8080` by default.
Bridge listens on `http://127.0.0.1:8443` by default.
---
## Design Principles
- **Offline-first.** No EA account required. No internet connection needed.
- **Single-player only.** This is not a multiplayer server emulator.
- **Data-driven.** All cards, packs, SBCs, and objectives are JSON files. Everything is moddable.
- **Clean architecture.** Core has zero knowledge of FIFA 23. Bridge has zero game logic.
- **No copyrighted assets.** No real player images, no EA trademarks in data files.
---
## Disclaimer
This project is not affiliated with EA Sports. You must own FIFA 23 legitimately to use this software. This project does not bypass any ownership verification and is intended only to restore offline playability of a game whose online services have been retired.
-340
View File
@@ -1,340 +0,0 @@
{
"metadata": {
"reportDate": "2026-07-28",
"codebaseName": "OpenFUT",
"version": "0.1.0",
"submodulesCovered": [
"openfut-core",
"openfut-bridge",
"openfut-launcher"
],
"language": "Rust",
"framework": "Axum + SQLite"
},
"vulnerabilities": [
{
"severity": "critical",
"category": "authentication",
"file": "openfut-core/src/services/profile.rs",
"line": 8,
"cwe": "CWE-287",
"title": "Missing Authentication on All Endpoints",
"description": "No authentication or authorization checks on any API endpoint. The system uses single-profile design with get_active_profile() returning the first row (LIMIT 1) without any token validation, session management, or per-user isolation. In a networked context, any HTTP client can access all endpoints without credentials.",
"impact": "Complete compromise of data confidentiality and integrity. Any attacker can view, modify, or delete all user data without authentication.",
"exploitPath": "curl http://127.0.0.1:8080/clubs - accesses club data without any auth headers or tokens",
"recommendation": "Implement stateless JWT tokens or session-based authentication. Add middleware to validate tokens on all endpoints. Implement per-user authorization checks in services."
},
{
"severity": "critical",
"category": "injection",
"file": "openfut-core/src/routes/auth.rs",
"line": 87,
"cwe": "CWE-89",
"title": "SQL Injection via String Interpolation",
"description": "SQL table names are interpolated using string formatting: sqlx::query(&format!(\"DELETE FROM {table}\")). Although currently hardcoded in a loop, this violates parameterized query principles and creates a risk if the table list ever becomes user-controlled or the pattern is copied elsewhere.",
"impact": "Potential remote code execution via database manipulation. If extended to user input, attackers could modify arbitrary tables or drop the database.",
"exploitPath": "Currently mitigated by hardcoded table names, but the pattern is dangerous and violates secure coding practices.",
"recommendation": "Use SQLx's dynamic query builders or identifier types that properly escape table/column names. Replace format! string interpolation with sqlx::query_builder for dynamic identifiers."
},
{
"severity": "high",
"category": "configuration",
"file": "openfut-bridge/src/proxy.rs",
"line": 44,
"cwe": "CWE-295",
"title": "TLS Certificate Validation Disabled",
"description": "HTTP client explicitly disables TLS certificate validation: .danger_accept_invalid_certs(true). This bypasses all certificate pinning, expiration, and hostname verification, making the bridge vulnerable to man-in-the-middle attacks.",
"impact": "Attacker positioned between bridge and upstream can intercept, modify, or read all traffic. Compromises confidentiality and integrity of requests to Core and external services.",
"exploitPath": "MITM attack between openfut-bridge and openfut-core or upstream services. ARP spoofing on localhost subnet would redirect traffic.",
"recommendation": "Remove .danger_accept_invalid_certs(true) in production. If testing requires it, gate behind a development-only environment variable with strong warning. Use proper certificate management (CA bundles, cert pinning)."
},
{
"severity": "high",
"category": "dos",
"file": "openfut-core/src/services/season.rs",
"line": 23,
"cwe": "CWE-248",
"title": "Unguarded expect() Causes Denial of Service",
"description": "Multiple unchecked expect() calls that will panic and crash the server if database queries fail or return unexpected results: Ok(fetch(pool, profile_id).await?.expect(\"just inserted\"))",
"impact": "Denial of service. A single database inconsistency or race condition crashes the entire server, making the application unavailable.",
"exploitPath": "Trigger race conditions during concurrent requests (e.g., rapid profile deletion + season fetch). Database corruption or migration failure crashes the service immediately.",
"recommendation": "Replace expect() with proper error handling (Result types, error logging, graceful degradation). Handle database query failures without panicking. Add integration tests for race conditions."
},
{
"severity": "high",
"category": "dos",
"file": "openfut-core/src/services/season.rs",
"line": 69,
"cwe": "CWE-248",
"title": "Unguarded expect() in season fetch",
"description": "let season = fetch(pool, profile_id).await?.expect(\"season must exist\"); Panics if season is not found.",
"impact": "Server crash on missing or deleted season records.",
"exploitPath": "Delete a season via concurrent requests, then call /seasons endpoint. Server panics.",
"recommendation": "Return proper error (AppError::NotFound) instead of panicking."
},
{
"severity": "high",
"category": "dos",
"file": "openfut-core/src/services/season.rs",
"line": 144,
"cwe": "CWE-248",
"title": "Unguarded expect() in season update",
"description": "let updated = fetch(pool, profile_id).await?.expect(\"season must exist\");",
"impact": "Server crash on concurrent season modifications.",
"exploitPath": "Rapid concurrent season updates that fail race conditions.",
"recommendation": "Handle missing records gracefully."
},
{
"severity": "high",
"category": "cors",
"file": "openfut-core/src/app.rs",
"line": 257,
"cwe": "CWE-346",
"title": "Permissive CORS Configuration Allows All Origins",
"description": ".layer(CorsLayer::permissive()) enables CORS for all origins (*), methods, and headers. Any website can make cross-origin requests to the API and access/modify data.",
"impact": "Cross-site request forgery (CSRF) attacks. Malicious websites can issue API requests on behalf of users. Data exfiltration via JavaScript from any origin.",
"exploitPath": "Attacker website:\n <img src=\"http://127.0.0.1:8080/clubs\" />\n Fetch API calls to delete profiles, modify squads, etc.",
"recommendation": "Restrict CORS to specific origins (e.g., localhost:3000 for web UI, or the game process if exposed). Use CorsLayer::very_restrictive() as default and explicitly allowlist origins."
},
{
"severity": "high",
"category": "dos",
"file": "openfut-bridge/src/proxy.rs",
"line": 47,
"cwe": "CWE-248",
"title": "HTTP Client Construction Panic",
"description": ".expect(\"failed to build HTTP client\") will panic if the HTTP client fails to initialize, crashing the entire proxy service on startup.",
"impact": "Service unavailability. Bridge cannot start if HTTP client configuration is invalid.",
"exploitPath": "Invalid system configuration or missing TLS libraries causes HTTP client build to fail, crashing bridge during startup.",
"recommendation": "Return Result<ProxyState, Error> from new() and handle construction errors. Use anyhow::Context for better error messages."
},
{
"severity": "medium",
"category": "information-disclosure",
"file": "openfut-core/src/error.rs",
"line": 54,
"cwe": "CWE-209",
"title": "Error Messages Leak Implementation Details",
"description": "JSON parsing errors are returned directly to clients: format!(\"json parse error: {e}\"). Exposes serde_json parser internals and syntax details useful for crafting attacks.",
"impact": "Information disclosure. Attackers learn the JSON parser implementation and can tailor payloads to bypass validation or find parser-specific quirks.",
"exploitPath": "Send malformed JSON to any endpoint. Response includes parser error details (e.g., 'expected `,` at line 2 col 5') that aid in crafting exploits.",
"recommendation": "Return generic error message to clients: 'invalid request format'. Log detailed errors internally with tracing for debugging."
},
{
"severity": "medium",
"category": "information-disclosure",
"file": "openfut-core/src/error.rs",
"line": 40,
"cwe": "CWE-215",
"title": "Database Errors Logged with Full Details",
"description": "Database errors are logged with full SQL/query details: tracing::error!(\"Database error: {e}\"). If logs are exposed or compromised, schema, query patterns, and data structure are revealed.",
"impact": "Information disclosure in logs. Compromised log files expose database schema and query logic useful for SQL injection or data exfiltration planning.",
"exploitPath": "Access server logs (via log aggregation service, file access, etc.) and extract database schema and query patterns.",
"recommendation": "Log only error type and ID to clients. Sanitize logs before exporting. Use structured logging with field masking for queries."
},
{
"severity": "medium",
"category": "input-validation",
"file": "openfut-core/src/routes/auth.rs",
"line": 17,
"cwe": "CWE-1025",
"title": "Hardcoded Default Credentials",
"description": "Default username 'Player 1' is hardcoded with no unique identifier enforcement. Multiple profiles can be created with identical usernames, and weak defaults are used.",
"impact": "Weak account creation, potential for account confusion or conflicts. No strong identity guarantees.",
"exploitPath": "Multiple users create profiles with default 'Player 1' username. No way to distinguish profiles programmatically.",
"recommendation": "Require explicit username on profile creation. Use UUIDs as primary identifiers. Validate username uniqueness and minimum length."
},
{
"severity": "medium",
"category": "input-validation",
"file": "openfut-core/src/services/",
"line": 0,
"cwe": "CWE-400",
"title": "Missing Input Length Validation",
"description": "No maximum length checks on string fields (usernames, club names, squad names, etc.). Large inputs can cause database bloat, memory exhaustion, or DoS.",
"impact": "Denial of service via large payloads. Database bloat. Memory exhaustion. While DefaultBodyLimit::max(256KB) provides some protection, field-level validation is missing.",
"exploitPath": "POST /auth/local with username = 256KB string. Database receives bloated data. Repeated calls exhaust storage.",
"recommendation": "Add input validation for all user-submitted strings. Set maximum lengths (e.g., username: 50 chars, club name: 100 chars). Validate at route handler level."
},
{
"severity": "medium",
"category": "configuration",
"file": "openfut-core/src/db.rs",
"line": 13,
"cwe": "CWE-315",
"title": "Unencrypted SQLite Database on Disk",
"description": "SQLite database file (openfut.db) is stored unencrypted on disk. All user data, profiles, squads, cards, etc., are readable by anyone with filesystem access.",
"impact": "Data breach if server filesystem is compromised. No protection against:local file access, stolen backups, forensic recovery.",
"exploitPath": "Attacker gains filesystem access (compromised server, stolen disk). Reads openfut.db directly. All game data is readable without authentication.",
"recommendation": "Use SQLite encryption (e.g., sqlcipher crate) or migrate to PostgreSQL with TLS. Implement file-level encryption. Use restrictive filesystem permissions (0600)."
},
{
"severity": "medium",
"category": "rate-limiting",
"file": "openfut-core/src/app.rs",
"line": 0,
"cwe": "CWE-770",
"title": "No Rate Limiting on Endpoints",
"description": "No per-IP or per-user rate limiting. Endpoints like POST /auth/reset can be called repeatedly without restriction, allowing attackers to repeatedly wipe all data.",
"impact": "Denial of service and data destruction. Attacker can spam /auth/reset to destroy user data or exhaust server resources.",
"exploitPath": "for i in 1..1000: POST /auth/reset with confirm='reset'. All data wiped repeatedly.",
"recommendation": "Implement rate limiting middleware using tower_governor or similar. Add per-IP limits (e.g., 10 requests/min) and per-endpoint limits. Use exponential backoff."
},
{
"severity": "low",
"category": "audit-logging",
"file": "openfut-core/src/services/",
"line": 0,
"cwe": "CWE-778",
"title": "Missing Audit Logging",
"description": "No audit trail of user actions (profile creation, data deletion, squad modifications). Cannot detect unauthorized access, data tampering, or compliance violations.",
"impact": "Incident response and forensics are impossible. Cannot determine who did what and when. Compliance risks (GDPR, etc.).",
"exploitPath": "Attacker deletes all profiles, modifies squads. No audit log shows what happened or who did it.",
"recommendation": "Add audit logging for all data mutations. Log: timestamp, user (profile) ID, action, resource affected, before/after state. Store in separate immutable table."
},
{
"severity": "low",
"category": "dependencies",
"file": "openfut-bridge/Cargo.toml",
"line": 0,
"cwe": "CWE-1035",
"title": "Older Dependency Versions (reqwest, rustls)",
"description": "openfut-bridge uses reqwest 0.11 (latest is 0.12) and rustls 0.21 (latest is 0.23). Intentional for version matching, but creates a larger surface area for known CVEs.",
"impact": "Potential vulnerabilities in older dependencies. Delayed access to security patches.",
"exploitPath": "Known CVE in reqwest 0.11 or rustls 0.21 could be exploited. Combined with danger_accept_invalid_certs, TLS bypass becomes easier.",
"recommendation": "Upgrade dependencies to latest versions when possible. Monitor CVE databases (CVE, RustSec) for the versions in use. Pin versions and set up automated dependency updates."
},
{
"severity": "low",
"category": "error-handling",
"file": "openfut-core/src/app.rs",
"line": 256,
"cwe": "CWE-248",
"title": "Body Size Limit Without Per-Field Validation",
"description": "DefaultBodyLimit::max(256KB) limits the entire request body, but individual fields are not validated. A single large field can consume most of the limit.",
"impact": "Mild DoS. Large field values cause database bloat. Not a critical issue due to body limit, but field-level validation would be better.",
"exploitPath": "POST /auth/local with 250KB club_name field. Database receives bloated data.",
"recommendation": "Add per-field validation in addition to body limits. Validate and sanitize fields before database insertion."
}
],
"riskScore": 82,
"riskCategory": "CRITICAL",
"riskSummary": "OpenFUT has critical security issues that would make it unsafe for production or networked deployment. The most severe are the complete absence of authentication/authorization and the SQL injection pattern in the auth.rs module. The system is designed as single-player (single-profile) with no multi-tenant isolation, which is dangerous if exposed to the network.",
"recommendations": [
{
"priority": "CRITICAL",
"area": "Authentication & Authorization",
"recommendation": "Implement JWT-based or session-based authentication on all endpoints. Add middleware to validate auth tokens on every request. Implement per-profile authorization checks. Currently any HTTP client can access all endpoints.",
"effort": "High",
"impact": "Blocks all data breaches from unauthenticated access"
},
{
"priority": "CRITICAL",
"area": "SQL Injection Prevention",
"recommendation": "Replace sqlx::query(&format!(...)) in auth.rs:87 with proper parameterized identifiers. Use sqlx::query_builder for dynamic table/column names instead of string interpolation.",
"effort": "Low",
"impact": "Prevents SQL injection even if pattern is copied to user input"
},
{
"priority": "HIGH",
"area": "TLS & Transport Security",
"recommendation": "Remove .danger_accept_invalid_certs(true) from proxy.rs:44. If development requires it, gate behind an environment variable (e.g., DEV_SKIP_TLS_VERIFICATION) with strong warnings in logs.",
"effort": "Low",
"impact": "Prevents MITM attacks on bridge-to-core communication"
},
{
"priority": "HIGH",
"area": "Error Handling",
"recommendation": "Replace all expect() calls with proper Result handling. Use anyhow::Context or custom error types. Add logging for debugging but return generic errors to clients.",
"effort": "Medium",
"impact": "Prevents DoS via server panics"
},
{
"priority": "HIGH",
"area": "CORS",
"recommendation": "Replace CorsLayer::permissive() with CorsLayer::very_restrictive() or explicit allowlist. For single-player use, restrict to localhost and the game process only.",
"effort": "Low",
"impact": "Prevents CSRF and cross-origin attacks"
},
{
"priority": "HIGH",
"area": "Rate Limiting",
"recommendation": "Add per-IP rate limiting using tower_governor or similar. Implement limits on destructive endpoints (e.g., POST /auth/reset: 1 request per hour per IP).",
"effort": "Medium",
"impact": "Prevents DoS and repeated data destruction"
},
{
"priority": "MEDIUM",
"area": "Input Validation",
"recommendation": "Add maximum length validation for all string fields (username, club_name, squad_name, etc.). Enforce at route handler level. Example: username max 50 chars, club_name max 100 chars.",
"effort": "Medium",
"impact": "Prevents database bloat and data validation failures"
},
{
"priority": "MEDIUM",
"area": "Data Encryption",
"recommendation": "Use SQLite encryption (sqlcipher) or migrate to PostgreSQL with TLS. Set restrictive filesystem permissions (0600) on openfut.db.",
"effort": "High",
"impact": "Protects data at rest from filesystem access"
},
{
"priority": "MEDIUM",
"area": "Error Message Handling",
"recommendation": "Return generic error messages to clients. Log detailed errors internally. Example: client sees 'invalid request', server logs 'JSON parse error: expected `,` at line 2'.",
"effort": "Low",
"impact": "Reduces information disclosure"
},
{
"priority": "MEDIUM",
"area": "Audit Logging",
"recommendation": "Add audit trail for all data mutations (create, update, delete). Log timestamp, profile ID, action, resource, and before/after state. Store in immutable audit_log table.",
"effort": "Medium",
"impact": "Enables incident response and forensics"
},
{
"priority": "LOW",
"area": "Dependency Management",
"recommendation": "Upgrade reqwest to 0.12 and rustls to 0.23 when possible. Set up Dependabot or RustSec monitoring for CVEs. Regularly audit dependencies.",
"effort": "Low",
"impact": "Reduces attack surface from known CVEs"
},
{
"priority": "LOW",
"area": "Default Values",
"recommendation": "Remove hardcoded default username 'Player 1'. Require explicit username on profile creation. Use UUIDs for profile identification.",
"effort": "Low",
"impact": "Improves account identity and prevents confusion"
}
],
"securityDesignNotes": {
"intendedUse": "OpenFUT is designed for single-player offline use. Single-profile design is intentional for local FIFA 23 emulation.",
"deploymentContext": "Localhost only (127.0.0.1:8080). Not intended for networked or multi-user deployment.",
"implicationForSecurity": "Many security issues (no auth, permissive CORS) are acceptable for localhost-only use. However, the code structure lacks security boundaries, so if ever exposed to the network, it would be completely unsecured. Recommend adding security gates now rather than retrofitting later.",
"suggestedDefensiveApproach": "Even for single-player use, add security layers (basic auth, CORS restrictions, rate limiting) to prevent accidental misuse if deployed in an unsafe context."
},
"positiveFindingsAndStrengths": [
"✓ SQLx is used throughout with parameterized queries (except auth.rs:87)",
"✓ Foreign key constraints are enforced in SQLite",
"✓ UUIDs are used for entity IDs instead of sequential IDs (reduces enumeration attacks)",
"✓ Request body size is limited to 256KB (prevents large payload DoS)",
"✓ Concurrency is limited to 256 concurrent requests",
"✓ Sensitive tokens (X-UT-SID, X-UT-PHISHING-TOKEN) are stripped from captures",
"✓ Logging is structured using tracing crate (good for audit trails)",
"✓ Services layer properly encapsulates database access"
],
"testingRecommendations": [
"Add integration tests for authentication bypass (attempt to access endpoints without tokens)",
"Test SQL injection payloads in auth.rs:87 pattern (if table names become dynamic)",
"Test CORS with cross-origin requests from external origins",
"Test rate limiting with rapid concurrent requests to /auth/reset",
"Test input validation with oversized strings (100MB+ usernames)",
"Test panic handling with corrupted database state",
"Test TLS MITM scenarios (certificate pinning validation)",
"Add fuzz testing for JSON parsing to find edge cases"
],
"complianceNotes": {
"gdpr": "No explicit data handling policy. If user data is processed, GDPR requires consent, data retention limits, and audit trails. Not currently implemented.",
"dataProtection": "Unencrypted database at rest violates most data protection frameworks.",
"logging": "Audit logging is missing, violating compliance requirements."
}
}
-93
View File
@@ -1,93 +0,0 @@
# ============================================================================
# ⚠️ LEGACY (FIFA 23 lineage). This compose runs core + bridge for the
# superseded FIFA 23 direction. It is NOT the canonical server bring-up.
#
# Canonical server (FIFA 17):
# cd fifa17-recon/docker/fifa17-python && docker compose up -d
# (runbook: fifa17-recon/FUT-RUNBOOK.md)
#
# `core` (openfut-core) IS still the shared, game-independent backend and is
# used by the FIFA 17 UTAS host (OPENFUT_CORE_URL). `bridge` (openfut-bridge)
# is the retired FIFA 23 integration, kept for reference.
# Status source of truth: docs/PROJECT_STATE.md
# ============================================================================
# OpenFUT server stack — offline FUT backend (Core) + FIFA proxy (Bridge).
#
# Bring up: docker compose up -d
# Tear down: docker compose down (keeps data/captures volumes)
# Wipe state: docker compose down -v (also drops volumes)
# Rebuild: docker compose build (or ./scripts/registry.sh build)
# Logs: docker compose logs -f
#
# Images are pulled from / pushed to the Gitea container registry. Override the
# registry, namespace, or tag in .env (see .env.example). When REGISTRY is set,
# `up` pulls prebuilt images; the build: blocks let you rebuild locally too.
name: openfut
services:
core:
image: ${REGISTRY:-git.aleshym.co}/${NAMESPACE:-openfut}/openfut-core:${TAG:-latest}
build:
context: ./openfut-core
dockerfile: Dockerfile
restart: unless-stopped
environment:
LISTEN_ADDR: 0.0.0.0:8080
DATABASE_URL: sqlite:///app/db/openfut.db
DATA_DIR: /app/data
RUST_LOG: ${CORE_LOG:-openfut_core=info,tower_http=info}
volumes:
- core-db:/app/db
# Bound to localhost by default — the bridge reaches core over the internal
# network, so core need not be world-exposed. Set CORE_PUBLISH=0.0.0.0 in
# .env if you want to hit the REST API directly from other hosts.
ports:
- "${CORE_PUBLISH:-127.0.0.1}:8080:8080"
networks:
- openfut
healthcheck:
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8080/health"]
interval: 15s
timeout: 4s
retries: 5
start_period: 10s
bridge:
image: ${REGISTRY:-git.aleshym.co}/${NAMESPACE:-openfut}/openfut-bridge:${TAG:-latest}
build:
context: ./openfut-bridge
dockerfile: Dockerfile
restart: unless-stopped
depends_on:
core:
condition: service_healthy
environment:
BRIDGE_LISTEN_ADDR: 0.0.0.0:8443
CORE_URL: http://core:8080
CAPTURES_DIR: /app/captures
PLACEHOLDER_MODE: ${PLACEHOLDER_MODE:-true}
TLS_ENABLED: "true"
RUST_LOG: ${BRIDGE_LOG:-openfut_bridge=info,tower_http=info}
volumes:
- bridge-captures:/app/captures
# The FIFA client connects here — publish on all interfaces by default so
# LAN clients (e.g. 10.10.0.0/24) can reach it.
ports:
- "${BRIDGE_PUBLISH:-0.0.0.0}:8443:8443"
networks:
- openfut
healthcheck:
test: ["CMD", "curl", "-fsSk", "https://127.0.0.1:8443/_bridge/health"]
interval: 15s
timeout: 4s
retries: 5
start_period: 8s
networks:
openfut:
driver: bridge
volumes:
core-db:
bridge-captures:
Submodule fifa-blaze deleted from f4f33969f2
-16
View File
@@ -1,16 +0,0 @@
# Keep the authoritative-tree build context lean: only tools/ and data/ runtime
# files (plus the Dockerfile's own entrypoint/manifest) are needed in-image.
.git
.gitignore
artifacts
captures
futmem
staging
docs
FUT-RUNBOOK.md
README.md
data/memdump
**/__pycache__
*.pyc
*.pem
*.key
-13
View File
@@ -1,13 +0,0 @@
# Heavy / game-derived / volatile — never commit
*.asm
*.bin
*.strings
*.dll
*.exe
*.pem
*.key
*.log
__pycache__/
captures/
staging/
tools/fifa17_profile.json
-67
View File
@@ -1,67 +0,0 @@
# FIFA 17 offline FUT — runbook
Brings FIFA 17 **Ultimate Team** up against a 100% offline, clean-room emulated backend
(no EA servers, no internet). Proven working end-to-end 2026-08-01 (auth → Blaze login →
device-trust → the FUT hub).
## One-command start
```bash
cd fifa17-recon/tools
./openfut-fut.sh start # arms the host + starts all 5 servers
```
`start` is idempotent and re-arms everything, so **just re-run it after a reboot**. It will pop a
graphical password prompt (via `pkexec`) the first time to arm the host, then skip it while armed.
Then, **in this order**:
1. Launch FIFA 17 **fresh** (a clean launch avoids the "FUT Squad Update"/live-DB error caused by
stale in-process state): `~/Desktop/launch-fifa17.sh`
2. In-game, select **Ultimate Team**.
3. At the **security question** ("system not trusted"): type **any answer** → Continue → OK.
(Our server accepts any answer and marks the device trusted.)
4. → the **FUT hub**.
`./openfut-fut.sh status` shows what's up; `stop` / `restart` do the obvious. The servers must be
up **before** launching FIFA — they bind the ports the game dials.
## What it stands up
| Component | Port(s) | Role |
|---|---|---|
| `lsx_responder_v2.py` | 4216 | Origin LSX (login, GetProfile, GetAuthCode, events) |
| `blaze_responder_v3b.py` | 42127 / 42130 / 42131 | Blaze redirector (TLS) / Blaze / Nucleus |
| `roster_server.py` | 8081 | FUT roster-update XML |
| `utas_server.py` | 8099 | FUT/UTAS (RS4) API: auth, device-trust, boot calls, hub |
| `autopatch.py` | — | patches FIFA17.exe's ProtoSSL cert-verify on launch |
Privileged host state (armed by `root_arm.sh` via `pkexec`): `kernel.yama.ptrace_scope=0`,
`net.ipv4.conf.lo.route_localnet=1`, iptables DNAT `159.153.51.20 → 127.0.0.1:42127`, and
`/etc/hosts: 127.0.0.1 easw.easports.com` (the last persists across reboot; the rest don't).
## Persistence / reboot
Sysctls, iptables and the TLS cert are volatile — `./openfut-fut.sh start` rebuilds them, so the
supported recovery is simply to re-run it after boot. (For hands-off auto-start you can wrap
`root_arm.sh` in a root `systemd` oneshot at boot and the servers in a user service, but the
one-command flow above is the sanctioned path.)
## Troubleshooting — the gate ladder (each fixed; if one regresses this is where)
Watch `/tmp/{lsx,blaze,roster,utas,autopatch}.log`. The screens you may see and their cause:
| Screen | Cause / fix |
|---|---|
| "log in to Origin" | LSX `GetInternetConnectedState` → `connected="1"` |
| "title version outdated" | LSX `GetGameInfo UPTODATE` → `"true"` |
| "Unable to retrieve account information" | LSX response `sender` must echo the request `recipient`; `AuthCode value=` |
| "not eligible … age restriction" | mislabeled — the `AuthCode` reply needed the `value=` attribute |
| "Unable to connect to the EA servers" | Blaze `CONF` durations must be unit-suffixed (`"30s"`, not `30000000`) |
| FUT loading spinner (forever) | Blaze `CensusData` subscribe reply needs non-zero `CNP/NTMT`; and `ROSTERUPDATE_URL` served + roster_server up |
| "error connecting to Ultimate Team" | `easw.easports.com` → 127.0.0.1 (`/etc/hosts`) + `utas_server` on :8099 |
| "error downloading the FUT Squad Update" | stale in-process state — **relaunch FIFA fresh** |
| Security question | type any answer → our `utas_server` `/phishing/validate` accepts it |
Full reverse-engineering write-ups: `login_dump/*.md`, `docs/*.md`. All findings are clean-room
(from binaries we own); nothing from any leak. The whole protocol maps to FIFA 23 (identical wire format).
-196
View File
@@ -1,196 +0,0 @@
# FIFA 17 Blaze Recon (Rosetta Stone for FIFA 23)
Clean-room reverse engineering: all findings derive from observing our own running
FIFA 17 client + static disassembly of the shipped binary we own. **No leaked EA
source is used or referenced.**
> ## ✅ WORKING: FIFA 17 Ultimate Team, 100% offline
> The full online + FUT stack is emulated. **Quick start → [`FUT-RUNBOOK.md`](FUT-RUNBOOK.md):**
> ```bash
> cd tools && ./openfut-fut.sh start # arm host + start all servers (re-run after reboot)
> ~/Desktop/launch-fifa17.sh # then launch FIFA FRESH and select Ultimate Team
> ```
> Proven end-to-end 2026-08-01: auth → Blaze login → device-trust → the FUT hub. The rest of this
> file is the reverse-engineering history that got there (see also `login_dump/*.md`, `docs/*.md`).
## Breakthrough — 2026-07-30: ProtoSSL cert pin DEFEATED, redirector handshake captured
FIFA 17 dials the **secure** Blaze redirector `winter15.gosredirector.ea.com` over
TLS 1.2 (RSA-kx). We MITM it with a self-signed cert and defeated DirtySDK/ProtoSSL's
cert pinning with two live `/proc/PID/mem` patches, then captured the **plaintext**
first-hop handshake.
### Key architectural finding
The secure redirector is **HTTPS + XML (ProtoHttp)**, NOT raw Fire2/Heat2:
```
POST /redirector/getServerInstance HTTP/1.1
Host: winter15.gosredirector.ea.com:42230
User-Agent: ProtoHttp 1.3/DS 15.1.2.1.0 (Windows)
Content-Type: application/xml
<serverinstancerequest>...</serverinstancerequest>
```
Fire2/Heat2 binary is the **second hop** — the redirector replies with a
`<serverinstance>` XML naming a Blaze server IP:port; the client then connects THERE
for the binary protocol. Full request body in `captures/getServerInstance_request.http`.
## Reproduce (after reboot — all live state is volatile)
Binary maps flat at base `0x140000000` under Wine/Proton (UMU-Proton-10.0-4,
prefix `~/Games/umu/fifa17`). VAs below are stable across launches.
### 1. Root arm (scratchpad/root_arm.sh via pkexec)
- `sysctl kernel.yama.ptrace_scope=0` (enables /proc/mem WRITES)
- `sysctl net.ipv4.conf.lo.route_localnet=1`
- `iptables -t nat -A OUTPUT -p tcp -d 159.153.51.20 -j DNAT --to-destination 127.0.0.1:42127`
(winter15 resolves to 159.153.51.20; a /etc/hosts entry for winter15 would
short-circuit the DNAT and must be ABSENT)
### 2. TLS capture server
`scratchpad/blaze_tls_capture.py` on 127.0.0.1:42127, presents `redir_cert.pem`
(self-signed, CN+SAN=winter15.gosredirector.ea.com), ciphers `ALL:@SECLEVEL=0`.
### 3. The two cert-verify patches (via scratchpad/memtool.py)
The cert handler lives at ~`0x14613252x`. Two gates:
| VA | Role | Patch |
|---|---|---|
| `0x146132548` | Gate 1: `jne 0x1461326c4` (UNKNOWN_CA branch after chain-verify `call 0x146136410`) | 6 bytes → `90 90 90 90 90 90` (NOP) |
| `0x1461361b0` | **Gate 2: the real pin** — cert verify helper; returned `-51 (0xffffffcd)` live | 3 bytes → `31 c0 c3` (`xor eax,eax; ret`) |
Gate 2 (`0x1461361b0`) is the decisive one — a shared verify helper (also called from
`0x146131f86`). Forcing it to return 0 makes `r12d=0`, the `je 0x14613262d` at
`0x14613256c` is taken, and the accept path at `0x146132675` is reached (skips the
UNKNOWN_CA alert send at `0x146135250`).
NB: last session's patch of `0x146136410` (chain-verify callee) did NOT work — it was
not the function returning the live failure. gdb breakpoint on `0x1461361b0` proved
Gate 2 was the wall (`eax=0xffffffcd`).
## Breakthrough #2 — 2026-07-30: BOTH HOPS DEFEATED, Fire2/Heat2 decoded
Built `tools/blaze_responder.py`: answers `getServerInstance` over TLS with a
`<serverinstanceinfo>` that redirects the client to a local plain Blaze port, and
captures the second-hop Fire2 binary. The client **accepted the redirect and connected**,
sending its `Util::preAuth` handshake in binary Heat2. `tools/decode_fire2.py` decodes it.
### getServerInstance response schema (the redirect)
`ServerInstanceInfo.address` is a `ServerAddress` **union**; Heat2 XML encodes a union as
`<field member="N"><valu>...</valu></field>`. Working response (member=0 = ipAddress variant):
```xml
<serverinstanceinfo>
<address member="0"><valu>
<hostname>127.0.0.1</hostname><ip>2130706433</ip><port>42130</port>
</valu></address>
<secure>0</secure>
<trialservicename></trialservicename>
<defaultdnsaddress>0</defaultdnsaddress>
</serverinstanceinfo>
```
`<ip>` is a **decimal uint32** host-order (2130706433 = 127.0.0.1). `<secure>` 0/1 picks
plaintext vs TLS for the Blaze connection. (Schema cross-confirmed clean-room vs MEC
Catalyst private-server projects; response types reversed from the client's own TDF
reflection tables at ~0x143891xxx / 0x144873xxx.)
### Fire2 frame header (16 bytes, big-endian)
```
[0:4] u32 payloadLength [6:8] u16 component [8:10] u16 command
[10:12] u16 error/msgId [12] u8 msgType [13:16] reserved
```
First RPC observed: **component 0x0009 = Util, command 0x0007 = preAuth, msgType 0x02**.
Ping/pong keep-alives: Util command 0x0002, empty payload, msgType 0x01/0x03.
### Heat2 TDF encoding (decoded in decode_fire2.py)
Per field: 3-byte tag (4 chars, 6-bit packed, char = v?v+0x20:' ') + 1 type byte + value.
Types: 0x00 int(varint, first byte 6 data bits + continue@0x80), 0x01 string(varint len incl
null + bytes), 0x02 blob, 0x03 struct(nested, 0x00 terminator), 0x04 list, 0x05 map, 0x06 union.
### preAuth codebook (Util::preAuth PreAuthRequest) — captures/blaze/preauth_decoded.txt
```
CDAT{ IITO:int LANG:int SVCN:str='fifa-2017-pc' TYPE:int }
CINF{ BSDK='15.1.1.3.0' BTIM='Jun 9 2017 16:15:40' CLNT='FIFA17' CPFT:int=4
CSKU='FIFAPC' CVER='3175939' DSDK='15.1.2.1.0' ENV='prod' LOC:int PTVR='1.1' }
FCCR{ CFID='BlazeSDK' }
LADD:int
```
Same fields as the XML getServerInstance request → XML and Fire2 are the two encodings of
the same TDFs (the Rosetta mapping).
(Fire2 header was later CORRECTED: byte[12] is the low octet of a 24-bit msgNum, not msgType;
msgType lives in byte[13] high bits = (msgType<<5)|userIndex. REPLY=1→0x20, NOTIFICATION=2→0x40.
metadataLen is u16 at [4:6]. See tools/heat2.py / blaze_responder_v3b.py.)
## Breakthrough #3 — Origin/LSX layer defeated (PreAuthResponse + login flow work)
`tools/blaze_responder_v3b.py` answers preAuth, ping, fetchClientConfig, login (1/0x0A),
getAccount(1/0x1E)=AccountInfo, getPersona/listPersonas, and pushes UserAuthenticated (0x7802/8).
But Blaze isn't the online gate — **Origin is**, via its own in-process LSX layer:
- The Steampunks `stp-origin_emu.dll` serves **LSX** (length-prefixed, NUL-terminated XML) IN-PROCESS
on 127.0.0.1:4216. It's a blind fixed-script replayer that reports OFFLINE. **Replace it**:
bind 4216 BEFORE launching FIFA (`tools/lsx_responder_v2.py`; the stub has no SO_REUSEADDR and
stands down cleanly), serve real request-driven LSX.
- **LSX crypto (reversed + verified byte-exact):** server sends `<Challenge key="<32hex>">`; client
replies `<ChallengeResponse response="<96hex>" key="<32hex>">`; **H = hex(AES128-ECB(K=000102..0f,
PKCS7pad16(clientKey_ascii)))** (32 ASCII → 48 bytes/3 blocks); server sends `<ChallengeAccepted
response="H">`; session key = srand(7) LCG of H; later msgs = hex(AES-ECB(pkcs7(xml)))+NUL.
- **LSX verbs to answer:** GetProfile(PersonaId=33068179 Persona=CAGE US), GetSetting UPPERCASE
(ENVIRONMENT→"production", LANGUAGE→"en_US", else "false"), GetGameInfo (LANGUAGES→locales,
**UPTODATE→"true"** [else "title version outdated"], FREETRIAL→"false"),
**GetInternetConnectedState→connected="1"** [the online gate], etc.
- Gates cleared this way: "log in to Origin" ✓ and "title version outdated" ✓.
## Breakthrough #4 — 2026-07-30: repack fully reversed (LSX contract is a byte-exact oracle)
The Steampunks repack ships two UPX-packed helpers; we unpacked and clean-room reversed BOTH
(multi-agent workflow, adversarially verified — full report `docs/REPACK_INTEL.md`, emu disasm
`docs/emu.asm`). Unpack recipe: `upx -d stp-origin_emu.dll` and `upx -d _fifa17.exe` (emu base
0x180000000, loader base 0x140000000; both are NORMAL PEs — objdump works, unlike the encrypted
FIFA17.exe). Findings that matter:
- **`stp-origin_emu.dll` = the reference LSX server, offline BY CONSTRUCTION.** It is a blind
18-step straight-line script with NO parser and NO dispatch branch; its ONLY unsolicited frame is
the plaintext Challenge; it hardcodes `connected="0"` and has NO `<Login>` event / no auth vocab
anywhere in its 19,456 bytes. **Structural proof (not absence-of-evidence): nothing in the repack
can flip `m_isLoggedIn`.** The login mechanism lives ONLY in FIFA17.exe's live-decrypted code.
- **Our `lsx_responder_v2.py` is CONFIRMED byte-exact** on framing (NUL-terminated, NUL counted in
send len), crypto (AES-128 K_FIXED=000102..0f, PKCS7, srand(7)→61 session-key LCG), event shape,
sender values (EALS / EbisuSDK / ""), and encryption timing (plaintext through ChallengeAccepted
id=1, encrypted from id=2). Applied hardening C1–C3 (emu-exact `challenge_response` + tail assert,
extract `response="`, partial-frame buffering). Selftest still green (session key unchanged).
- The loader is an offline keygen/launcher (no WS2_32, no injection, no Blaze/Nucleus strings); its
`.dlf` GameToken is a local ENTITLEMENT grant, not a session — will not help login. Shared build
constants: UserId/PersonaId **33068179**, MachineHash == LSX Challenge key **2b8ee7fa…e32** (fixed).
## CURRENT WALL — "Unable to retrieve account information" (m_isLoggedIn stays 0)
FIFA has two Origin flags — "internet reachable" (fed by GetInternetConnectedState, DONE) and
**"user LOGGED IN" = OriginMgr.m_isLoggedIn @[OriginMgr+0x13]**, whose only setter is dispatcher
case-2 @0x146f1e0ab, driven by a server-PUSHED `<Event sender="LOGIN_EVENT"><Login IsLoggedIn="true"/>`.
**Pushing it 90× did NOT flip the flag.** Breakthrough #4 RULED OUT three causes: framing, event
shape, and encryption timing are all confirmed correct. **Surviving hypotheses, narrowed:**
(1) **encrypted mid-session Events are dropped** — the emu's only Event is plaintext+pre-key, so
there is zero evidence FIFA routes an *encrypted* Event to the same parser (STRONGEST); (2) `sender`
name mismatch; (3) handler-registration timing. Deeper residual: LoginStatePCLogin @0x1471b58e0 may
gate on a session OBJECT [0x144b86bf8]->vtbl+0x60, not the flag.
### THE decisive next experiment (observe, don't guess) — new tooling ready
1. Relaunch harness+game (below), run responder with an UNBOUNDED heartbeat so pushes stay in flight:
`OPENFUT_LSX_EVENT_COUNT=100000 python3 -u tools/lsx_responder_v2.py`
2. `bash tools/trace_login.sh` — attaches gdb, traces the sender matcher (0x147102880), the <Login>
parser (0x147138660), and dispatcher case-2 (0x146f1e09e / set-1 0x146f1e0ab / set-0 0x146f1e0b8).
Answers the 3-question ladder in ONE run: does the frame reach the matcher? what sender does it
strcmp against (dumps the table entry)? does case-2 run and the flag flip?
3. If the trace shows the ENCRYPTED frame never reaches the matcher → run the A/B:
`OPENFUT_LSX_LOGIN_PLAINTEXT=1 …` pushes the Login Event in plaintext right after ChallengeAccepted.
4. `tools/dump_login_code.py` — dumps + disassembles the decrypted login machinery at true VAs for a
follow-up static pass if the trace points below the dispatcher.
## How to resume (rebuild the volatile harness)
1. `pkexec sh tools/../scratchpad/root_arm.sh` (ptrace_scope=0, route_localnet, DNAT 159.153.51.20→42127).
2. `python3 -u tools/lsx_responder_v2.py` — bind :4216 BEFORE launching FIFA.
3. `python3 -u tools/blaze_responder_v3b.py` — :42127 (redir TLS) / :42130 (blaze) / :42131 (nucleus).
4. `python3 tools/autopatch.py` — re-applies the two ProtoSSL cert patches to any relaunched FIFA17.exe.
5. Launch FIFA via `~/Desktop/launch-fifa17.sh`; go Online.
6. Watch /tmp/lsx.log (LSX) + /tmp/blaze_responder.log (Blaze); use tools/origin_login_probe.py to read
m_isLoggedIn. Everything is volatile across reboot; VAs are stable (base 0x140000000).
## Live-state note
Volatile across reboot: cert patches, responders, DNAT, ptrace_scope. `tools/autopatch.py`
re-applies both cert patches automatically to any relaunched FIFA17.exe (VAs are stable).
Everything ported here (framing, Heat2, LSX crypto, tags) applies to FIFA 23 (identical wire format).
File diff suppressed because it is too large Load Diff
-416
View File
@@ -1,416 +0,0 @@
{
"_source": "data/tables/*.json dumped read-only from the running client by tools/db_dump.py",
"_key": "resourceId == carddbid, RAW u32 (the staff branches of FUN_180141660 do NOT mask, unlike players)",
"families": {
"headcoach": {
"cardsubtypeid": 5,
"table": "headcoachcards",
"record_4c": 3,
"rowcount": 124,
"carddbid_band": [
2000004,
2000328
],
"absent_ids_in_band": 201,
"miss_fill_assetid": 2000148,
"seeds": [
{
"carddbid": 2000004,
"assetid": 2000004,
"attribute": 0,
"value": 55,
"amount": 5,
"rare": 0
},
{
"carddbid": 2000008,
"assetid": 2000008,
"attribute": 2,
"value": 55,
"amount": 5,
"rare": 0
},
{
"carddbid": 2000016,
"assetid": 2000016,
"attribute": 5,
"value": 55,
"amount": 5,
"rare": 0
},
{
"carddbid": 2000024,
"assetid": 2000024,
"attribute": 4,
"value": 55,
"amount": 5,
"rare": 0
},
{
"carddbid": 2000032,
"assetid": 2000032,
"attribute": 5,
"value": 55,
"amount": 5,
"rare": 0
},
{
"carddbid": 2000044,
"assetid": 2000044,
"attribute": 1,
"value": 64,
"amount": 5,
"rare": 1
},
{
"carddbid": 2000064,
"assetid": 2000064,
"attribute": 1,
"value": 80,
"amount": 15,
"rare": 1
},
{
"carddbid": 2000084,
"assetid": 2000084,
"attribute": 3,
"value": 66,
"amount": 5,
"rare": 0
},
{
"carddbid": 2000124,
"assetid": 2000124,
"attribute": 0,
"value": 70,
"amount": 10,
"rare": 1
},
{
"carddbid": 2000164,
"assetid": 2000164,
"attribute": 1,
"value": 77,
"amount": 10,
"rare": 0
}
],
"bad_controls": [
2000005,
2000089,
2000177,
2000259
]
},
"gkcoach": {
"cardsubtypeid": 6,
"table": "gkcoachcards",
"record_4c": 10,
"rowcount": 121,
"carddbid_band": [
9000001,
9000324
],
"absent_ids_in_band": 203,
"miss_fill_assetid": 9000258,
"seeds": [
{
"carddbid": 9000001,
"assetid": 9000001,
"attribute": 0,
"value": 55,
"amount": 5,
"rare": 0
},
{
"carddbid": 9000017,
"assetid": 9000017,
"attribute": 4,
"value": 55,
"amount": 5,
"rare": 0
},
{
"carddbid": 9000021,
"assetid": 9000021,
"attribute": 5,
"value": 55,
"amount": 5,
"rare": 0
},
{
"carddbid": 9000025,
"assetid": 9000025,
"attribute": 0,
"value": 80,
"amount": 15,
"rare": 1
},
{
"carddbid": 9000037,
"assetid": 9000037,
"attribute": 3,
"value": 64,
"amount": 5,
"rare": 1
},
{
"carddbid": 9000081,
"assetid": 9000081,
"attribute": 2,
"value": 66,
"amount": 5,
"rare": 0
},
{
"carddbid": 9000117,
"assetid": 9000117,
"attribute": 5,
"value": 80,
"amount": 15,
"rare": 1
},
{
"carddbid": 9000121,
"assetid": 9000121,
"attribute": 0,
"value": 75,
"amount": 10,
"rare": 0
},
{
"carddbid": 9000125,
"assetid": 9000125,
"attribute": 1,
"value": 74,
"amount": 10,
"rare": 1
},
{
"carddbid": 9000308,
"assetid": 9000308,
"attribute": 5,
"value": 80,
"amount": 15,
"rare": 1
}
],
"bad_controls": [
9000002,
9000086,
9000174,
9000280
]
},
"physio": {
"cardsubtypeid": 7,
"table": "physiocards",
"record_4c": 5,
"rowcount": 51,
"carddbid_band": [
4000002,
4000259
],
"absent_ids_in_band": 207,
"miss_fill_assetid": 4000146,
"seeds": [
{
"carddbid": 4000002,
"assetid": 4000002,
"attribute": 5,
"value": 55,
"amount": 5,
"rare": 0
},
{
"carddbid": 4000018,
"assetid": 4000018,
"attribute": 6,
"value": 55,
"amount": 5,
"rare": 0
},
{
"carddbid": 4000022,
"assetid": 4000022,
"attribute": 0,
"value": 80,
"amount": 15,
"rare": 1
},
{
"carddbid": 4000026,
"assetid": 4000026,
"attribute": 2,
"value": 55,
"amount": 5,
"rare": 0
},
{
"carddbid": 4000046,
"assetid": 4000046,
"attribute": 3,
"value": 64,
"amount": 5,
"rare": 1
},
{
"carddbid": 4000078,
"assetid": 4000078,
"attribute": 4,
"value": 66,
"amount": 5,
"rare": 0
},
{
"carddbid": 4000122,
"assetid": 4000122,
"attribute": 3,
"value": 74,
"amount": 10,
"rare": 1
},
{
"carddbid": 4000170,
"assetid": 4000170,
"attribute": 1,
"value": 75,
"amount": 10,
"rare": 0
},
{
"carddbid": 4000194,
"assetid": 4000194,
"attribute": 6,
"value": 75,
"amount": 10,
"rare": 0
},
{
"carddbid": 4000254,
"assetid": 4000254,
"attribute": 6,
"value": 80,
"amount": 15,
"rare": 1
}
],
"bad_controls": [
4000003,
4000089,
4000175,
4000257
]
},
"fitnesscoach": {
"cardsubtypeid": 8,
"table": "fitnesscoachcards",
"record_4c": 4,
"rowcount": 115,
"carddbid_band": [
3000019,
3000328
],
"absent_ids_in_band": 195,
"miss_fill_assetid": 3000259,
"seeds": [
{
"carddbid": 3000019,
"assetid": 3000019,
"value": 55,
"amount": 1,
"posbonus": 3,
"fieldpos": 1,
"rare": 0
},
{
"carddbid": 3000023,
"assetid": 3000023,
"value": 55,
"amount": 1,
"posbonus": 5,
"fieldpos": 1,
"rare": 0
},
{
"carddbid": 3000035,
"assetid": 3000035,
"value": 55,
"amount": 1,
"posbonus": 5,
"fieldpos": 0,
"rare": 0
},
{
"carddbid": 3000043,
"assetid": 3000043,
"value": 64,
"amount": 2,
"posbonus": 6,
"fieldpos": 2,
"rare": 1
},
{
"carddbid": 3000047,
"assetid": 3000047,
"value": 64,
"amount": 2,
"posbonus": 2,
"fieldpos": 1,
"rare": 1
},
{
"carddbid": 3000059,
"assetid": 3000059,
"value": 64,
"amount": 2,
"posbonus": 1,
"fieldpos": 0,
"rare": 1
},
{
"carddbid": 3000083,
"assetid": 3000083,
"value": 66,
"amount": 2,
"posbonus": 5,
"fieldpos": 0,
"rare": 0
},
{
"carddbid": 3000091,
"assetid": 3000091,
"value": 80,
"amount": 5,
"posbonus": 5,
"fieldpos": 2,
"rare": 1
},
{
"carddbid": 3000127,
"assetid": 3000127,
"value": 70,
"amount": 3,
"posbonus": 5,
"fieldpos": 1,
"rare": 1
},
{
"carddbid": 3000171,
"assetid": 3000171,
"value": 77,
"amount": 3,
"posbonus": 5,
"fieldpos": 3,
"rare": 0
}
],
"bad_controls": [
3000020,
3000100,
3000178,
3000307
]
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-934
View File
@@ -1,934 +0,0 @@
k|J|
tz^WU
Gb\X[
,j|L
cXXXX
gzW[rp
)l``b`
c^^^^
zrbnz
r--)
&jzzx
Jl```
c^^^\
----
k|X\^_
c\Xxx
K|bjk
cxxxx
---%
{xx|
cxxxz
Frxz
{VVVW
cpxz~
gr*:
sTVUU
cxz^W
[5555
px~M
cUUU5
cUU-
gz((+
&rX`
&kVX
cUUUx
&r^\
%%%%
&kUW
f[UUW
gcE[
$gcE[
cUU%
UUWT
xxxx
FsUU^
$ecF[
icD[
T\Rb
sUW|
UUU\
VUUU
BIGF
L286
Apt Data:1:7:8
game/globalComponents/globalComponents
game.globalComponents.ImageLoader
game/components/SelectTeam
game.components.SelectTeam
Coins
TournamentData
BackingFUT
VersusFUT
external.ion_fut.screens.futSelectTeam
__Packages.external.ion_fut.screens.futSelectTeam
__Packages.ion.manager.HelpProperties
EACondBold
10.000
Screen
RtIL
RYgO
7uOO
XsOY
2sOY
<@OY
BG&Y
3NuIL
7NuI
3NuI
3NstY
7uOY
&v>Y
&v>t
3NYN
7NYN
tOYZ
BG&v
NZGO
NZGOZu
uOZu
mcCup
txtPrizeHeading
txtCoins
mcCoin
mcBacking
txtVs
mcTournamentInfo
mcSelectTeam
mcVersusFUT
publishObject
dpID
nHomeKitID
nAwayKitID
keyCode
controllerId
nSide
arrKitIDs
teamId
kitToResolve
side
isUser
arrKits
objProperties
Void
nXPos
DDS |
NVTT
DXT5
8VTTT
UUVT
TTTU
0TUVT
TTUW
$$r
%UUU
WUUU
UUUSP
UUUM
UUUNK
72Ib
*72Ib
U;8I
WWWW?>I
UIFI
WWWWLKI
WWWVQNI
VVYVI
`]IB
daIB
heIB
VlhI
vtI"I
UU%!I
*;8I
U?>I
ULKI
Apt1
_global
external
Object
ion_fut
screens
futSelectTeam
futSelectTeam::futSelectTeam()
OnExitScreen
cafe
utility
Delegate
Create
game
globalClasses
ScreenManager
SetOnExitScreenCallback
m_nFlowState
EA_ZONE
gScreenFlowManager
getFlowState
ION_Platform
IsFinal
CardNotification
eState
FUT_OFFLINE_DRAFT
FUT_OFFLINE_TOURNAMENT
FUT_OFFLINE_SEASON
m_bAllowSelectAnyTeam
FUT/ALLOW_ANY_CPU_TEAM
ION_Customization
GetAardvarkIntValue
mcPanelHome
mcPanelAway
mcReadyHome
mcReadyAway
mcKitHome
mcKitAway
mcLockHome
mcLockAway
InitComponents
InitializeScreen
Initialize
screen
BaseScreen
prototype
futSelectTeam::InitializeScreen()
_visible
HOME_SIDE
GameServices
eTeamSide
SIDE_HOME
AWAY_SIDE
SIDE_AWAY
NEUTRAL_SIDE
SIDE_NEUTRAL
m_arrPanelData
Array
m_arrKitPanelData
futSelectTeam::InitComponents()
InitializeKitConfig
InitializeTeamConfig
SetTeamAndKitConfigs
UIFDataProviderList
FUT_USER_CLUB_DATA_DP
UIFUtility
RegisterDataProvider
FUT_OPPONENT_CLUBS_LIST_DP
FUT_OPPONENTS_SQUADS_LIST_DP
FUT_OPPONENT_SQUAD_LINEUP_DP
FUT_USER_SQUAD_LINEUP_DP
FUT_CREATE_MATCH_DP
FUT_GET_MATCH_KITS_DP
SetupReadyTexts
initSideInfo
SetPanels
m_arrPanels
m_arrKitPanels
KitSelectDP
TeamSetupDP
AnimateIn
AnimateInComplete
BeginAnimateIn
futSelectTeam::AnimateInComplete()
m_bHasAnimatedIn
checkForDisconnect
gScreenNotAborted
LocalEventHandler
InputManager
AddLocalEventHandler
SetHandlerId
refreshCurrentConnectionStatus
HelpManager
Update
futSelectTeam::OnExitScreen()
AnimationManager
ClearAnimations
UnregisterDataProvider
INJURY_POPUP_ID
PopupManager
DeletePopup
TOTW_BELOW_MIN_POPUP_ID
USER_BELOW_MIN_POPUP_ID
OPP_BELOW_MIN_POPUP_ID
OPP_HAS_NO_VALID_SQUADS_ID
Shutdown
ClearSavedOpponentData
SQUAD_ID
UUID_UPPER
UUID_LOWER
UIFActionList
ACTION_SAVE_OPPONENT_DATA
SendActionObj
Publish
futSelectTeam::Publish()
header
USER_CLUB_DATA
SetUserClubData
initVersusFUTComponents
OPPONENT_CLUBS
m_arrOpponentClubs
data
MATCH_CREATED
FUT_PAFC_GAME
GetCurrentCountryIndex
SQUADS
GetCurrentLeagueIndex
ACTION_ADVANCE
SendAction
eSoundEvent
PRIMARY_SELECT
playSound
m_bShouldWaitForPublish
OPP_SQUADS_LIST
SetOpponentSquadListData
SQUAD_LINEUP_LOADED
IS_USER
SetSquadLineup
KITS_AVAILABLE
LENGTH
KIT_
push
futSelectTeam::InitializeKitConfig()
SetupTeamsInfo
GetHomeTeamId
ACTION_MATCHDAY_HOME_TEAM_CHANGE
GetAwayTeamId
ACTION_MATCHDAY_AWAY_TEAM_CHANGE
ACTION_MATCHDAY_ADVANCE_KIT_SETUP
SetReadyStatus
FadeOut
GetKitArrayForFUT
HOME_KIT_ID
AWAY_KIT_ID
ION_Uniform
IsKitSelectCreated
EnterKitSelect
IsAlternatingMode
GetUnhighlightedSide
SetKitUnReady
InitializeKitsFromArray
Unhighlight
SetDisabled
SetHighlightedSide
GetHighlightedSide
Highlight
futSelectTeam::InitializeTeamConfig()
LEAGUE_ID
components
TeamSetupControl
TEAM_TOGGLE
GetUserSideForFUT
m_isInFUT
InitData
GetToggleValue
UpdateTeamInfo
m_bOpponentTeamInvalid
m_OppHasSquads
SetChemistryValue
ResetTeamInfo
FadeIn
SetupMouseSupport
SetWomenTeamsOnlyFilter
SetMenTeamsOnlyFilter
DeactivateReady
futSelectTeam::SetupTeamsInfo()
USER_TEAM_ID
ION_GameSetup
GetTeam
SetHomeTeamId
SetAwayTeamId
setCustomSelectionArray
Team
eAttribute
ION_Team
GetAttributes
futSelectTeam::LocalEventHandler()
WARNING: Preventing the user to move until a Publish occurs.
IsInTransition
Stop spamming buttons, the team select screen is in a transition.
GetUserControllerSide
GetScreenState
DataProviders
STATE_TEAM
InputCodes
LEFT
RIGHT
GetReadyStatus
DOWN
BACK
ADVANCE
OPTION_TOP
OPTION_LEFT
IsSwitchSidesActive
STATE_KIT
SetUniform
ExitKitSelect
RemoveKitLocks
ACTION_BACKOUT
CANCEL
SetKit
SaveKitsForMatch
FUT_TOTW_GAME
SetGoingToKickoffHub
SetHomeKitId
SetAwayKitId
GetHomeKitId
GetAwayKitId
ACTION_CREATE_MATCH
SetReady
SetKitReady
FUT_OPP_HAS_NO_VALID_SQUADS
PopupData
Okay_abbr2
AddButton
ShowPopup
ValidateFullLineUp
m_sInjuryOrSuspendedWarning
m_bConceptPlayersInSquad
FUT_DB_Players_Not_Playable
FUT_TOTW_BELOW_MIN_PLAYERS
FUT_BELOW_MIN_PLAYERS
FUT_OPP_BELOW_MIN_PLAYERS
COUNTRY_TOGGLE
LEAGUE_TOGGLE
ACTION_GET_USER_SQUAD_LINEUP
ACTION_GET_OPPONENT_SQUAD_LINEUP
GoToViewSquad
PlatformManager
IsMicrosoft
USER_NAME
length
gEaso
showGamercard
getHelpContext
futSelectTeam::getHelpContext()
STATE_INVALID
FUT_VIEW_SQUAD_HOME
ltxt
manager
HelpItem
CreateHelpItem
FUT_VIEW_SQUAD_AWAY
ViewGamerCard
CreateHelpTickerItem
futSelectTeam::InitializeKitsFromArray()
GetAllAttributes
TYPE_UPPER
ITEM_NAME
ITEM_ID
ASSET_ID
StyleManager
FONT_TILE_HS
SetTitleTextFormat
SetToggleOffset
globalComponents
BasePanel
STYLE_FIFTEEN
SetBasePanelStyle
KIT_SCALE
kits
ToggleWithImage
STYLE_TOGGLE
SetStrokeVisibility
CheckIsKitLocked
futSelectTeam::GetKitArrayForFUT()
GetNonConflictingUniformID
eSortType
SORT_ASCENDING
Uniform
eSortColumn
SORT_NONE
eFilter
FILTER_UNFILTERED
GetIDs
LOCKED
NAME
shift
futSelectTeam::initVersusFUTComponents()
text
Versus_abbr
_height
FUT_Tournament
GetOfflineActiveTournamentId
GetOfflineTournamentInfo
TROPHY_ID
trophy
getArtAssetPath
SCALE_ASPECT_CENTER
setScaling
setSize
setImage
FUT_UC_TOURNAMENT_BONUS
PRIZE_FINAL
ION_Localization
LocalizeInteger
_width
textWidth
FUT_COINS_OFFSET
futSelectTeam::GoToViewSquad()
isUserTeam
CLUB_NAME
BADGE_TEAM_ID
SQUAD_NAME
RATING
SQUAD_RATING
CHEMISTRY
SQUAD_CHEMISTRY
SHOW_CHEM_LINE
SCREEN
VIEW_SQUADS
setContextDataObject
loadOverlayScreen
futSelectTeam::SetUserClubData()
m_arrUserClubs
PUBLIC
CLUB_ABBR
EST_DATE
ACTIVE_SQUAD_ID
SIDE_NAME
Away_Side
Home_Side
futSelectTeam::SetOpponentSquadListData()
split
FUT_NO_VALID_SQUADS
futSelectTeam::SetSquadLineup()
SetTeam
futSelectTeam::GetCurrentCountryIndex()
futSelectTeam::GetCurrentLeagueIndex()
futSelectTeam::GetUserSideForFUT()
bIsDemo
GetLockRules
SIDE_LOCK
futSelectTeam::ValidateFullLineUp()
FUT_SquadManagement
GetOpponentSquadLineup
GetSquadLineup
FUT_NUM_PLAYERS_IN_SQUAD
CARD_ID
ION_Card
GetPlayerCardInfo
IS_DREAM_PLAYER
FUT_NUM_PLAYERS_IN_SQUAD_EXTENDED
gFutHelpers
GetInjuryOrSuspendedSquadWarning
futSelectTeam::SaveKitsForMatch()
SIDE
NUM_KITS
ACTION_SAVE_MATCH_KIT
FUT_TOURNAMENT_CUP_SCALE
INJURY_OR_SUSPENDED_POPUP
TOTW_NUM_PLAYERS_BELOW_MIN_POPUP
USER_NUM_PLAYERS_BELOW_MIN_POPUP
OPP_NUM_PLAYERS_BELOW_MIN_POPUP
OPP_HAS_NO_VALID_SQUADS
SCALE_NONE
SCALE_ASPECT
SCALE_ABSOLUTE
ASSetPropFlags
HelpProperties
mXPos
GetXPos
SetXPos
registerClass
hj\W
hj/U
UUUV
'Z`XV
j`XVW
b$9^
UW^}
hb>x
DA__\X
UWW^
HbCA
hjCA/
+{dA
b#9X7*
I^^|x
(Z``pP
Zxp`
\j~X
&j\xp
jXXXX
Fn%Vb=
xxxp
xh``
WWWW
r\XXX
xxz_
{XPpr
Hb__^\
`x|x
``xX
]{jp
xxhh
X\\\
U\T_
`pz~
_^^^
cq,6
-/+*+
jjjj
jJJj
_^Xp
WV\p
TTWU
```h
pWUU
\UUU
$I">
x^UU
/UUU
$IR`m
$IL#
cAxW
dI/U
&b%W
|UWV\
j_uyQ
|UUVT
|WT\\
j`ppp
|\\\\
bpppp
)---
||x||
bzzzz
s"#)5
K{&R
D(tFR```
j5555
){zxh`
hlUU_`
$Ithd
Ithd
hlUWVT
s(ljj
HR{O
IBww
@Bbb
Hl\\Xx
zzhh
@`pP
Htxxxx
hlHd
Ht%%%5
ZZ\\
H|xxxx
Hthd
xxxX
TV_]
H|hd
Xxx`
_\|p
pppP
H|xxxz
i|%%%5
pX\T
H|xzzz
(dHt
H|`xz_
UU^p
$G|(t
G|(t
(tG\
VTTT
kUUU5
(pXxx
XXXX
KOKK
'cUU^
hs'c
$Gk(c
Gk(c
~ZZX
GkUWx
GkUUU\
'Gk(c
p``H
zUU~
X`pxZ
sUWx
c```
@@@@
WVT\
Vw~U
_^_j
\XPp
^|~^
c``pX\
````
UUUU
\\\\
????
p~UU
Ib'b
X\WU
A*++
UUUX
VWUU
z^VW
W^x
\\\\j
TWVV
\^xx
W^~
VWVt
cI^xxp
k$)WWVT
)W_VT
$1VTVT
(\\\\
\\\\"
$1\\XX
pr`z
AXPp`
yU^r^
$I2,r
PZrC
U{Bz
{||Z
kkki
c`p^
cx6l
\\\\]
dIb`@@
pvv]
'z@@
XVUU
e9`p
UVVV
(.-5
JJJJ
cQxxx
(%-)+
VVVV
#9ZZxx
i-)-
1U_|
#9=*
VVTT
T\\X
X^__
5-)+
$I"'r
rrbJ
8)-%5
ZZZZ
jjjk
1^UUU
g1G)^
!XX\V
BIGF0
Apt Data:1:5:8
U555
Urpp
~B'j
5555
m*((
;RRRR
m***
:RRRR
`15555
sZPPP
`95555
Apppp
95555
{PPPR
RRRR
rrp_
&j2'
pppp
Ns%!U
%)%%%%
f)%!
` 6dC.kE!
Z%)70
1E!W
1E!U
f1E!
F1Xp*
9f)U
xUU\
JV~No
(n{$!
iJPPpp
<W\^
AqUW
{Cq_
U]P\
Pppp
TTTT
PPPp
,(;k
z^\x
\^VT
???/
btTVV
M{-/75
x~_^
TUWW
%555
(^xp`
UUWV
jR\T\\
1xp``
b\\\X
b557/
jZ'5
WWWh
^XPZ
zxxxx
1UWVT
h4Vb%
\^U?
\\\X
I*.$
Hb'A
9UU\
i--+
Wka@
P|WWW
UW^x
@PW^
czXX
++-5
`x@p
brp`
U%%%
\VUW
XPXX
WTTV
PPXX
zc9~^z
I"1-+
!*+*
TTVT
----Y
73 &
Av|z
`^UJ
xx~p
&jB1_
Y444$
xWU0
$_nO
G1BBBB
xxx^
xxz~
---=
***J
O"'@
7 '>
U`X\Y
h035^
Lw!f
&T@a
]8RR
[OAq
D/Oz%F
+1.^-
_,_Y
..^O
CG|!@
;}>|
nHT*
a8Nj
?'Un70
^[zM2Bj @
6nd[N
Z)MBc
wY=A
8p(a
:m"D
[dbt
E'0S
nT+bJuZ
V-:t
v)(n
(*s?p
cc?r
B%{r
-4Yi
sci,Iy
|3;=
<KB6
cCFVJ
J|jg
4VvVV6
p$$e&
4%1{
~%ew==_.
EFGFFED
[FFB}9
$"dOz%^-
mw77
ct3r
ecGB
*\JV
c&WV
w6GMq
13aB
$X~_
mMx%
;11sZR
'&'n
q&##>o
+:Z/Y
]:AY
$(+~
,^:(,
kp>C
luqYql
wf_q
XYX\
@p77
--X&q
{ cf
waF,
znrn;
VRwCE
5=#&
/J"}
_A4Z
gnB7%
q`Y
Q|!+
[MMA
**rV
)~U(w*,)m
Z*SVd
$#&qi
qmUW=
F"MN
HaA%e%
(T!]5(\
IK#k
v wQ
C(\M
];%P
7f&=kJ
%(oRtK
gRr?
+rq_
/==7
,IUk
D?t(zC,
\}oe
'^YY
nwzu
jdf,
i5hFc
z@xOrFp
aqgv
y^oT+
dZ13
d{g~
ttzi
p,@B
upqH
1{pl0
J4)~
&W<;@
p77Es
:aPw
`>(^&
lnW|
~+w8
@@ -1,278 +0,0 @@
# FIFA17.exe runtime command/event id -> name registry
# Recovered 2026-08-24 from live pid 44405 (Denuvo-decrypted, /proc/PID/mem, read-only).
# CardsDLL live base 0x6ffffc0f0000; registration loop at live 0x147dd0000-0x147df8000.
# NOTE: this is a DIFFERENT namespace from CardsDLL's DataProvider id table.
# the same numeric id has a different name in each, matching the APT's split
# between game.uif.UIFDataProviderList and the action/command list.
#
0x0207 %d
0x0bb9 back
0x0bbb preScreenSucceeded
0x0bbc preScreenFailed
0x0bc0 clearTeamSheets
0x0be7 selectTab
0x0c15 optionSelected
0x0c2a leaveGameGroup
0x0c2c quitToHub
0x0dac UpdateStadiumCrests
0x0dac startStoryMode
0x2713 matchdayFixtureChange
0x271a evt_set_matchDay_offline_fixture
0x271b evt_team_setup_state
0x271c advanceDefault
0x271d advanceDefaultWithTeam
0x271e advancePran
0x271f feInitialized
0x2720 skipBootflow
0x2721 startBootflow
0x2722 bootflowStarted
0x2723 bootflowFinished
0x2724 bootflowSaveLoadFailed
0x2725 returnToPressStart
0x2726 showPressStart
0x2727 evt_load_personal_settings
0x2728 evt_settings_load_complete
0x2729 assetUpdate
0x272a pranUpload
0x272b pranDownload
0x272c controllerConfig
0x272d activateGameModeIntro
0x272e ActivateFullGame
0x272f startIntroFlow
0x2730 offlineEulaProfileSuccess
0x2731 offlineEulaProfileFail
0x2732 startIntroMatch
0x2733 abortIntroMatch
0x2735 setCareerType
0x2736 exitTitle
0x2737 evt_set_fullscreen
0x273e enterSubPanel
0x273f exitSubPanel
0x2742 evt_invite_accepted
0x2743 profileSignOut
0x2744 profilePrepareForSave
0x2745 logTelemetry
0x2746 enterPracticeArena
0x2748 navigationBackoutStart
0x2749 navigationBackoutContinue
0x274a navigationBackoutComplete
0x274b checkSpeechData
0x274c newsSharingSettings
0x274d leaveBootFlow
0x274e mainMenuProfileCreationDone
0x274f nonLeadProfileCreation
0x2750 nonLeadProfileLoad
0x2755 teamSheetAction
0x2758 evt_set_lead_profile
0x2759 evt_sign_out
0x275a notifySignOut
0x275b notifySignOutReady
0x275c notifySignOutTitleScreen
0x275d evt_sign_out_flow_ready
0x275e evt_sign_out_flow_not_ready
0x275f showSignOutPopup
0x2760 showSignOutTitleScreenPopup
0x2761 evt_dismiss_sign_out_popup
0x2762 evt_show_account_picker
0x2763 evt_lead_profile_recovered
0x2764 triggerSignOut
0x2765 checkLeadProfilePairing
0x2766 evt_lead_profile_paired
0x2767 evt_lead_profile_unpaired
0x2768 evt_lead_profile_controller_changed
0x2769 beginProfileCheck
0x276a endProfileCheck
0x276b evt_controller_disconnect
0x276c evt_notify_controller_disconnect
0x276d evt_controller_disconnect_flow_ready
0x276e evt_controller_disconnect_flow_not_ready
0x276f showLoadPersonalSettingsPopup
0x2770 showSavePersonalSettingsPopup
0x2771 feRenderInGame
0x2772 pvProfilerStart
0x2773 pvProfilerStop
0x2775 enterMatchDayTab
0x2776 exitMatchDayTab
0x2777 restartWithNewTeams
0x2778 playSecondLegFixture
0x2779 setupSecondLegFixture
0x277a welcomeToMatchDayLive
0x277b exitMatchDayLivePanel
0x277c enableAardvark
0x277d disableAardvark
0x277e conditionAardvark
0x2780 adaptiveDifficultyDetectedPopup
0x2781 adaptiveDifficultyUpPopup
0x2782 adaptiveDifficultyDownPopup
0x2783 adaptiveDifficultyDetected
0x2784 adaptiveDifficultyUp
0x2785 adaptiveDifficultyDown
0x2786 adaptiveDifficultyDisable
0x2787 adaptiveDifficultyReset
0x2788 adaptiveDifficultyKeep
0x2789 adaptiveDifficultyOverride
0x278c evt_countdown_done
0x278d evt_countdown_restart
0x278e evt_start_stadium_change
0x278f evt_wait_for_stadium_change
0x2790 evt_wait_for_stadium_change_bootflow
0x2791 evt_advance_to_wait_popup
0x2792 evt_advance_to_wait
0x2793 evt_stadium_background_loaded
0x2795 setupTournament
0x2796 createTournament
0x2797 createWomenTournament
0x2799 setWomenTournament
0x279a evt_sl_operation_started
0x279b evt_sl_operation_complete
0x279c evt_sl_operation_load
0x279d evt_sl_operation_boot_load
0x279e evt_sl_operation_save
0x279f evt_sl_operation_delete
0x27a0 FUTLoginComplete
0x27a1 requestDownload
0x27a2 backendEnter
0x27a3 backendExit
0x27a4 onlineLoginToEaPopup
0x27a5 onlineBootLoginToEaPopup
0x27a6 evt_onlineAlertPopup
0x27a7 evt_onlineBootLoginFailurePopup
0x27a8 evt_onlineLoginFailurePopup
0x27a9 onlineLoginPopupHide
0x27aa onlineLoginPopupShow
0x27ab evt_invite_flow_ready
0x27ac evt_invite_flow_not_ready
0x27ad inviteFlowAbortSaveLoad
0x27ae evt_verify_invite_nav_cleanup
0x27af downloadComplete
0x27b0 downloadFailed
0x27b1 spevnetNotAvailable
0x27b2 spevnetNotRegistered
0x27b3 spevnetNotRegisteredBeta
0x27b4 userBanned
0x27b5 showExitConfirmPopup
0x27b6 hideExitConfirmPopup
0x27b7 confirmExit
0x27b8 showRegisterConfirmPopup
0x27b9 hideRegisterConfirmPopup
0x27ba setStadiumPosition
0x27bb liveCompCountryDecision
0x27bc liveCompAllCountriesSelect
0x27bd liveCompLimitedCountriesSelect
0x27be liveCompAdvanceToTeamSelect
0x27bf liveCompRegistrationConfirm
0x27c0 liveCompEventListSuccess
0x27c1 liveCompEventListFail
0x27c2 postMatchHighlightExit
0x27c3 postMatchHighlightComplete
0x27c4 postMatchHighlightSelect
0x27c5 postMatchHighlightReelSelect
0x27c6 postMatchHighlightIRSelect
0x27cf leaveUpsell
0x27d0 purchase
0x27d1 advanceFromPMA
0x27d2 evt_transitionToPMADone
0x27d3 cutSceneCommand
0x27d4 cutScenePlay
0x27d5 loadCutScenesSubLevel
0x27d6 unloadCutScenesSubLevel
0x27d7 evt_enable_skip_cutscene
0x27d8 gmCutSceneStarted
0x27d9 gmCutSceneEnded
0x27da gmCutScenesSublevelLoaded
0x27db gmCutScenesSublevelUnloaded
0x27dc gmAirlockToGameplayEnded
0x27dd gmAirlockLoadComplete
0x27de evt_quit_to_training_hub
0x27e0 evt_training_allow_advance_to_game
0x27e1 checkOriginConnected
0x27e2 OriginIsOnline
0x27e3 OriginIsOffline
0x27e4 OIGOpened
0x27e5 OIGClosed
0x27e6 overrideOnlineStadium
0x27e7 smLoadFEStadium
0x27e8 smActivateFreeRoam
0x27e9 smGameOver
0x27ea smScenePrime
0x27eb smScenePrimeAndPrep
0x27ec smScenePause
0x27ed smSceneResume
0x27ee smMoment
0x27ef smMomentRepeat
0x27f0 smMomentComplete
0x27f1 smExitMomentState
0x27f2 smOnPlayScene
0x27f3 smConversation
0x27f4 smConversationComplete
0x27f5 smConversationNotification
0x27f6 smConversationNotificationComplete
0x27f7 smGameplayStartLoad
0x27f8 smGameplayLoadOver
0x27f9 smGameplayStart
0x27fa smGameplayOver
0x27fb smGameplayPause
0x27fc smGameplayResume
0x27ff smTweetConsume
0x2800 smHeroLoanedOut
0x2801 smSetupAcademyMatch
0x2802 smSetupAcademyTeams
0x2803 smStartIntroFlow
0x2804 smStartSeason
0x2805 smPlayMatch
0x2806 smEndMatch
0x2807 smGetTrainingSet
0x2808 smEnterTrainingTeamHub
0x2809 smEnterTraining
0x280a smPlayTrainingSessionVO
0x280b smPrepareTraining
0x280c smPlayTraining
0x280d smStopTraining
0x280e smStartSkillGame
0x280f smSimTraining
0x2810 smEndTraining
0x2811 smSave
0x2812 smAutoSave
0x2814 smLoad
0x2815 smSetScreenFlowLocation
0x2816 smGetScreenFlowLocation
0x2817 smGetHomeHubLocation
0x2818 smGetHeroLeague
0x2819 smCompleteMatchday
0x281a smEndInterviewPeriod
0x281b smHeroRemovedFromMatch
0x281c smEpisodicUploadCheck
0x281d smRetryEpisodicUpload
0x281e smNotifyMatchNotPlayed
0x281f matchFlowStart
0x2820 matchFlowHalftime
0x2821 matchFlowPostgame
0x2822 matchFlowEnd
0x2823 enterGameplay
0x2824 leaveGameplay
0x2825 forfeitMatch
0x2826 matchSetType
0x2827 simMatch
0x2828 simStarted
0x2829 simStopped
0x282a fbStartFlowEvent
0x282b stopSavedInput
0x282c changeSonyStoreBrowseMode
0x282d trialCheck
0x282e gotoTrialUpsell
0x754d retrieveManagerQuestData
0x7560 futWidgetShow
0x7561 futWidgetHide
0x7562 futWidgetLoad
0x7563 futWidgetUnload
0x7567 inviteAcceptedFUT
0x7568 futAddCriticalSection
0x7569 futRemoveCriticalSection
0x7572 exitDraftMode
0x7579 useSavedMatchData
0x757a useSavedMatchKits
0x7580 exitSbcMode
0x7587 setFUTServerEnvironment
0x9cc1 discardTeamSheet
0x9cc1 resetReady
0x9cd0 showKeyboard
-4
View File
@@ -1,4 +0,0 @@
# Raw /proc/PID/mem captures: regenerate with tools/db_dump.py, never commit.
# One of these directories reached 2.3GB.
data/memdump/*.bin
data/memdump/*.raw
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
-61
View File
@@ -1,61 +0,0 @@
{
"20801": 27,
"41236": 25,
"48717": 0,
"48940": 0,
"52091": 7,
"53612": 5,
"53914": 5,
"106231": 25,
"108080": 3,
"112253": 10,
"120533": 5,
"121944": 14,
"137186": 5,
"138956": 5,
"139668": 0,
"139720": 5,
"139968": 0,
"142780": 5,
"142784": 3,
"143745": 14,
"146530": 3,
"146562": 18,
"146954": 14,
"150724": 0,
"152729": 5,
"153244": 25,
"156616": 16,
"157481": 5,
"158121": 0,
"159147": 5,
"161648": 18,
"162240": 14,
"162895": 14,
"163711": 10,
"165153": 25,
"167431": 14,
"168354": 0,
"168651": 14,
"171877": 14,
"172879": 5,
"175943": 27,
"176769": 25,
"177413": 14,
"177610": 5,
"178509": 25,
"179783": 0,
"179944": 5,
"181458": 16,
"182494": 0,
"183497": 0,
"184144": 16,
"184432": 7,
"185239": 5,
"188152": 18,
"189125": 16,
"189461": 14,
"189560": 10,
"190547": 5,
"191740": 14
}
-19
View File
@@ -1,19 +0,0 @@
{
"155862": "CB",
"158023": "RW",
"167495": "GK",
"176580": "ST",
"177003": "CM",
"182521": "CM",
"183277": "LM",
"183907": "CB",
"184941": "CB",
"188545": "ST",
"189332": "LB",
"190871": "LW",
"192985": "RM",
"197445": "LB",
"200389": "GK",
"202126": "ST",
"20801": "LW"
}
File diff suppressed because it is too large Load Diff
@@ -1 +0,0 @@
{"table":"BigAttendance","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":7,"rowsize_bytes":4,"rows_emitted":7,"rowblock":"0x7be0210","rowblock_bytes":104,"descriptor":"0x7bf0848","schema":[{"name":"max","bit":0,"width":4,"kind":"int","min":0,"max":10,"storage":"int"},{"name":"emotion","bit":4,"width":3,"kind":"int","min":0,"max":6,"storage":"int"},{"name":"min","bit":7,"width":4,"kind":"int","min":0,"max":10,"storage":"int"}],"rows":[{"max":6,"emotion":0,"min":0},{"max":6,"emotion":1,"min":0},{"max":7,"emotion":2,"min":0},{"max":7,"emotion":3,"min":0},{"max":10,"emotion":4,"min":1},{"max":9,"emotion":5,"min":1},{"max":9,"emotion":6,"min":1}]}
@@ -1 +0,0 @@
{"table":"MatchIntensity","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":9,"rowsize_bytes":4,"rows_emitted":9,"rowblock":"0x7c31058","rowblock_bytes":0,"descriptor":"0x42e9a3a8","schema":[{"name":"scorediff","bit":0,"width":4,"kind":"int","min":-4,"max":4,"storage":"int"},{"name":"time60","bit":4,"width":2,"kind":"int","min":-1,"max":2,"storage":"int"},{"name":"time90","bit":6,"width":2,"kind":"int","min":-1,"max":2,"storage":"int"},{"name":"time120","bit":8,"width":3,"kind":"int","min":-1,"max":3,"storage":"int"},{"name":"time75","bit":11,"width":3,"kind":"int","min":-1,"max":3,"storage":"int"},{"name":"time45","bit":14,"width":2,"kind":"int","min":-1,"max":2,"storage":"int"},{"name":"time30","bit":16,"width":2,"kind":"int","min":-1,"max":2,"storage":"int"},{"name":"time15","bit":18,"width":2,"kind":"int","min":-1,"max":2,"storage":"int"}],"rows":[{"scorediff":-4,"time60":-1,"time90":-1,"time120":-1,"time75":-1,"time45":-1,"time30":-1,"time15":-1},{"scorediff":-3,"time60":0,"time90":-1,"time120":-1,"time75":0,"time45":0,"time30":-1,"time15":-1},{"scorediff":-2,"time60":1,"time90":-1,"time120":0,"time75":0,"time45":0,"time30":0,"time15":-1},{"scorediff":-1,"time60":-1,"time90":2,"time120":3,"time75":3,"time45":1,"time30":0,"time15":1},{"scorediff":0,"time60":-1,"time90":2,"time120":3,"time75":3,"time45":0,"time30":-1,"time15":0},{"scorediff":1,"time60":0,"time90":1,"time120":2,"time75":2,"time45":1,"time30":0,"time15":1},{"scorediff":2,"time60":0,"time90":0,"time120":0,"time75":1,"time45":1,"time30":1,"time15":2},{"scorediff":3,"time60":-1,"time90":0,"time120":0,"time75":0,"time45":-1,"time30":-1,"time15":0},{"scorediff":4,"time60":0,"time90":0,"time120":-1,"time75":-1,"time45":0,"time30":-1,"time15":-1}]}
@@ -1 +0,0 @@
{"table":"NoAttendance","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":7,"rowsize_bytes":4,"rows_emitted":7,"rowblock":"0x7be01e8","rowblock_bytes":114,"descriptor":"0x7bf0f08","schema":[{"name":"max","bit":0,"width":4,"kind":"int","min":0,"max":10,"storage":"int"},{"name":"emotion","bit":4,"width":3,"kind":"int","min":0,"max":6,"storage":"int"},{"name":"min","bit":7,"width":4,"kind":"int","min":0,"max":10,"storage":"int"}],"rows":[{"max":7,"emotion":0,"min":0},{"max":8,"emotion":1,"min":0},{"max":9,"emotion":2,"min":0},{"max":9,"emotion":3,"min":0},{"max":10,"emotion":4,"min":1},{"max":9,"emotion":5,"min":1},{"max":8,"emotion":6,"min":0}]}
@@ -1 +0,0 @@
{"table":"assetcryptokeys","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":44,"rows_emitted":0,"rowblock":"0x42750c68","rowblock_bytes":3553,"descriptor":"0x7bf0e48","schema":[{"name":"key","bit":0,"width":256,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"keyid","bit":256,"width":64,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"artificialkey","bit":320,"width":7,"kind":"int","min":0,"max":127,"storage":"int"}],"rows":[]}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
{"table":"audiostadium","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":86,"rowsize_bytes":4,"rows_emitted":86,"rowblock":"0x42e9a4c8","rowblock_bytes":369,"descriptor":"0x7b57908","schema":[{"name":"stadiumpalanguageindex","bit":0,"width":6,"kind":"int","min":-1,"max":31,"storage":"int"},{"name":"stadiumid","bit":6,"width":9,"kind":"int","min":0,"max":511,"storage":"int"}],"rows":[{"stadiumpalanguageindex":0,"stadiumid":1},{"stadiumpalanguageindex":4,"stadiumid":2},{"stadiumpalanguageindex":3,"stadiumid":5},{"stadiumpalanguageindex":2,"stadiumid":9},{"stadiumpalanguageindex":4,"stadiumid":10},{"stadiumpalanguageindex":0,"stadiumid":13},{"stadiumpalanguageindex":1,"stadiumid":14},{"stadiumpalanguageindex":7,"stadiumid":15},{"stadiumpalanguageindex":-1,"stadiumid":26},{"stadiumpalanguageindex":0,"stadiumid":28},{"stadiumpalanguageindex":1,"stadiumid":29},{"stadiumpalanguageindex":2,"stadiumid":30},{"stadiumpalanguageindex":-1,"stadiumid":32},{"stadiumpalanguageindex":-1,"stadiumid":33},{"stadiumpalanguageindex":-1,"stadiumid":34},{"stadiumpalanguageindex":-1,"stadiumid":35},{"stadiumpalanguageindex":2,"stadiumid":41},{"stadiumpalanguageindex":4,"stadiumid":42},{"stadiumpalanguageindex":0,"stadiumid":100},{"stadiumpalanguageindex":13,"stadiumid":104},{"stadiumpalanguageindex":0,"stadiumid":112},{"stadiumpalanguageindex":0,"stadiumid":113},{"stadiumpalanguageindex":0,"stadiumid":115},{"stadiumpalanguageindex":0,"stadiumid":116},{"stadiumpalanguageindex":2,"stadiumid":135},{"stadiumpalanguageindex":2,"stadiumid":137},{"stadiumpalanguageindex":-1,"stadiumid":147},{"stadiumpalanguageindex":-1,"stadiumid":149},{"stadiumpalanguageindex":-1,"stadiumid":153},{"stadiumpalanguageindex":0,"stadiumid":155},{"stadiumpalanguageindex":0,"stadiumid":156},{"stadiumpalanguageindex":3,"stadiumid":157},{"stadiumpalanguageindex":-1,"stadiumid":158},{"stadiumpalanguageindex":-1,"stadiumid":172},{"stadiumpalanguageindex":-1,"stadiumid":175},{"stadiumpalanguageindex":-1,"stadiumid":176},{"stadiumpalanguageindex":-1,"stadiumid":178},{"stadiumpalanguageindex":-1,"stadiumid":179},{"stadiumpalanguageindex":-1,"stadiumid":180},{"stadiumpalanguageindex":-1,"stadiumid":181},{"stadiumpalanguageindex":-1,"stadiumid":182},{"stadiumpalanguageindex":-1,"stadiumid":183},{"stadiumpalanguageindex":-1,"stadiumid":192},{"stadiumpalanguageindex":-1,"stadiumid":193},{"stadiumpalanguageindex":-1,"stadiumid":194},{"stadiumpalanguageindex":-1,"stadiumid":195},{"stadiumpalanguageindex":-1,"stadiumid":196},{"stadiumpalanguageindex":-1,"stadiumid":197},{"stadiumpalanguageindex":-1,"stadiumid":212},{"stadiumpalanguageindex":-1,"stadiumid":228},{"stadiumpalanguageindex":-1,"stadiumid":229},{"stadiumpalanguageindex":0,"stadiumid":246},{"stadiumpalanguageindex":3,"stadiumid":247},{"stadiumpalanguageindex":0,"stadiumid":248},{"stadiumpalanguageindex":-1,"stadiumid":249},{"stadiumpalanguageindex":0,"stadiumid":260},{"stadiumpalanguageindex":-1,"stadiumid":261},{"stadiumpalanguageindex":-1,"stadiumid":262},{"stadiumpalanguageindex":14,"stadiumid":264},{"stadiumpalanguageindex":0,"stadiumid":265},{"stadiumpalanguageindex":-1,"stadiumid":316},{"stadiumpalanguageindex":0,"stadiumid":326},{"stadiumpalanguageindex":0,"stadiumid":327},{"stadiumpalanguageindex":0,"stadiumid":329},{"stadiumpalanguageindex":0,"stadiumid":330},{"stadiumpalanguageindex":0,"stadiumid":331},{"stadiumpalanguageindex":0,"stadiumid":332},{"stadiumpalanguageindex":0,"stadiumid":333},{"stadiumpalanguageindex":0,"stadiumid":335},{"stadiumpalanguageindex":0,"stadiumid":336},{"stadiumpalanguageindex":0,"stadiumid":337},{"stadiumpalanguageindex":0,"stadiumid":341},{"stadiumpalanguageindex":2,"stadiumid":343},{"stadiumpalanguageindex":14,"stadiumid":344},{"stadiumpalanguageindex":-1,"stadiumid":345},{"stadiumpalanguageindex":0,"stadiumid":347},{"stadiumpalanguageindex":0,"stadiumid":348},{"stadiumpalanguageindex":0,"stadiumid":349},{"stadiumpalanguageindex":-1,"stadiumid":352},{"stadiumpalanguageindex":-1,"stadiumid":353},{"stadiumpalanguageindex":17,"stadiumid":354},{"stadiumpalanguageindex":0,"stadiumid":355},{"stadiumpalanguageindex":-1,"stadiumid":357},{"stadiumpalanguageindex":-1,"stadiumid":358},{"stadiumpalanguageindex":-1,"stadiumid":359},{"stadiumpalanguageindex":-1,"stadiumid":360}]}
@@ -1 +0,0 @@
{"table":"career_calendar","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":1,"rowsize_bytes":20,"rows_emitted":1,"rowblock":"0x7c20708","rowblock_bytes":0,"descriptor":"0x4254fc28","schema":[{"name":"transferwindowend1","bit":0,"width":11,"kind":"int","min":101,"max":1231,"storage":"int"},{"name":"transferwindowstart1","bit":11,"width":11,"kind":"int","min":101,"max":1231,"storage":"int"},{"name":"transferwindowend2","bit":22,"width":11,"kind":"int","min":101,"max":1231,"storage":"int"},{"name":"setupdate","bit":33,"width":19,"kind":"int","min":20080101,"max":20601231,"storage":"int"},{"name":"dateid","bit":52,"width":1,"kind":"int","min":0,"max":1,"storage":"int"},{"name":"enddate","bit":53,"width":19,"kind":"int","min":20080101,"max":20601231,"storage":"int"},{"name":"currdate","bit":72,"width":19,"kind":"int","min":20080101,"max":20601231,"storage":"int"},{"name":"startdate","bit":91,"width":19,"kind":"int","min":20080101,"max":20601231,"storage":"int"},{"name":"transferwindowstart2","bit":110,"width":11,"kind":"int","min":101,"max":1231,"storage":"int"},{"name":"objectivecheckdate","bit":121,"width":19,"kind":"int","min":20080101,"max":20601231,"storage":"int"}],"rows":[{"transferwindowend1":831,"transferwindowstart1":701,"transferwindowend2":131,"setupdate":20080101,"dateid":0,"enddate":20080101,"currdate":20080101,"startdate":20080101,"transferwindowstart2":101,"objectivecheckdate":20080101}]}
@@ -1 +0,0 @@
{"table":"career_clinchedobjectives","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":20,"rows_emitted":0,"rowblock":"0x42e982a8","rowblock_bytes":513,"descriptor":"0x7b102a8","schema":[{"name":"predictedclinchfordrawflags","bit":0,"width":31,"kind":"int","min":0,"max":2147483520,"storage":"int"},{"name":"clinchedobjectivesflags","bit":31,"width":31,"kind":"int","min":0,"max":2147483520,"storage":"int"},{"name":"predictedclinchforwinflags","bit":62,"width":31,"kind":"int","min":0,"max":2147483520,"storage":"int"},{"name":"teamid","bit":93,"width":18,"kind":"int","min":-1,"max":200000,"storage":"int"},{"name":"predictedclinchforlossflags","bit":111,"width":31,"kind":"int","min":0,"max":2147483520,"storage":"int"}],"rows":[]}
@@ -1 +0,0 @@
{"table":"career_commonnames","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":8,"rows_emitted":0,"rowblock":"0x0","rowblock_bytes":null,"descriptor":"0x7b408f8","schema":[{"name":"firstname","bit":0,"width":15,"kind":"int","min":0,"max":29999,"storage":"int"},{"name":"lastname","bit":15,"width":15,"kind":"int","min":0,"max":29999,"storage":"int"},{"name":"groupid","bit":30,"width":7,"kind":"int","min":0,"max":127,"storage":"int"},{"name":"commonnameid","bit":37,"width":10,"kind":"int","min":1,"max":1024,"storage":"int"}],"rows":[]}
@@ -1 +0,0 @@
{"table":"career_firstnames","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":8,"rows_emitted":0,"rowblock":"0x0","rowblock_bytes":null,"descriptor":"0x7bf0c08","schema":[{"name":"firstnameid","bit":0,"width":12,"kind":"int","min":1,"max":4096,"storage":"int"},{"name":"firstname","bit":12,"width":15,"kind":"int","min":0,"max":29999,"storage":"int"},{"name":"groupid","bit":27,"width":7,"kind":"int","min":0,"max":127,"storage":"int"}],"rows":[]}
@@ -1 +0,0 @@
{"table":"career_lastnames","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":8,"rows_emitted":0,"rowblock":"0x0","rowblock_bytes":null,"descriptor":"0x7bf12c8","schema":[{"name":"lastname","bit":0,"width":15,"kind":"int","min":0,"max":29999,"storage":"int"},{"name":"lastnameid","bit":15,"width":12,"kind":"int","min":1,"max":4096,"storage":"int"},{"name":"groupid","bit":27,"width":7,"kind":"int","min":0,"max":127,"storage":"int"}],"rows":[]}
@@ -1 +0,0 @@
{"table":"career_playerlastmatchhistory","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":12,"rows_emitted":0,"rowblock":"0x42521898","rowblock_bytes":120033,"descriptor":"0x7ba3408","schema":[{"name":"minsplayed","bit":0,"width":8,"kind":"int","min":0,"max":150,"storage":"int"},{"name":"position","bit":8,"width":6,"kind":"int","min":-1,"max":50,"storage":"int"},{"name":"artificialkey","bit":14,"width":19,"kind":"int","min":0,"max":300000,"storage":"int"},{"name":"playerfact","bit":33,"width":5,"kind":"int","min":-1,"max":15,"storage":"int"},{"name":"teamid","bit":38,"width":18,"kind":"int","min":-1,"max":200000,"storage":"int"},{"name":"playeroverall","bit":56,"width":7,"kind":"int","min":-1,"max":100,"storage":"int"},{"name":"playerid","bit":63,"width":19,"kind":"int","min":-1,"max":300000,"storage":"int"}],"rows":[]}
@@ -1 +0,0 @@
{"table":"career_playermatchratinghistory","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":12,"rows_emitted":0,"rowblock":"0x42493f28","rowblock_bytes":7585,"descriptor":"0x7b205a8","schema":[{"name":"minsplayed","bit":0,"width":8,"kind":"int","min":-1,"max":140,"storage":"int"},{"name":"position","bit":8,"width":5,"kind":"int","min":0,"max":31,"storage":"int"},{"name":"date","bit":13,"width":19,"kind":"int","min":20080101,"max":20601231,"storage":"int"},{"name":"artificialkey","bit":32,"width":19,"kind":"int","min":0,"max":300000,"storage":"int"},{"name":"rating","bit":51,"width":7,"kind":"int","min":-1,"max":100,"storage":"int"},{"name":"playerid","bit":58,"width":19,"kind":"int","min":0,"max":300000,"storage":"int"}],"rows":[]}
@@ -1 +0,0 @@
{"table":"career_squadranking","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":8,"rows_emitted":0,"rowblock":"0x42e97c18","rowblock_bytes":449,"descriptor":"0x7bf0488","schema":[{"name":"curroverall","bit":0,"width":10,"kind":"int","min":0,"max":1000,"storage":"int"},{"name":"playerid","bit":10,"width":19,"kind":"int","min":-1,"max":300000,"storage":"int"},{"name":"lastoverall","bit":29,"width":10,"kind":"int","min":0,"max":1000,"storage":"int"}],"rows":[]}
@@ -1 +0,0 @@
{"table":"celebrations","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":13,"rowsize_bytes":4,"rows_emitted":13,"rowblock":"0x7bc3088","rowblock_bytes":5,"descriptor":"0x7b701e8","schema":[{"name":"celebrationid","bit":0,"width":4,"kind":"int","min":0,"max":13,"storage":"int"}],"rows":[{"celebrationid":0},{"celebrationid":1},{"celebrationid":2},{"celebrationid":3},{"celebrationid":4},{"celebrationid":5},{"celebrationid":6},{"celebrationid":7},{"celebrationid":8},{"celebrationid":9},{"celebrationid":10},{"celebrationid":11},{"celebrationid":12}]}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
{"table":"customteamstyles","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":12,"rows_emitted":0,"rowblock":"0x4254bdf8","rowblock_bytes":369,"descriptor":"0x42816ee8","schema":[{"name":"defmentality","bit":0,"width":7,"kind":"int","min":1,"max":100,"storage":"int"},{"name":"teamstyleid","bit":7,"width":7,"kind":"int","min":900,"max":1000,"storage":"int"},{"name":"basestyle","bit":14,"width":18,"kind":"int","min":-2,"max":200000,"storage":"int"},{"name":"buspassing","bit":32,"width":7,"kind":"int","min":1,"max":100,"storage":"int"},{"name":"defteamwidth","bit":39,"width":7,"kind":"int","min":1,"max":100,"storage":"int"},{"name":"busdribbling","bit":46,"width":7,"kind":"int","min":1,"max":100,"storage":"int"},{"name":"defaggression","bit":53,"width":7,"kind":"int","min":1,"max":100,"storage":"int"},{"name":"buspositioning","bit":60,"width":1,"kind":"int","min":1,"max":2,"storage":"int"},{"name":"ccpositioning","bit":61,"width":1,"kind":"int","min":1,"max":2,"storage":"int"},{"name":"busbuildupspeed","bit":62,"width":7,"kind":"int","min":1,"max":100,"storage":"int"},{"name":"ccshooting","bit":69,"width":7,"kind":"int","min":1,"max":100,"storage":"int"},{"name":"ccpassing","bit":76,"width":7,"kind":"int","min":1,"max":100,"storage":"int"},{"name":"defdefenderline","bit":83,"width":1,"kind":"int","min":1,"max":2,"storage":"int"},{"name":"cccrossing","bit":84,"width":7,"kind":"int","min":1,"max":100,"storage":"int"}],"rows":[]}
-1
View File
@@ -1 +0,0 @@
{"table":"cz_assets","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":248,"rows_emitted":0,"rowblock":"0x427ce458","rowblock_bytes":26817,"descriptor":"0x4254ffa8","schema":[{"name":"crestid","bit":0,"width":32,"kind":"int","min":-2147483648,"max":2147483647,"storage":"int"},{"name":"dbid","bit":32,"width":32,"kind":"int","min":-2147483648,"max":2147483647,"storage":"int"},{"name":"publishdate","bit":64,"width":32,"kind":"int","min":-2147483648,"max":2147483647,"storage":"int"},{"name":"rating","bit":96,"width":32,"kind":"unknown","min":0,"max":0,"storage":"int"},{"name":"kitid","bit":128,"width":32,"kind":"int","min":-2147483648,"max":2147483647,"storage":"int"},{"name":"xms_media_id","bit":160,"width":32,"kind":"int","min":-2147483648,"max":2147483647,"storage":"int"},{"name":"type","bit":192,"width":32,"kind":"int","min":-2147483648,"max":2147483647,"storage":"int"},{"name":"author","bit":224,"width":720,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"assetname","bit":944,"width":1008,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"assetyear","bit":1952,"width":4,"kind":"int","min":0,"max":15,"storage":"int"},{"name":"playerposition","bit":1956,"width":6,"kind":"int","min":0,"max":50,"storage":"int"},{"name":"version","bit":1962,"width":15,"kind":"int","min":0,"max":30000,"storage":"int"}],"rows":[]}
-1
View File
@@ -1 +0,0 @@
{"table":"cz_leagues","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":164,"rows_emitted":0,"rowblock":"0x424a1908","rowblock_bytes":849,"descriptor":"0x424af898","schema":[{"name":"overlaybgcolour3r","bit":0,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"tournamentballid","bit":8,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaytextcolour3r","bit":16,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaytextcolour1g","bit":24,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaytextcolour3b","bit":32,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaybgcolour1g","bit":40,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"championcupslotallotment","bit":48,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaybgcolour3b","bit":56,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"finalstadiumid","bit":64,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaytextcolour2b","bit":72,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaybgcolour1r","bit":80,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaybgcolour2b","bit":88,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaytextcolour1r","bit":96,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaytextcolour3g","bit":104,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaytextcolour1b","bit":112,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaybgcolour3g","bit":120,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaybgcolour1b","bit":128,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaybgcolour2r","bit":136,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaytextcolour2g","bit":144,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"eurocupslotallotment","bit":152,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaytextcolour2r","bit":160,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"overlaybgcolour2g","bit":168,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"leaguedescription","bit":176,"width":1080,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"leaguetype","bit":1256,"width":2,"kind":"int","min":0,"max":2,"storage":"int"},{"name":"numteams","bit":1258,"width":6,"kind":"int","min":0,"max":32,"storage":"int"},{"name":"trophyid","bit":1264,"width":9,"kind":"int","min":-1,"max":255,"storage":"int"},{"name":"teamadvancingpergroup","bit":1273,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"leagueid","bit":1276,"width":12,"kind":"int","min":1,"max":3000,"storage":"int"},{"name":"fixturevsgroup","bit":1288,"width":2,"kind":"int","min":0,"max":2,"storage":"int"},{"name":"teampergroup","bit":1290,"width":5,"kind":"int","min":0,"max":16,"storage":"int"},{"name":"finalmatchlegs","bit":1295,"width":2,"kind":"int","min":0,"max":2,"storage":"int"},{"name":"fixturevseachteam","bit":1297,"width":2,"kind":"int","min":0,"max":2,"storage":"int"},{"name":"subonbench","bit":1299,"width":3,"kind":"int","min":0,"max":7,"storage":"int"}],"rows":[]}
-1
View File
@@ -1 +0,0 @@
{"table":"cz_players","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":8,"rows_emitted":0,"rowblock":"0x42614398","rowblock_bytes":12033,"descriptor":"0x7bf0608","schema":[{"name":"assetid","bit":0,"width":19,"kind":"int","min":0,"max":300000,"storage":"int"},{"name":"commentaryid","bit":19,"width":20,"kind":"int","min":-1,"max":1000000,"storage":"int"},{"name":"playerid","bit":39,"width":19,"kind":"int","min":0,"max":300000,"storage":"int"}],"rows":[]}
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
{"table":"cz_teams","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":24,"rows_emitted":0,"rowblock":"0x4254c208","rowblock_bytes":1473,"descriptor":"0x7b110a8","schema":[{"name":"hascrestimage","bit":0,"width":32,"kind":"int","min":-2147483648,"max":2147483647,"storage":"int"},{"name":"hassponsorimage","bit":32,"width":32,"kind":"int","min":-2147483648,"max":2147483647,"storage":"int"},{"name":"teamabbrev3","bit":64,"width":72,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"teamid","bit":136,"width":18,"kind":"int","min":0,"max":200000,"storage":"int"},{"name":"commentaryid","bit":154,"width":20,"kind":"int","min":-1,"max":1000000,"storage":"int"}],"rows":[]}
@@ -1 +0,0 @@
{"table":"dcplayernames","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":40,"rows_emitted":0,"rowblock":"0x426df378","rowblock_bytes":200032,"descriptor":"0x7b579b8","schema":[{"name":"name","bit":0,"width":304,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"nameid","bit":304,"width":13,"kind":"int","min":30000,"max":35000,"storage":"int"}],"rows":[]}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
{"table":"dlcballs","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":52,"rows_emitted":0,"rowblock":"0x424a0528","rowblock_bytes":2625,"descriptor":"0x7b576f8","schema":[{"name":"name","bit":0,"width":400,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"assetid","bit":400,"width":11,"kind":"int","min":0,"max":2000,"storage":"int"}],"rows":[]}
-1
View File
@@ -1 +0,0 @@
{"table":"dlcboots","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":52,"rows_emitted":0,"rowblock":"0x424980e8","rowblock_bytes":2624,"descriptor":"0x7b57dd8","schema":[{"name":"name","bit":0,"width":400,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"assetid","bit":400,"width":11,"kind":"int","min":0,"max":2000,"storage":"int"}],"rows":[]}
-1
View File
@@ -1 +0,0 @@
{"table":"dna","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":260,"rows_emitted":0,"rowblock":"0x0","rowblock_bytes":null,"descriptor":"0x7b57b18","schema":[{"name":"dna","bit":0,"width":2040,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"playerid","bit":2040,"width":19,"kind":"int","min":0,"max":300000,"storage":"int"}],"rows":[]}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
{"table":"editedplayernames","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":0,"rowsize_bytes":184,"rows_emitted":0,"rowblock":"0x42a7f108","rowblock_bytes":281553,"descriptor":"0x7b10b68","schema":[{"name":"firstname","bit":0,"width":360,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"commonname","bit":360,"width":360,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"playerjerseyname","bit":720,"width":360,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"surname","bit":1080,"width":360,"kind":"string","min":0,"max":0,"storage":"inline-string"},{"name":"playerid","bit":1440,"width":19,"kind":"int","min":0,"max":300000,"storage":"int"}],"rows":[]}
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
{"table":"fcc_GrandStandPlayers","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":113,"rowsize_bytes":4,"rows_emitted":113,"rowblock":"0x424b4358","rowblock_bytes":481,"descriptor":"0x7988528","schema":[{"name":"playerid","bit":0,"width":19,"kind":"int","min":0,"max":300000,"storage":"int"}],"rows":[{"playerid":1},{"playerid":41},{"playerid":51},{"playerid":195},{"playerid":240},{"playerid":241},{"playerid":244},{"playerid":246},{"playerid":388},{"playerid":393},{"playerid":570},{"playerid":805},{"playerid":942},{"playerid":1025},{"playerid":1040},{"playerid":1041},{"playerid":1075},{"playerid":1088},{"playerid":1109},{"playerid":1116},{"playerid":1183},{"playerid":1198},{"playerid":1201},{"playerid":1419},{"playerid":1605},{"playerid":1620},{"playerid":1845},{"playerid":4000},{"playerid":4202},{"playerid":4833},{"playerid":5419},{"playerid":5467},{"playerid":5589},{"playerid":5673},{"playerid":5680},{"playerid":5681},{"playerid":6235},{"playerid":6975},{"playerid":7289},{"playerid":7512},{"playerid":7518},{"playerid":7743},{"playerid":9014},{"playerid":10264},{"playerid":13038},{"playerid":13128},{"playerid":20170},{"playerid":20801},{"playerid":41236},{"playerid":46747},{"playerid":51539},{"playerid":52241},{"playerid":53769},{"playerid":117106},{"playerid":121939},{"playerid":146530},{"playerid":153079},{"playerid":155862},{"playerid":156353},{"playerid":156616},{"playerid":158023},{"playerid":161840},{"playerid":162895},{"playerid":164000},{"playerid":164240},{"playerid":166120},{"playerid":166124},{"playerid":166906},{"playerid":167495},{"playerid":168473},{"playerid":168542},{"playerid":173731},{"playerid":176580},{"playerid":176635},{"playerid":176676},{"playerid":177003},{"playerid":177845},{"playerid":181872},{"playerid":182521},{"playerid":183277},{"playerid":183898},{"playerid":183907},{"playerid":184941},{"playerid":188350},{"playerid":188545},{"playerid":189332},{"playerid":189511},{"playerid":190043},{"playerid":190044},{"playerid":190053},{"playerid":190871},{"playerid":191189},{"playerid":191695},{"playerid":192119},{"playerid":192181},{"playerid":192883},{"playerid":192985},{"playerid":193080},{"playerid":195864},{"playerid":197445},{"playerid":198710},{"playerid":214098},{"playerid":214100},{"playerid":214101},{"playerid":214267},{"playerid":214649},{"playerid":215558},{"playerid":215732},{"playerid":222000},{"playerid":222257},{"playerid":222481},{"playerid":222680},{"playerid":226764}]}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
{"table":"fcc_bonusvalues","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":12,"rowsize_bytes":8,"rows_emitted":12,"rowblock":"0x77e13b8","rowblock_bytes":1919903238,"descriptor":"0x7b401a8","schema":[{"name":"bonusvalue","bit":0,"width":32,"kind":"unknown","min":0,"max":0,"storage":"int"},{"name":"bonuslevel","bit":32,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"bonustype","bit":40,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"bonusid","bit":48,"width":8,"kind":"int","min":0,"max":255,"storage":"int"}],"rows":[{"bonusvalue":0,"bonuslevel":0,"bonustype":0,"bonusid":0},{"bonusvalue":1065353216,"bonuslevel":1,"bonustype":0,"bonusid":1},{"bonusvalue":1073741824,"bonuslevel":2,"bonustype":0,"bonusid":2},{"bonusvalue":1077936128,"bonuslevel":3,"bonustype":0,"bonusid":3},{"bonusvalue":1065353216,"bonuslevel":0,"bonustype":1,"bonusid":4},{"bonusvalue":1067450368,"bonuslevel":1,"bonustype":1,"bonusid":5},{"bonusvalue":1069547520,"bonuslevel":2,"bonustype":1,"bonusid":6},{"bonusvalue":1073741824,"bonuslevel":3,"bonustype":1,"bonusid":7},{"bonusvalue":0,"bonuslevel":0,"bonustype":3,"bonusid":8},{"bonusvalue":1065353216,"bonuslevel":1,"bonustype":3,"bonusid":9},{"bonusvalue":1077936128,"bonuslevel":2,"bonustype":3,"bonusid":10},{"bonusvalue":1084227584,"bonuslevel":3,"bonustype":3,"bonusid":11}]}
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
{"table":"fcc_coinrewards","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":17,"rowsize_bytes":8,"rows_emitted":17,"rowblock":"0x79883e8","rowblock_bytes":0,"descriptor":"0x7b40758","schema":[{"name":"leaderboard","bit":0,"width":12,"kind":"int","min":-1024,"max":1024,"storage":"int"},{"name":"coin","bit":12,"width":12,"kind":"int","min":-1024,"max":1024,"storage":"int"},{"name":"cap","bit":24,"width":7,"kind":"int","min":0,"max":100,"storage":"int"},{"name":"objectiveid","bit":31,"width":7,"kind":"int","min":1,"max":100,"storage":"int"}],"rows":[{"leaderboard":500,"coin":40,"cap":5,"objectiveid":1},{"leaderboard":500,"coin":5,"cap":10,"objectiveid":2},{"leaderboard":500,"coin":1,"cap":25,"objectiveid":3},{"leaderboard":500,"coin":5,"cap":10,"objectiveid":4},{"leaderboard":500,"coin":75,"cap":1,"objectiveid":5},{"leaderboard":500,"coin":1,"cap":80,"objectiveid":6},{"leaderboard":500,"coin":1,"cap":60,"objectiveid":7},{"leaderboard":500,"coin":15,"cap":1,"objectiveid":8},{"leaderboard":-500,"coin":-20,"cap":3,"objectiveid":9},{"leaderboard":-500,"coin":-5,"cap":5,"objectiveid":10},{"leaderboard":-500,"coin":-10,"cap":5,"objectiveid":11},{"leaderboard":-500,"coin":-40,"cap":5,"objectiveid":12},{"leaderboard":-500,"coin":-1,"cap":10,"objectiveid":13},{"leaderboard":500,"coin":0,"cap":0,"objectiveid":15},{"leaderboard":500,"coin":325,"cap":1,"objectiveid":16},{"leaderboard":-500,"coin":0,"cap":0,"objectiveid":17},{"leaderboard":500,"coin":0,"cap":0,"objectiveid":18}]}
@@ -1 +0,0 @@
{"table":"fcc_contractcards","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":13,"rowsize_bytes":16,"rows_emitted":13,"rowblock":"0x7b10ee8","rowblock_bytes":13,"descriptor":"0x42814a68","schema":[{"name":"carddbid","bit":0,"width":31,"kind":"int","min":0,"max":2001001001,"storage":"int"},{"name":"cardsubtype","bit":31,"width":14,"kind":"int","min":0,"max":10000,"storage":"int"},{"name":"weightrare","bit":45,"width":14,"kind":"int","min":0,"max":10000,"storage":"int"},{"name":"cardassetid","bit":59,"width":14,"kind":"int","min":0,"max":10000,"storage":"int"},{"name":"gold","bit":73,"width":7,"kind":"int","min":0,"max":100,"storage":"int"},{"name":"rating","bit":80,"width":7,"kind":"int","min":0,"max":100,"storage":"int"},{"name":"bronze","bit":87,"width":7,"kind":"int","min":0,"max":100,"storage":"int"},{"name":"silver","bit":94,"width":7,"kind":"int","min":0,"max":100,"storage":"int"}],"rows":[{"carddbid":5001001,"cardsubtype":201,"weightrare":0,"cardassetid":7,"gold":1,"rating":50,"bronze":8,"silver":2},{"carddbid":5001002,"cardsubtype":201,"weightrare":0,"cardassetid":7,"gold":8,"rating":65,"bronze":10,"silver":10},{"carddbid":5001003,"cardsubtype":201,"weightrare":0,"cardassetid":7,"gold":13,"rating":80,"bronze":15,"silver":11},{"carddbid":5001004,"cardsubtype":201,"weightrare":100,"cardassetid":7,"gold":3,"rating":60,"bronze":15,"silver":6},{"carddbid":5001005,"cardsubtype":201,"weightrare":100,"cardassetid":7,"gold":18,"rating":70,"bronze":20,"silver":24},{"carddbid":5001006,"cardsubtype":201,"weightrare":100,"cardassetid":7,"gold":28,"rating":90,"bronze":28,"silver":24},{"carddbid":5001007,"cardsubtype":202,"weightrare":0,"cardassetid":8,"gold":1,"rating":50,"bronze":8,"silver":2},{"carddbid":5001008,"cardsubtype":202,"weightrare":0,"cardassetid":8,"gold":8,"rating":65,"bronze":8,"silver":10},{"carddbid":5001009,"cardsubtype":202,"weightrare":0,"cardassetid":8,"gold":13,"rating":80,"bronze":11,"silver":11},{"carddbid":5001010,"cardsubtype":202,"weightrare":10,"cardassetid":8,"gold":3,"rating":60,"bronze":15,"silver":6},{"carddbid":5001011,"cardsubtype":202,"weightrare":10,"cardassetid":8,"gold":18,"rating":70,"bronze":18,"silver":24},{"carddbid":5001012,"cardsubtype":202,"weightrare":10,"cardassetid":8,"gold":28,"rating":90,"bronze":24,"silver":24},{"carddbid":5001013,"cardsubtype":201,"weightrare":0,"cardassetid":7,"gold":99,"rating":90,"bronze":99,"silver":99}]}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
{"table":"fcc_healingcards","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":27,"rowsize_bytes":12,"rows_emitted":27,"rowblock":"0x42814488","rowblock_bytes":353,"descriptor":"0x7b200f8","schema":[{"name":"carddbid","bit":0,"width":31,"kind":"int","min":0,"max":2001001001,"storage":"int"},{"name":"cardsubtype","bit":31,"width":14,"kind":"int","min":0,"max":10000,"storage":"int"},{"name":"weightrare","bit":45,"width":14,"kind":"int","min":0,"max":10000,"storage":"int"},{"name":"cardassetid","bit":59,"width":14,"kind":"int","min":0,"max":10000,"storage":"int"},{"name":"amount","bit":73,"width":7,"kind":"int","min":0,"max":100,"storage":"int"},{"name":"rating","bit":80,"width":7,"kind":"int","min":0,"max":100,"storage":"int"}],"rows":[{"carddbid":5002001,"cardsubtype":219,"weightrare":0,"cardassetid":10,"amount":20,"rating":55},{"carddbid":5002002,"cardsubtype":219,"weightrare":0,"cardassetid":10,"amount":40,"rating":70},{"carddbid":5002003,"cardsubtype":219,"weightrare":0,"cardassetid":10,"amount":60,"rating":80},{"carddbid":5002004,"cardsubtype":220,"weightrare":70,"cardassetid":10,"amount":10,"rating":55},{"carddbid":5002005,"cardsubtype":220,"weightrare":70,"cardassetid":10,"amount":20,"rating":70},{"carddbid":5002006,"cardsubtype":220,"weightrare":70,"cardassetid":10,"amount":30,"rating":80},{"carddbid":5002007,"cardsubtype":211,"weightrare":0,"cardassetid":9,"amount":1,"rating":55},{"carddbid":5002008,"cardsubtype":211,"weightrare":0,"cardassetid":9,"amount":2,"rating":70},{"carddbid":5002009,"cardsubtype":211,"weightrare":0,"cardassetid":9,"amount":5,"rating":80},{"carddbid":5002010,"cardsubtype":212,"weightrare":0,"cardassetid":9,"amount":1,"rating":55},{"carddbid":5002011,"cardsubtype":212,"weightrare":0,"cardassetid":9,"amount":2,"rating":70},{"carddbid":5002012,"cardsubtype":212,"weightrare":0,"cardassetid":9,"amount":5,"rating":80},{"carddbid":5002013,"cardsubtype":213,"weightrare":0,"cardassetid":9,"amount":1,"rating":55},{"carddbid":5002014,"cardsubtype":213,"weightrare":0,"cardassetid":9,"amount":2,"rating":70},{"carddbid":5002015,"cardsubtype":213,"weightrare":0,"cardassetid":9,"amount":5,"rating":80},{"carddbid":5002019,"cardsubtype":215,"weightrare":0,"cardassetid":9,"amount":1,"rating":55},{"carddbid":5002020,"cardsubtype":215,"weightrare":0,"cardassetid":9,"amount":2,"rating":70},{"carddbid":5002021,"cardsubtype":215,"weightrare":0,"cardassetid":9,"amount":5,"rating":80},{"carddbid":5002022,"cardsubtype":216,"weightrare":0,"cardassetid":9,"amount":1,"rating":55},{"carddbid":5002023,"cardsubtype":216,"weightrare":0,"cardassetid":9,"amount":2,"rating":70},{"carddbid":5002024,"cardsubtype":216,"weightrare":0,"cardassetid":9,"amount":5,"rating":80},{"carddbid":5002025,"cardsubtype":217,"weightrare":0,"cardassetid":9,"amount":1,"rating":55},{"carddbid":5002026,"cardsubtype":217,"weightrare":0,"cardassetid":9,"amount":2,"rating":70},{"carddbid":5002027,"cardsubtype":217,"weightrare":0,"cardassetid":9,"amount":5,"rating":80},{"carddbid":5002028,"cardsubtype":218,"weightrare":20,"cardassetid":9,"amount":1,"rating":60},{"carddbid":5002029,"cardsubtype":218,"weightrare":20,"cardassetid":9,"amount":2,"rating":74},{"carddbid":5002030,"cardsubtype":218,"weightrare":20,"cardassetid":9,"amount":4,"rating":85}]}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
{"table":"fcc_leagues","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":43,"rowsize_bytes":12,"rows_emitted":43,"rowblock":"0x428136d8","rowblock_bytes":545,"descriptor":"0x7b405b8","schema":[{"name":"leaguename","bit":0,"width":32,"kind":"string","min":0,"max":0,"storage":"offset-unresolved"},{"name":"leagueid","bit":32,"width":13,"kind":"int","min":0,"max":5000,"storage":"int"},{"name":"fifacountryid","bit":45,"width":13,"kind":"int","min":0,"max":5000,"storage":"int"},{"name":"futcountryid","bit":58,"width":13,"kind":"int","min":0,"max":5000,"storage":"int"}],"rows":[{"leaguename":236,"leagueid":1,"fifacountryid":13,"futcountryid":212},{"leaguename":250,"leagueid":4,"fifacountryid":7,"futcountryid":212},{"leaguename":269,"leagueid":7,"fifacountryid":54,"futcountryid":211},{"leaguename":290,"leagueid":10,"fifacountryid":34,"futcountryid":212},{"leaguename":305,"leagueid":13,"fifacountryid":14,"futcountryid":14},{"leaguename":321,"leagueid":14,"fifacountryid":14,"futcountryid":14},{"leaguename":342,"leagueid":16,"fifacountryid":18,"futcountryid":18},{"leaguename":354,"leagueid":17,"fifacountryid":18,"futcountryid":18},{"leaguename":366,"leagueid":19,"fifacountryid":21,"futcountryid":21},{"leaguename":383,"leagueid":20,"fifacountryid":21,"futcountryid":21},{"leaguename":401,"leagueid":31,"fifacountryid":27,"futcountryid":27},{"leaguename":413,"leagueid":32,"fifacountryid":27,"futcountryid":27},{"leaguename":425,"leagueid":39,"fifacountryid":95,"futcountryid":211},{"leaguename":443,"leagueid":41,"fifacountryid":36,"futcountryid":212},{"leaguename":458,"leagueid":50,"fifacountryid":42,"futcountryid":212},{"leaguename":474,"leagueid":53,"fifacountryid":45,"futcountryid":45},{"leaguename":491,"leagueid":54,"fifacountryid":45,"futcountryid":45},{"leaguename":504,"leagueid":56,"fifacountryid":46,"futcountryid":212},{"leaguename":519,"leagueid":60,"fifacountryid":14,"futcountryid":14},{"leaguename":534,"leagueid":61,"fifacountryid":14,"futcountryid":14},{"leaguename":549,"leagueid":63,"fifacountryid":22,"futcountryid":212},{"leaguename":564,"leagueid":65,"fifacountryid":25,"futcountryid":212},{"leaguename":586,"leagueid":66,"fifacountryid":37,"futcountryid":212},{"leaguename":608,"leagueid":67,"fifacountryid":40,"futcountryid":211},{"leaguename":624,"leagueid":68,"fifacountryid":48,"futcountryid":212},{"leaguename":639,"leagueid":78,"fifacountryid":75,"futcountryid":211},{"leaguename":648,"leagueid":80,"fifacountryid":4,"futcountryid":212},{"leaguename":663,"leagueid":83,"fifacountryid":167,"futcountryid":211},{"leaguename":681,"leagueid":189,"fifacountryid":47,"futcountryid":212},{"leaguename":699,"leagueid":308,"fifacountryid":38,"futcountryid":212},{"leaguename":714,"leagueid":322,"fifacountryid":17,"futcountryid":212},{"leaguename":731,"leagueid":332,"fifacountryid":49,"futcountryid":212},{"leaguename":746,"leagueid":335,"fifacountryid":55,"futcountryid":211},{"leaguename":772,"leagueid":336,"fifacountryid":56,"futcountryid":211},{"leaguename":788,"leagueid":341,"fifacountryid":83,"futcountryid":211},{"leaguename":802,"leagueid":347,"fifacountryid":140,"futcountryid":211},{"leaguename":820,"leagueid":349,"fifacountryid":163,"futcountryid":211},{"leaguename":833,"leagueid":350,"fifacountryid":183,"futcountryid":211},{"leaguename":856,"leagueid":351,"fifacountryid":195,"futcountryid":211},{"leaguename":876,"leagueid":353,"fifacountryid":52,"futcountryid":211},{"leaguename":897,"leagueid":2025,"fifacountryid":54,"futcountryid":211},{"leaguename":914,"leagueid":2134,"fifacountryid":221,"futcountryid":211},{"leaguename":925,"leagueid":2150,"fifacountryid":221,"futcountryid":211}]}
@@ -1 +0,0 @@
{"table":"fcc_managerbonusvalues","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":9,"rowsize_bytes":4,"rows_emitted":9,"rowblock":"0x7c31088","rowblock_bytes":16472,"descriptor":"0x7b10388","schema":[{"name":"bonuslevel","bit":0,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"bonustype","bit":8,"width":8,"kind":"int","min":0,"max":255,"storage":"int"},{"name":"cardlevel","bit":16,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"bonusvalue","bit":19,"width":5,"kind":"int","min":0,"max":16,"storage":"int"},{"name":"bonusid","bit":24,"width":5,"kind":"int","min":0,"max":16,"storage":"int"}],"rows":[{"bonuslevel":3,"bonustype":1,"cardlevel":1,"bonusvalue":2,"bonusid":0},{"bonuslevel":3,"bonustype":1,"cardlevel":2,"bonusvalue":5,"bonusid":1},{"bonuslevel":3,"bonustype":1,"cardlevel":3,"bonusvalue":10,"bonusid":2},{"bonuslevel":2,"bonustype":2,"cardlevel":1,"bonusvalue":1,"bonusid":3},{"bonuslevel":2,"bonustype":2,"cardlevel":2,"bonusvalue":2,"bonusid":4},{"bonuslevel":2,"bonustype":2,"cardlevel":3,"bonusvalue":3,"bonusid":5},{"bonuslevel":3,"bonustype":2,"cardlevel":1,"bonusvalue":1,"bonusid":6},{"bonuslevel":3,"bonustype":2,"cardlevel":2,"bonusvalue":1,"bonusid":7},{"bonuslevel":3,"bonustype":2,"cardlevel":3,"bonusvalue":1,"bonusid":8}]}
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
{"table":"fcc_myclubs","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":2,"rowsize_bytes":8,"rows_emitted":2,"rowblock":"0x7c20748","rowblock_bytes":0,"descriptor":"0x7b57a68","schema":[{"name":"myclubname","bit":0,"width":32,"kind":"string","min":0,"max":0,"storage":"offset-unresolved"},{"name":"myclubid","bit":32,"width":8,"kind":"int","min":0,"max":128,"storage":"int"}],"rows":[{"myclubname":0,"myclubid":1},{"myclubname":16,"myclubid":2}]}
@@ -1 +0,0 @@
{"table":"fcc_myclubscategories","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":12,"rowsize_bytes":12,"rows_emitted":12,"rowblock":"0x7988488","rowblock_bytes":0,"descriptor":"0x7b20878","schema":[{"name":"categoryname","bit":0,"width":32,"kind":"string","min":0,"max":0,"storage":"offset-unresolved"},{"name":"futcountryid","bit":32,"width":16,"kind":"int","min":0,"max":50000,"storage":"int"},{"name":"myclubid","bit":48,"width":8,"kind":"int","min":0,"max":128,"storage":"int"},{"name":"id","bit":56,"width":8,"kind":"int","min":0,"max":128,"storage":"int"},{"name":"isteamcategory","bit":64,"width":8,"kind":"int","min":0,"max":128,"storage":"int"},{"name":"categoryid","bit":72,"width":8,"kind":"int","min":0,"max":128,"storage":"int"}],"rows":[{"categoryname":0,"futcountryid":0,"myclubid":0,"id":1,"isteamcategory":0,"categoryid":16},{"categoryname":13,"futcountryid":14,"myclubid":0,"id":2,"isteamcategory":1,"categoryid":1},{"categoryname":32,"futcountryid":18,"myclubid":0,"id":3,"isteamcategory":1,"categoryid":2},{"categoryname":50,"futcountryid":21,"myclubid":0,"id":4,"isteamcategory":1,"categoryid":3},{"categoryname":69,"futcountryid":27,"myclubid":0,"id":5,"isteamcategory":1,"categoryid":4},{"categoryname":86,"futcountryid":45,"myclubid":0,"id":6,"isteamcategory":1,"categoryid":5},{"categoryname":103,"futcountryid":212,"myclubid":0,"id":7,"isteamcategory":1,"categoryid":6},{"categoryname":121,"futcountryid":211,"myclubid":0,"id":8,"isteamcategory":1,"categoryid":7},{"categoryname":138,"futcountryid":0,"myclubid":2,"id":10,"isteamcategory":0,"categoryid":18},{"categoryname":155,"futcountryid":0,"myclubid":2,"id":11,"isteamcategory":0,"categoryid":8},{"categoryname":173,"futcountryid":0,"myclubid":2,"id":12,"isteamcategory":0,"categoryid":10},{"categoryname":190,"futcountryid":0,"myclubid":2,"id":13,"isteamcategory":0,"categoryid":11}]}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
{"table":"fcc_preferredformationcalcback","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":16,"rowsize_bytes":12,"rows_emitted":16,"rowblock":"0x7b40a98","rowblock_bytes":0,"descriptor":"0x42811bb8","schema":[{"name":"formations","bit":0,"width":32,"kind":"string","min":0,"max":0,"storage":"offset-unresolved"},{"name":"form10","bit":32,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form2","bit":35,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"id","bit":38,"width":6,"kind":"int","min":0,"max":34,"storage":"int"},{"name":"form3","bit":44,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form5","bit":47,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form4","bit":50,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form13","bit":53,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form7","bit":56,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form9","bit":59,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form14","bit":62,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form12","bit":65,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form15","bit":68,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form8","bit":71,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form6","bit":74,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form16","bit":77,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form11","bit":80,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form1","bit":83,"width":3,"kind":"int","min":0,"max":4,"storage":"int"}],"rows":[{"formations":0,"form10":1,"form2":0,"id":3,"form3":0,"form5":1,"form4":0,"form13":2,"form7":1,"form9":2,"form14":0,"form12":1,"form15":0,"form8":1,"form6":3,"form16":0,"form11":1,"form1":0},{"formations":6,"form10":2,"form2":0,"id":6,"form3":0,"form5":1,"form4":0,"form13":1,"form7":1,"form9":2,"form14":0,"form12":1,"form15":0,"form8":3,"form6":1,"form16":0,"form11":1,"form1":0},{"formations":12,"form10":2,"form2":0,"id":7,"form3":0,"form5":1,"form4":0,"form13":1,"form7":1,"form9":3,"form14":0,"form12":1,"form15":0,"form8":2,"form6":2,"form16":0,"form11":1,"form1":0},{"formations":18,"form10":3,"form2":0,"id":8,"form3":0,"form5":1,"form4":0,"form13":1,"form7":1,"form9":2,"form14":0,"form12":1,"form15":0,"form8":2,"form6":1,"form16":0,"form11":1,"form1":0},{"formations":25,"form10":1,"form2":0,"id":13,"form3":0,"form5":2,"form4":0,"form13":1,"form7":3,"form9":1,"form14":0,"form12":2,"form15":0,"form8":1,"form6":1,"form16":0,"form11":2,"form1":0},{"formations":31,"form10":1,"form2":0,"id":14,"form3":0,"form5":3,"form4":0,"form13":1,"form7":2,"form9":1,"form14":0,"form12":2,"form15":0,"form8":1,"form6":1,"form16":0,"form11":2,"form1":0},{"formations":37,"form10":1,"form2":0,"id":16,"form3":0,"form5":2,"form4":0,"form13":1,"form7":2,"form9":1,"form14":0,"form12":3,"form15":0,"form8":1,"form6":1,"form16":0,"form11":2,"form1":0},{"formations":44,"form10":1,"form2":0,"id":19,"form3":0,"form5":2,"form4":0,"form13":1,"form7":2,"form9":1,"form14":0,"form12":2,"form15":0,"form8":1,"form6":1,"form16":0,"form11":3,"form1":0},{"formations":51,"form10":1,"form2":0,"id":21,"form3":0,"form5":1,"form4":0,"form13":3,"form7":1,"form9":1,"form14":0,"form12":1,"form15":0,"form8":1,"form6":2,"form16":0,"form11":1,"form1":0},{"formations":58,"form10":0,"form2":2,"id":23,"form3":2,"form5":0,"form4":1,"form13":0,"form7":0,"form9":0,"form14":0,"form12":0,"form15":0,"form8":0,"form6":0,"form16":0,"form11":0,"form1":3},{"formations":64,"form10":0,"form2":3,"id":24,"form3":2,"form5":0,"form4":1,"form13":0,"form7":0,"form9":0,"form14":0,"form12":0,"form15":0,"form8":0,"form6":0,"form16":0,"form11":0,"form1":2},{"formations":70,"form10":0,"form2":2,"id":25,"form3":3,"form5":0,"form4":1,"form13":0,"form7":0,"form9":0,"form14":0,"form12":0,"form15":0,"form8":0,"form6":0,"form16":0,"form11":0,"form1":2},{"formations":76,"form10":0,"form2":1,"id":27,"form3":1,"form5":0,"form4":3,"form13":0,"form7":0,"form9":0,"form14":0,"form12":0,"form15":0,"form8":0,"form6":0,"form16":0,"form11":0,"form1":1},{"formations":82,"form10":0,"form2":0,"id":29,"form3":0,"form5":0,"form4":0,"form13":0,"form7":0,"form9":0,"form14":3,"form12":0,"form15":2,"form8":0,"form6":0,"form16":1,"form11":0,"form1":0},{"formations":89,"form10":0,"form2":0,"id":30,"form3":0,"form5":0,"form4":0,"form13":0,"form7":0,"form9":0,"form14":2,"form12":0,"form15":3,"form8":0,"form6":0,"form16":1,"form11":0,"form1":0},{"formations":96,"form10":0,"form2":0,"id":31,"form3":0,"form5":0,"form4":0,"form13":0,"form7":0,"form9":0,"form14":1,"form12":0,"form15":1,"form8":0,"form6":0,"form16":3,"form11":0,"form1":0}]}
@@ -1 +0,0 @@
{"table":"fcc_preferredformationcalcgk","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":16,"rowsize_bytes":12,"rows_emitted":16,"rowblock":"0x7b40828","rowblock_bytes":7,"descriptor":"0x428119f8","schema":[{"name":"formations","bit":0,"width":32,"kind":"string","min":0,"max":0,"storage":"offset-unresolved"},{"name":"form10","bit":32,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form2","bit":35,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"id","bit":38,"width":6,"kind":"int","min":0,"max":34,"storage":"int"},{"name":"form3","bit":44,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form5","bit":47,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form4","bit":50,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form13","bit":53,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form7","bit":56,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form9","bit":59,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form14","bit":62,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form12","bit":65,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form15","bit":68,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form8","bit":71,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form6","bit":74,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form16","bit":77,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form11","bit":80,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form1","bit":83,"width":3,"kind":"int","min":0,"max":4,"storage":"int"}],"rows":[{"formations":0,"form10":2,"form2":0,"id":3,"form3":0,"form5":2,"form4":0,"form13":2,"form7":2,"form9":2,"form14":0,"form12":2,"form15":0,"form8":2,"form6":3,"form16":0,"form11":2,"form1":0},{"formations":6,"form10":2,"form2":0,"id":6,"form3":0,"form5":2,"form4":0,"form13":2,"form7":2,"form9":2,"form14":0,"form12":2,"form15":0,"form8":3,"form6":2,"form16":0,"form11":2,"form1":0},{"formations":12,"form10":2,"form2":0,"id":7,"form3":0,"form5":2,"form4":0,"form13":2,"form7":2,"form9":3,"form14":0,"form12":2,"form15":0,"form8":2,"form6":2,"form16":0,"form11":2,"form1":0},{"formations":18,"form10":3,"form2":0,"id":8,"form3":0,"form5":2,"form4":0,"form13":2,"form7":2,"form9":2,"form14":0,"form12":2,"form15":0,"form8":2,"form6":2,"form16":0,"form11":2,"form1":0},{"formations":25,"form10":2,"form2":0,"id":13,"form3":0,"form5":2,"form4":0,"form13":2,"form7":3,"form9":2,"form14":0,"form12":2,"form15":0,"form8":2,"form6":2,"form16":0,"form11":2,"form1":0},{"formations":31,"form10":2,"form2":0,"id":14,"form3":0,"form5":3,"form4":0,"form13":2,"form7":2,"form9":2,"form14":0,"form12":2,"form15":0,"form8":2,"form6":2,"form16":0,"form11":2,"form1":0},{"formations":37,"form10":2,"form2":0,"id":16,"form3":0,"form5":2,"form4":0,"form13":2,"form7":2,"form9":2,"form14":0,"form12":3,"form15":0,"form8":2,"form6":2,"form16":0,"form11":2,"form1":0},{"formations":44,"form10":2,"form2":0,"id":19,"form3":0,"form5":2,"form4":0,"form13":2,"form7":2,"form9":2,"form14":0,"form12":2,"form15":0,"form8":2,"form6":2,"form16":0,"form11":3,"form1":0},{"formations":51,"form10":2,"form2":0,"id":21,"form3":0,"form5":2,"form4":0,"form13":3,"form7":2,"form9":2,"form14":0,"form12":2,"form15":0,"form8":2,"form6":2,"form16":0,"form11":2,"form1":0},{"formations":58,"form10":0,"form2":2,"id":23,"form3":2,"form5":0,"form4":2,"form13":0,"form7":0,"form9":0,"form14":0,"form12":0,"form15":0,"form8":0,"form6":0,"form16":0,"form11":0,"form1":3},{"formations":64,"form10":0,"form2":3,"id":24,"form3":2,"form5":0,"form4":2,"form13":0,"form7":0,"form9":0,"form14":0,"form12":0,"form15":0,"form8":0,"form6":0,"form16":0,"form11":0,"form1":2},{"formations":70,"form10":0,"form2":2,"id":25,"form3":3,"form5":0,"form4":2,"form13":0,"form7":0,"form9":0,"form14":0,"form12":0,"form15":0,"form8":0,"form6":0,"form16":0,"form11":0,"form1":2},{"formations":76,"form10":0,"form2":2,"id":27,"form3":2,"form5":0,"form4":3,"form13":0,"form7":0,"form9":0,"form14":0,"form12":0,"form15":0,"form8":0,"form6":0,"form16":0,"form11":0,"form1":2},{"formations":82,"form10":0,"form2":0,"id":29,"form3":0,"form5":0,"form4":0,"form13":0,"form7":0,"form9":0,"form14":3,"form12":0,"form15":2,"form8":0,"form6":0,"form16":2,"form11":0,"form1":0},{"formations":89,"form10":0,"form2":0,"id":30,"form3":0,"form5":0,"form4":0,"form13":0,"form7":0,"form9":0,"form14":2,"form12":0,"form15":3,"form8":0,"form6":0,"form16":2,"form11":0,"form1":0},{"formations":96,"form10":0,"form2":0,"id":31,"form3":0,"form5":0,"form4":0,"form13":0,"form7":0,"form9":0,"form14":2,"form12":0,"form15":2,"form8":0,"form6":0,"form16":3,"form11":0,"form1":0}]}
@@ -1 +0,0 @@
{"table":"fcc_preferredformationcalcmid","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":16,"rowsize_bytes":12,"rows_emitted":16,"rowblock":"0x7b409c8","rowblock_bytes":10,"descriptor":"0x42811838","schema":[{"name":"formations","bit":0,"width":32,"kind":"string","min":0,"max":0,"storage":"offset-unresolved"},{"name":"form10","bit":32,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form2","bit":35,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"id","bit":38,"width":6,"kind":"int","min":0,"max":34,"storage":"int"},{"name":"form3","bit":44,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form5","bit":47,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form4","bit":50,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form13","bit":53,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form7","bit":56,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form9","bit":59,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form14","bit":62,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form12","bit":65,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form15","bit":68,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form8","bit":71,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form6","bit":74,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form16","bit":77,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form11","bit":80,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form1","bit":83,"width":3,"kind":"int","min":0,"max":4,"storage":"int"}],"rows":[{"formations":0,"form10":0,"form2":0,"id":3,"form3":0,"form5":0,"form4":1,"form13":2,"form7":0,"form9":2,"form14":0,"form12":0,"form15":0,"form8":0,"form6":3,"form16":0,"form11":0,"form1":0},{"formations":6,"form10":2,"form2":0,"id":6,"form3":0,"form5":1,"form4":0,"form13":0,"form7":0,"form9":2,"form14":0,"form12":0,"form15":0,"form8":3,"form6":0,"form16":0,"form11":0,"form1":0},{"formations":12,"form10":2,"form2":0,"id":7,"form3":0,"form5":0,"form4":0,"form13":0,"form7":0,"form9":3,"form14":0,"form12":0,"form15":0,"form8":2,"form6":2,"form16":0,"form11":0,"form1":0},{"formations":18,"form10":3,"form2":0,"id":8,"form3":0,"form5":0,"form4":0,"form13":0,"form7":0,"form9":2,"form14":0,"form12":0,"form15":0,"form8":2,"form6":0,"form16":0,"form11":0,"form1":0},{"formations":25,"form10":0,"form2":1,"id":13,"form3":1,"form5":1,"form4":0,"form13":0,"form7":3,"form9":0,"form14":0,"form12":2,"form15":0,"form8":0,"form6":0,"form16":0,"form11":2,"form1":1},{"formations":31,"form10":0,"form2":1,"id":14,"form3":1,"form5":3,"form4":0,"form13":0,"form7":1,"form9":0,"form14":0,"form12":2,"form15":0,"form8":1,"form6":0,"form16":0,"form11":2,"form1":1},{"formations":37,"form10":0,"form2":1,"id":16,"form3":1,"form5":2,"form4":0,"form13":0,"form7":2,"form9":0,"form14":0,"form12":3,"form15":0,"form8":0,"form6":0,"form16":0,"form11":2,"form1":1},{"formations":44,"form10":0,"form2":1,"id":19,"form3":1,"form5":2,"form4":0,"form13":0,"form7":2,"form9":0,"form14":0,"form12":2,"form15":0,"form8":0,"form6":0,"form16":0,"form11":3,"form1":1},{"formations":51,"form10":0,"form2":0,"id":21,"form3":0,"form5":0,"form4":0,"form13":3,"form7":0,"form9":0,"form14":0,"form12":0,"form15":0,"form8":0,"form6":2,"form16":0,"form11":0,"form1":0},{"formations":58,"form10":0,"form2":2,"id":23,"form3":2,"form5":1,"form4":0,"form13":0,"form7":1,"form9":0,"form14":0,"form12":1,"form15":0,"form8":0,"form6":0,"form16":0,"form11":1,"form1":3},{"formations":64,"form10":0,"form2":3,"id":24,"form3":2,"form5":1,"form4":0,"form13":0,"form7":1,"form9":0,"form14":0,"form12":1,"form15":0,"form8":0,"form6":0,"form16":0,"form11":1,"form1":2},{"formations":70,"form10":0,"form2":2,"id":25,"form3":3,"form5":1,"form4":0,"form13":0,"form7":1,"form9":0,"form14":0,"form12":1,"form15":0,"form8":0,"form6":0,"form16":0,"form11":1,"form1":2},{"formations":76,"form10":0,"form2":0,"id":27,"form3":0,"form5":0,"form4":3,"form13":0,"form7":0,"form9":0,"form14":0,"form12":0,"form15":0,"form8":0,"form6":1,"form16":0,"form11":0,"form1":0},{"formations":82,"form10":0,"form2":0,"id":29,"form3":0,"form5":0,"form4":0,"form13":0,"form7":0,"form9":0,"form14":3,"form12":0,"form15":2,"form8":0,"form6":0,"form16":1,"form11":0,"form1":0},{"formations":89,"form10":0,"form2":0,"id":30,"form3":0,"form5":0,"form4":0,"form13":0,"form7":0,"form9":0,"form14":2,"form12":0,"form15":3,"form8":0,"form6":0,"form16":1,"form11":0,"form1":0},{"formations":96,"form10":0,"form2":0,"id":31,"form3":0,"form5":0,"form4":0,"form13":0,"form7":0,"form9":0,"form14":1,"form12":0,"form15":1,"form8":0,"form6":0,"form16":3,"form11":0,"form1":0}]}
@@ -1 +0,0 @@
{"table":"fcc_preferredformationcalcst","source":"FIFA17.exe resident database (tools/db_dump.py)","rowcount":16,"rowsize_bytes":12,"rows_emitted":16,"rowblock":"0x7b404e8","rowblock_bytes":15,"descriptor":"0x42811678","schema":[{"name":"formations","bit":0,"width":32,"kind":"string","min":0,"max":0,"storage":"offset-unresolved"},{"name":"form10","bit":32,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form2","bit":35,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"id","bit":38,"width":6,"kind":"int","min":0,"max":34,"storage":"int"},{"name":"form3","bit":44,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form5","bit":47,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form4","bit":50,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form13","bit":53,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form7","bit":56,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form9","bit":59,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form14","bit":62,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form12","bit":65,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form15","bit":68,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form8","bit":71,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form6","bit":74,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form16","bit":77,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form11","bit":80,"width":3,"kind":"int","min":0,"max":4,"storage":"int"},{"name":"form1","bit":83,"width":3,"kind":"int","min":0,"max":4,"storage":"int"}],"rows":[{"formations":0,"form10":0,"form2":0,"id":3,"form3":0,"form5":0,"form4":0,"form13":2,"form7":0,"form9":0,"form14":0,"form12":0,"form15":1,"form8":0,"form6":3,"form16":0,"form11":1,"form1":0},{"formations":6,"form10":2,"form2":1,"id":6,"form3":1,"form5":1,"form4":0,"form13":0,"form7":0,"form9":2,"form14":1,"form12":0,"form15":0,"form8":3,"form6":0,"form16":0,"form11":0,"form1":1},{"formations":12,"form10":2,"form2":1,"id":7,"form3":1,"form5":0,"form4":0,"form13":0,"form7":0,"form9":3,"form14":0,"form12":0,"form15":1,"form8":2,"form6":0,"form16":0,"form11":0,"form1":1},{"formations":18,"form10":3,"form2":1,"id":8,"form3":1,"form5":0,"form4":0,"form13":0,"form7":0,"form9":2,"form14":1,"form12":0,"form15":1,"form8":2,"form6":0,"form16":0,"form11":0,"form1":1},{"formations":25,"form10":0,"form2":0,"id":13,"form3":0,"form5":2,"form4":1,"form13":0,"form7":3,"form9":0,"form14":0,"form12":2,"form15":0,"form8":0,"form6":0,"form16":0,"form11":2,"form1":0},{"formations":31,"form10":0,"form2":0,"id":14,"form3":0,"form5":3,"form4":1,"form13":0,"form7":2,"form9":0,"form14":1,"form12":2,"form15":0,"form8":1,"form6":0,"form16":1,"form11":2,"form1":0},{"formations":37,"form10":0,"form2":0,"id":16,"form3":0,"form5":2,"form4":1,"form13":0,"form7":2,"form9":0,"form14":0,"form12":3,"form15":0,"form8":0,"form6":0,"form16":0,"form11":2,"form1":0},{"formations":44,"form10":0,"form2":0,"id":19,"form3":0,"form5":2,"form4":0,"form13":0,"form7":2,"form9":0,"form14":0,"form12":2,"form15":0,"form8":0,"form6":1,"form16":0,"form11":3,"form1":0},{"formations":51,"form10":0,"form2":1,"id":21,"form3":0,"form5":0,"form4":0,"form13":3,"form7":0,"form9":0,"form14":0,"form12":0,"form15":0,"form8":0,"form6":2,"form16":0,"form11":0,"form1":0},{"formations":58,"form10":1,"form2":2,"id":23,"form3":2,"form5":0,"form4":0,"form13":0,"form7":0,"form9":1,"form14":1,"form12":0,"form15":1,"form8":1,"form6":0,"form16":0,"form11":0,"form1":3},{"formations":64,"form10":1,"form2":3,"id":24,"form3":2,"form5":0,"form4":0,"form13":1,"form7":0,"form9":1,"form14":1,"form12":0,"form15":1,"form8":1,"form6":0,"form16":0,"form11":0,"form1":2},{"formations":70,"form10":1,"form2":2,"id":25,"form3":3,"form5":0,"form4":0,"form13":0,"form7":0,"form9":1,"form14":1,"form12":0,"form15":1,"form8":1,"form6":0,"form16":0,"form11":0,"form1":2},{"formations":76,"form10":0,"form2":0,"id":27,"form3":0,"form5":1,"form4":3,"form13":0,"form7":1,"form9":0,"form14":0,"form12":1,"form15":0,"form8":0,"form6":0,"form16":1,"form11":0,"form1":0},{"formations":82,"form10":1,"form2":1,"id":29,"form3":1,"form5":1,"form4":0,"form13":0,"form7":0,"form9":0,"form14":3,"form12":0,"form15":2,"form8":1,"form6":0,"form16":1,"form11":0,"form1":1},{"formations":89,"form10":1,"form2":1,"id":30,"form3":1,"form5":0,"form4":0,"form13":0,"form7":0,"form9":1,"form14":2,"form12":0,"form15":3,"form8":0,"form6":1,"form16":1,"form11":0,"form1":1},{"formations":96,"form10":0,"form2":0,"id":31,"form3":0,"form5":1,"form4":1,"form13":0,"form7":0,"form9":0,"form14":1,"form12":0,"form15":1,"form8":0,"form6":0,"form16":3,"form11":0,"form1":0}]}
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More