davestinhast/l4d2c-anticheat-re
GitHub: davestinhast/l4d2c-anticheat-re
Stars: 1 | Forks: 0
# Ingeniería Inversa — L4D2Center Anticheat
Análisis estático completo del binario `l4d2c_anticheat.exe`, el sistema anti-cheat del servidor comunitario L4D2Center. Este repositorio documenta absolutamente todo lo que hace el programa, cómo lo hace, y los vectores de bypass identificados.
**Restricción:** Todo el análisis fue realizado de forma estática. El binario no fue ejecutado.
## Identificación del Binario
Archivo: l4d2c_anticheat.exe
Tamaño: 44,877,952 bytes (42.80 MB)
Arquitectura: x86-64 (PE32+)
Lenguaje: Go (confirmado por múltiples indicadores del runtime)
Ofuscador: garble (obfuscación de nombres, tipos, strings y timestamp PE)
Framework UI: Wails v2 (Go + WebView2/Chromium embebido)
Servidor: https://l4d2center.com/0
Protocolo: HTTP/2 + TLS 1.2/1.3 + Protocol Buffers v3 (gRPC)
Firma digital: Authenticode — "Editor verificado: L4D2Center" en UAC
Certificados: Auto-firmados (Root CA 10 años, hoja ~2.3 años)
Certificate Pinning: NO (usa el store de certificados de Windows)
## Lo que hace el AC — Resumen Técnico
### Al iniciar (Startup — 87 goroutines)
- Carga la interfaz WebView2 (Chromium embebido) con UI de consola oscura
- Inicializa blacklists de ventanas, procesos y herramientas RE
- Carga el sistema WMI (COM/DCOM) para el HWID
- Configura el cliente HTTP/2 hacia `l4d2center.com`
- Configura el sistema de tokens de autenticación
- Expone tres métodos al frontend JS: `StartL4D2` (ID=2), `ConnectL4D2Server` (ID=0), `FrontendReady` (ID=1)
### Al conectar al servidor (ConnectL4D2Server — 4 goroutines)
**Goroutine 1 — Autenticación**
- Lee el SteamID del usuario desde el cliente de Steam local
- Ejecuta consultas WMI para recolectar HWID completo:
- `Win32_Processor.ProcessorId` → CPU ID
- `Win32_DiskDrive.SerialNumber` / `Win32_DiskDrive.Model` → Disco
- `Win32_BaseBoard.SerialNumber` / `Win32_BaseBoard.Model` → Placa madre
- `Win32_VideoController.PNPDeviceID` / `.Name` → GPU
- `Win32_OperatingSystem.BuildNumber` / `.Version` → OS
- Lee fecha de instalación de Steam (anti-smurf) → `AAUUUh.InstallDate`
- Solicita token de auth al servidor l4d2center.com
- Verifica si la cuenta es smurf (`GetSmurf`)
- Verifica si la cuenta está baneada (`GetBanned` → `Qi1Z8I.Banned`)
**Goroutine 2 — Configuración de detección**
- Descarga `CheatSigs` (W99qYP[]) desde el servidor — patrones de bytes en memoria
- Enumera todos los archivos `.vpk` del directorio de addons del juego
- Busca VPKs con patrón `%s\%sk1e1y*.vpk` (cheats de L4D2 conocidos)
- Inicializa el WatchList (`_6di6zc0se2v`)
**Goroutine 3 — Loop de detección (ticker cada ~5-60s)**
- Scan de títulos de ventanas: `EnumWindows` + `GetWindowTextW` contra blacklist
- Scan de procesos: `CreateToolhelp32Snapshot` + `Process32First/Next` contra blacklist
- Scan de memoria del juego: `ReadProcessMemory` contra CheatSigs descargados
- Monitoreo de módulos DLL: `Module32First/Next` buscando inyecciones
- Heartbeat al servidor cada ~30 segundos
- Capturas de pantalla con `BitBlt` cada ~120 segundos (formato PNG NRGBA)
**Goroutine 4 — Handler de resultados**
- Al detectar algo: captura screenshot → reporta al servidor → desconecta/banea
- Mensajes de consola en rojo (`#FF0000`) = ban/error
### Al lanzar el juego (StartL4D2 — 5 goroutines)
- `os/exec.Cmd.Start()` → lanza `left4dead2.exe`
- `exec.Cmd.Wait()` → espera cierre del juego
- Vigilancia de módulos DLL cargados en el proceso del juego
- Capturas periódicas de pantalla como evidencia
### Motor de Detección Principal (dUgTofmw.ga4oovjHCfg — 37 closures)
- 33 goroutines de detección numeradas (func1–func33) + 4 sub-goroutines anidadas (func9.1, func12.1, func21.1, func28.1)
- Cada goroutine maneja un vector de detección independiente
- Patrón productor-consumidor: `(*fcje4l4dl_uV).Feed` alimenta datos entre goroutines
- Paralelización: scan de ventanas, procesos, memoria, módulos, network
## Estructura del Repositorio
analysis/
binario.md Análisis PE: secciones, imports, metadatos
goroutines.md Arquitectura de goroutines y timing
protobuf_esquema.md Esquema protobuf completo reconstruido
hwid.md HWID: queries WMI, structs, bypass detallado
pipeline_hwid.md Pipeline HWID completo: A39Z4i → FXWqsvy_ → dUgTofmw
listas_negras.md Blacklists completas de procesos y ventanas
logica_deteccion.md Lógica interna de detección (20 vectores documentados)
protocolo_red.md Protocolo de red, autenticación, MITM
motor_deteccion.md Motor de detección principal
pdFrspK_G.md Motor hlavBkMcO: 644 verificaciones activas de detección
scanner_source_engine.md Scanner de ConVars Source Engine (sOAbtRgFLa6_)
monitoreo_proceso.md gopsutil y monitoreo de proceso
main_package.md Paquete main: ciclo de vida Wails, 75 closures Startup, QSUMsCa
paquetes_identificados.md Mapa completo de paquetes garble (183 paquetes identificados)
frontend_ui.md Análisis de la UI: HTML, JavaScript, WebSocket IPC
bypass_guide.md Guía de bypass para todos los vectores (20 vectores)
ui_logo.png Logo extraído del binario (150,356 bytes)
proto/
esquema.proto Definición protobuf reconstruida (16 mensajes)
## Herramientas Utilizadas
- Búsqueda de strings en PowerShell (`[System.Text.Encoding]::GetEncoding(1252)`)
- Análisis de type reflection metadata de Go (nombres de tipos en `.rdata`)
- Análisis de anotaciones protobuf (`protobuf:"..."` / `json:"..."`) en `.rdata`
- Análisis de nombres de funciones Go (parcialmente visibles por el binding Wails)
## Hallazgos Clave
### Seguridad del Protocolo
- **Sin certificate pinning** — MITM con Burp/Fiddler funciona sin modificaciones
- El stack TLS está embebido en Go, no usa WinSSL/SChannel ni OpenSSL
- Tres métodos de MITM documentados: Burp proxy, hook TLS in-process, DNS redirect
### HWID
- **5 componentes:** CPU (`ProcessorId`), Disco (`SerialNumber`), GPU (`PNPDeviceID`), Motherboard (`SerialNumber`), OS (`BuildNumber`)
- Todas las queries van vía WMI COM: `IWbemServices::ExecQuery` en vtable índice 20
- Bypass documentado con hook de vtable WMI
### Detección
- **CheatSigs dinámicos** — patrones de bytes descargados del servidor en cada sesión
- **778 firmas de cheat hardcoded** en 5 paquetes de firmas estáticas: `ra_94HIlnc6`(299) + `EyjsrRr`(162) + `WGfDxX0zz2M`(117) + `YCJ5PUz_M`(116) + `kNpc1A53`(84). Supera en firmas estáticas a EAC y VAC
- **`hlavBkMcO` — motor de detección principal** con **644 sub-closures** en el paquete `pdFrspK_G`. Cada closure = una verificación activa de estado del juego. Distinto de las firmas estáticas: estas se EJECUTAN directamente, no se registran en tablas
- **Blacklist de ~62 entradas en 4 listas distintas** — BL1 (16 títulos de ventana, 6 chars fijos): x32dbg, windbg, ghidra, de4dot, dbgclr, hacker, sysmon, efence... | BL2 (~30 procesos/substrings): aimware, fiddler, ollydbg, x64_dbg, PhantOm, wpe pro, harmony, cef.pak, Discord-, Operacmd.exe, Arc.exe... | BL3 (6 herramientas RE cortas): dump, peek, kgdb, mdbg | BL4 (10 herramientas .NET + cheats): dnspy, ilspy, pizza (cheat L4D2), ida -, crack
- **Endpoint gRPC `/auth`** confirmado — encontrado en string table inmediatamente después de la blacklist
- **Búsqueda de VPKs** con patrón glob `k1e1y*.vpk` para cheats conocidos de L4D2
- **Screenshot automático** cada ~120s como evidencia de ban (PNG NRGBA)
- **`os/exec`** presente — el AC puede spawnar procesos del sistema (wmic, bcdedit, sc, powershell) para detección y recolección de datos adicionales
### Anti-Análisis
- **garble** — todos los nombres de paquetes, tipos y funciones son strings aleatorios
- **Timestamp PE = 0** — impide correlacionar con fecha de build
- **APIs por ordinal** — ReadProcessMemory, OpenProcess, CreateToolhelp32Snapshot no aparecen como strings
- **ObfuscatedCall** — mecanismo Wails personalizado con IDs numéricos en lugar de nombres de función
### Correcciones de Análisis Previo
- `reportZombies` = runtime de Go (GC), NO función del AC
- `ReportZerolen`/`IsZerolen` = librería gopacket/802.11, NO función del AC
- `ReportValidationErrors` = `go-playground/validator`, NO función del AC
- `mTkHARFkg8` = paquete `sync` de Go (WaitGroup, Mutex)
- `BEwVDQOh5` = `encoding/xml` de Go (no sistema de tokens)
### Goroutines (150+ en total durante monitoreo activo)
- Startup: 87 goroutines (incluyendo Wails + runtime) — `Startup` tiene 75 closures totales: `func1-60` directas + `ZrMEw4hJW.func61-75` (función inner nombrada) + `gowrap2`
- ConnectL4D2Server: 4 goroutines principales (`func1-4`)
- QSUMsCa (orquestador de detección): 4 gowraps + 2 inner goroutines (`MDfyjAe.func7`, `RaR0kkqIl.func8`) = 6 goroutines
- Motor de detección (`pdFrspK_G.hlavBkMcO`): 644 verificaciones activas paralelas
- StartL4D2: 4 closures + goroutine de capturas (`func4.1`)
- BhCuafOD (xxhash) confirma: el HWID final es un hash xxHash64 de los 5 componentes de hardware
## Mapa de Vectores de Bypass
| Vector | Dificultad | Método |
|--------|-----------|--------|
| Blacklist ventanas | Baja | Renombrar ventana del debugger |
| Blacklist procesos | Baja | Renombrar ejecutable |
| HWID pipeline (`FXWqsvy_`) | Media | Hook Z6ey1EJD.func1-11 con frida |
| CheatSigs memoria | Alta | No inyectar en proceso / hook VirtualQuery |
| 778 firmas estáticas | Alta | Polimorfismo / código sin firmas conocidas |
| `hlavBkMcO` 644 checks | Muy Alta | Análisis dinámico completo + hook Feed() |
| DLL modules | Alta | Manual mapping (sin LoadLibrary) |
| os/exec procesos | Media | Hook CreateProcess para output limpio |
| Screenshots | N/A | Solo evidencia, no prevención directa |
| Heartbeat | N/A | No requiere bypass |
| SteamID | Media | Requiere cuenta legítima |
| InstallDate | Media | Hook de lectura de registro |
| gopsutil | Baja | No usar flags sospechosos en procesos |
| Source Engine ConVars | Media | Hook ReadProcessMemory |
| Captura de paquetes (pcap) | Muy Alta | VM con NIC virtual |
| Protocolo red | Baja | Burp Suite (sin certificate pinning) |