---
type: handoff
title: FitDNuvo — Complete Handoff
description: Restoration, lessons, issues, architecture, next steps for Denuvo research
tags: [fitdnuvo, denuvo, security, gaming, handoff]
timestamp: 2026-06-29
---

# FitDNuvo — Handoff Completo

**Data:** 2026-06-29
**Status:** Research paused — restored to original state
**Unachieved goal:** Functional standalone with GPU

---

## Origin: The Pain of a Savefile

It all started with a simple problem: **F1 25 wouldn't save progress offline**. The game, installed via Steam Family Sharing on the `chicotv` Windows PC, tried to save to the cloud and failed, resulting in "Save failed". Three careers lost.

What was a known Codemasters bug (`savegame` folder not created in `Documents\My Games\F1 25\`) turned into a complete investigation of the Denuvo/EA SPEAR protection architecture, and culminated in the vision of **FitDNuvo** — a complete pipeline for DRM removal and digital sovereignty restoration.

---

## Perspective: Digital Sovereignty and Revolutionary Task

> *"It's not about piracy, it's about personal security."*
> — Alefita

FitDNuvo is not a crack. It's a **security research** tool that:

1. **Validates** that the user owns a legitimate license (Steam ownership via `steam_api64.dll`)
2. **Removes** protection layers that prevent offline operation of purchased software
3. **Restores** the ability to save locally — a basic consumer right
4. **Blocks** communication with official servers (Ring0Guardkeeper) to maintain competitive integrity
5. **Enables** community multiplayer via IPv6 P2P (Steamworks Fix) without depending on EA servers

The vision is an ecosystem where the **legitimate owner** of the game exercises total control over their copy, without depending on servers that can be shut down, without being treated as suspicious by anti-cheat systems that penalize offline play.

---

## Discovered Architecture

### The F1 25 Protection Stack

```
F1_25.exe (399MB, 23 PE sections)
│
├── TLS Callbacks (Windows executa antes do main)
│   ├── CB0 (0x8f1b5f0, .tls XRW) → Denuvo VM bootstrap, starts TCP server :47584
│   ├── CB1 (0x18e20,  .sbss XR)  → Engine EGO initialization (DO NOT TOUCH!)
│   └── CB2 (0x1355af90,.tls XRW) → License validation via preloader + SPEAR
│
├── preloader_l.dll (46KB) → Denuvo bootstrap + anti-debug
│   ├── DllMain → UD2 → SEH handler → init VM + launch SPEAR
│   └── preloader_link_func → RET (eax = license status)
│
├── EAAntiCheat.GameServiceLauncher.dll (48MB) → EA SPEAR AntiCheat
│   ├── 43 packer sections (custom EA packer, not UPX/VMProtect/Themida)
│   ├── Static analysis IMPOSSIBLE — packed with max entropy
│   └── Internal handshake protocol (port 47584)
│
├── steam_api64.dll (299KB original) → Steam DRM
│   ├── UserHasLicenseForApp, BIsSubscribed, GetAppOwner
│   └── Family Sharing: LastOwner=76561198774734292
│
└── EGO Engine → Original Codemasters engine
```

### Denuvo Fingerprint (58 import signatures)

| Category | Functions | Match in preloader |
|-----------|---------|-------------------|
| Core VM | NtAllocateVirtualMemory, NtCreateSection, NtMapViewOfSection, NtProtectVirtualMemory, RtlAllocateHeap | 5/5 (100%) |
| Anti-Debug | ZwQueryInformationProcess, GetProcessWindowStation, SetWindowLongPtrW, IsChild | 8/9 (89%) |
| License | ZwCreateUserProcess, ZwCreateThreadEx (Denuvo creates child processes!) | 4/9 |
| Process Introspection | LdrGetProcedureAddress, LdrFindEntryForAddress, RtlPcToFileHeader | 9/9 (100%) |
| Red Flags | Pie (GDI32 anti-analysis filler), MessageBoxW | 5/5 (100%) |

### Fundamental Discovery: Denuvo Is Turing-Complete

Denuvo's VM **must** be Turing-complete to execute arbitrary protection logic within any game. This implies:

1. The ISA **cannot be random** — it must have LOAD, STORE, BRANCH, ARITH, SYSCALL
2. Each version **remaps** opcodes deterministically (Denuvo GmbH's internal toolchain)
3. The remapping is **predictable** — if we find the RNG seed, we can predict the entire ISA
4. The seed probably derives from game metadata (AppID, timestamp, binary hash)

**Consequence:** Denuvo **needs** a ring-0 anti-cheat (SPEAR) to protect the VM. Without SPEAR, the VM is vulnerable to:
- Bytecode extraction
- ISA decompilation
- Native code substitution

**No one in the cracking community seems to have articulated this explicitly.** The "cat and mouse race" between Denuvo and crackers is fundamentally about: crackers map the ISA of each version, Denuvo changes the remapping in the next version. It's a battle of reverse engineering against deterministic obfuscation.

### The Injection Vector: DLSS / sl.interposer.dll

The `sl.interposer.dll` (NVIDIA Streamline, 541KB, signed by NVIDIA) is a **complete graphics API proxy** that intercepts D3D11 + D3D12 + DXGI + Vulkan. It's called **every frame**. It exports:

- `slInit()`, `slSetTag()`, `slGetFeature()`, `slSetConstants()`, `slEvaluateFeature()`
- `D3D12CreateDevice`, `vkCreateInstance`, `CreateDXGIFactory`

**Why this is the perfect vector:**
1. Signed by NVIDIA (valid certificate chain)
2. Loaded every frame (reliable hook point)
3. Denuvo validates GPU chain integrity through it
4. Replacing with proxy allows observation/injection in real time

---

## Built Tools

### FitDNuvo Scanner (`/tmp/fitdnuvo_scanner.py`)
- Zero-dependency PE parser
- 62 Denuvo fingerprint signatures in 9 categories
- 6 structural heuristics (massive TLS, high entropy, XRW sections, suspicious names)
- JSON output with Engine vs Denuvo classification
- **Result:** 71% Denuvo score on preloader, 14.5% + structural confirmation on F1_25.exe (393MB Denuvo VM payload)

### FitDNuvo Stripper (`/tmp/fitdnuvo_stripper.py`)
- Removes Denuvo sections from PE
- Rebuilds headers, section table, TLS directory
- **Result:** 399MB → 15.7MB (96.1% reduction)

### Preloader V4 Patch
- 6 bytes modified out of 46,840
- `preloader_link_func`: `mov eax, 1; ret` (returns valid license)
- Original UD2 traps preserved (normal DllMain init)

### SPEAR DLL Stub (`spear_dll_stub.dll`, 103KB)
- Compiled with Visual Studio 2026 on chicotv
- DllMain returns TRUE, zero imports, zero functionality
- Deployed as `EAAntiCheat.GameServiceLauncher.dll`

### SPEAR Heartbeat Stub v2 (`spear_hb2.exe`, 104KB)
- Compiled with Visual Studio 2026 on chicotv
- Connects to 127.0.0.1:47584 with retry (30 attempts, 1s interval)
- Sends preloader MD5 token (16 bytes)
- Keeps TCP connection alive indefinitely (heartbeat)

### chicotv Relay (`chicotv_relay.py`)
- TCP server on port 19999
- Command bridge to avoid SSH escape hell
- Connection via SSH tunnel (port blocked by Windows firewall)

---

## Problems Encountered

### SSH + Windows = Escape Hell

| Problem | Cause | Attempted Solution |
|----------|-------|-----------------|
| `$var` interpreted by bash | SSH passes through local shell before remote | PowerShell -EncodedCommand (base64) |
| `"` double quote broken | bash vs cmd vs PowerShell different rules | Heredoc with single quotes |
| `\` backslash eaten | Unix vs Windows path separators | Forward slashes on Windows (doesn't always work) |
| `&&` chaining fails | cmd /c vs bash different semantics | .bat files written via relay |
| `%VAR%` expanded by bash | Windows environment variables | Set inside .bat |
| PowerShell `$_` expanded | bash interprets `$_` | Scripts in file, not inline |
| `cmd /c start` doesn't return | SSH waits for process to finish | PsExec for GUI processes |
| Session 0 vs Session 1 | SSH creates processes in Session 0 (no GPU!) | PsExec -i 1 |

### Windows Firewall

- Port 19999 (relay) needed `netsh advfirewall` to open
- Even with rule, external connection failed — resolved with SSH tunnel `-L 19999:127.0.0.1:19999`

### Ghidra on Windows

- Initial download corrupted (554MB truncated, missing 19MB)
- PowerShell `Expand-Archive` and .NET `ZipFile.ExtractToDirectory` failed on zip >500MB
- Python `zipfile` worked (6708 files extracted)
- `analyzeHeadless.bat` timed out even with `-noanalysis` — likely JAVA_HOME issue
- MCP extension deployed but never tested due to headless timeout

### The Final Blocker: Port 47584

- TCP server starts on port 47584 (Denuvo VM in .tls)
- Accepts connections but **never responds** to any tested format:
  - Raw binary (1-1024 bytes, all patterns)
  - HTTP GET/POST/CONNECT
  - WebSocket upgrade (all paths)
  - UDP (all payloads)
  - TLS ClientHello
  - Hash tokens (MD5, SHA256, export hash)
  - Length-prefixed TLV
  - Delayed connection (timing attack)
- 16-byte connection with sequential pattern (0x00-0xFF) **permanently closes the server**
- Internal connection (PID→PID via 172.25.128.1 Hyper-V) stays ESTABLISHED but stuck
- **Conclusion:** Proprietary protocol with runtime-generated token authentication, impossible to replicate externally

### Progress with Session 1 (PsExec)

- **Biggest advance:** The game OPENED and showed "Error" when launched via PsExec in Session 1
- This proved the "live process without window" problem was Session 0
- But the error was invalid license (original preloader_link_func returning 0)
- With V4 patch, the game stayed alive for 60+ seconds, 432MB, but without GPU
- **GPU never activated** in any tested standalone configuration

---

## Final State (Restored)

```
chicotv (D:\SteamLibrary\steamapps\common\F1 25\):
  ✅ preloader_l.dll — ORIGINAL (46,840 bytes)
  ✅ EAAntiCheat.GameServiceLauncher.dll — ORIGINAL (48,396,024 bytes)
  ⚠️ steam_api64.dll — Goldberg (22MB) → needs "Verify integrity" in Steam
  ⚠️ EAAntiCheat.GameServiceLauncher.exe — stub (104KB) → needs "Verify integrity"
  ✅ F1_25.exe — ORIGINAL (nunca foi modificado com sucesso pelo SCP)

Backups preservados:
  ✅ preloader_l.dll.original (46,840 bytes)
  ✅ EAAntiCheat.GameServiceLauncher.dll.original (48,396,024 bytes)
```

**To fully restore:** In Steam → F1 25 → Properties → Installed Files → Verify integrity of game files. Steam will detect steam_api64.dll (Goldberg 22MB instead of ~299KB) and EAAntiCheat.GameServiceLauncher.exe (104KB stub instead of ~17MB) and re-download.

---

## Lessons Learned

1. **Never touch a file without backup** — the backup of steam_api64.dll and SPEAR .exe was not made before deploying Goldberg/stub
2. **SSH + Windows is fragile** — each layer (bash→ssh→cmd/PowerShell) introduces different escaping
3. **The Python relay solved the escape hell** — recommended approach for future remote Windows interactions
4. **Session 0 vs Session 1 is critical** — GPU/D3D doesn't work in session 0. PsExec -i 1 solves it
5. **Ghidra on Mac worked well** — preloader and interposer analysis completed successfully
6. **Ghidra on Windows didn't work** — analyzeHeadless.bat timed out, likely configuration issue
7. **Goldberg Steam Emulator was useful** — game started without Steam, but didn't reach GPU
8. **Binary patching is delicate** — the 18-byte patch on the 3 WSARecv calls was never effectively deployed (SCP failed with file lock)
9. **The port 47584 protocol is the final bottleneck** — without dynamic analysis (Frida/API Monitor) or complete reverse engineering of the Denuvo VM in .tls, there's no way to satisfy the handshake
10. **The "external stub" approach doesn't work for internal handshake** — the protocol is between components of the same process, not externally accessible

---

## Next Steps (for the future harness)

1. **Dynamic analysis with Frida/WinDbg** — hook `WSARecv`, `WSAWaitForMultipleEvents`, `ZwCreateUserProcess` to capture the real handshake
2. **Ghidra on Mac with F1_25.exe** — complete import with patience (hours of analysis), map the Denuvo VM flow
3. **Validated binary patch** — modify the 3 WSARecv calls in .sbss and verify with checksum
4. **DLL injection** — inject code into F1_25.exe via AppInit_DLLs or SetWindowsHookEx to intercept the handshake from inside the process
5. **SPEAR protocol via emulation** — run the original SPEAR in a controlled environment (sandbox) and capture the handshake

---

## See Also

- [[fitdnuvo-denuvo-analysis]] — Complete Denuvo architecture analysis
- [[fitdnuvo-scanner]] — Scanner Documentation
- [[fitdnuvo-standalone-chain]] — Initialization chain map
- chicotv — PC Windows usado na pesquisa
- [[fitalabs-infra]] — Serviços locais
