
Análisis estático de ingeniería inversa de las heurísticas de entrada de movimiento en el motor Source 2, identificando casos límite estructurales en la automatización de entradas y las rutinas de limitación de velocidad de salto.
server.dll)Este documento presenta un análisis estático de ingeniería inversa de dos rutinas de verificación de movimiento del lado del cliente implementadas en el motor de Counter-Strike 2 (server.dll): el evaluador de automatización de entrada / SOCD (sub_1801C6B30, designado CVE-2026-1801C / QUANTUM-SHIFT) y el limitador de tasa de solicitudes de salto (sub_180A7EDB0, designado CVE-2026-180A7 / BAL-JUMP). Mediante análisis de desensamblado y modelado matemático formal de las máquinas de estado subyacentes, demostramos casos límite estructurales en ambas heurísticas. Específicamente, documentamos cómo la cuantización temporal discreta en sub_1801C6B30 crea un límite de clasificación invariante bajo desplazamientos de fase fijos de un solo tick, y cómo sub_180A7EDB0 depende de una métrica de intervalo univariante ($\Delta t$) que permanece invariante bajo disparadores de impulso único bloqueados por fase.
sub_1801C6B30)server.dll (Compilación Minorista Win64)0x1C6B30void __fastcall sub_1801C6B30(int *pMovementServices, __int64 pPlayerController, __int64 pUserCmdPB)La rutina evalúa eventos de transición de botones de movimiento (+moveleft / +moveright) enviados a través de payloads de cliente CBaseUserCmdPB. La ejecución sigue un pipeline condicional:
sv_auto_cstrafe_attempt_window, por defecto 100).sub_1801C6B30)void __fastcall sub_1801C6B30(int *pMovementServices, __int64 pPlayerController, __int64 pUserCmdPB)
{
if (!pPlayerController || (*(_BYTE *)(pUserCmdPB + 16) & 1) == 0)
return;
__int64 pPawn = sub_180B137A0(pPlayerController);
if (!pPawn || !(*(unsigned __int8 (__fastcall **)(__int64))(*(_QWORD *)pPawn + 3216i64))(pPawn))
return;
float *pVel = (float *)sub_1803CBD90(pPawn, &szVelocityBuf);
float vSq = (pVel[0] * pVel[0]) + (pVel[1] * pVel[1]) + (pVel[2] * pVel[2]);
// Filtrado: Umbral mínimo de velocidad
if (vSq <= 18279.04f)
return;
int rawTicks = *(_DWORD *)(pUserCmdPB + 24);
bool bIsOverlap = (rawTicks >= 0);
int absTicks = bIsOverlap ? rawTicks : ~rawTicks;
double curTime = sub_1801F46D0(off_181C9F350);
if (curTime * 1e-9 * (double)absTicks >= 15.5)
return;
int roundedTicks = (int)V_roundd();
if ((unsigned int)roundedTicks > 15)
return;
// Asignación de Símbolo
char symbolCode;
if (roundedTicks == 0)
symbolCode = 1; // Éxito / 0 ticks perfecto
else
symbolCode = bIsOverlap ? 2 : 3; // Solapamiento o Sub-solapamiento
// Obtener punteros de configuración ConVar
unsigned int windowCap = *GetConVarUInt(&unk_181DDBD30, &qword_181DDBD38);
if (windowCap - 1 > 999)
return;
sub_1801ECEA0(pMovementServices, windowCap);
// Añadir símbolo al buffer circular
int bufCap = pMovementServices[0];
if (bufCap > 0)
{
int writeIdx = pMovementServices[6];
if (writeIdx >= 0 && writeIdx < bufCap)
{
*(_BYTE *)(writeIdx + *((_QWORD *)pMovementServices + 1)) = symbolCode;
if (++pMovementServices[6] == bufCap)
pMovementServices[6] = 0;
}
}
// Actualizar histogramas de frecuencia de ticks discretos
if (bIsOverlap)
pMovementServices[roundedTicks + 7]++;
else
pMovementServices[roundedTicks + 23]++;
int seqLen = *GetConVarInt(&unk_181DDBD40, &qword_181DDBD48);
if ((unsigned int)(seqLen - 1) > 999)
return;
// Evaluar métricas de secuencia de ventana deslizante
int totalValid = 0;
int totalOverlaps = 0;
int curSequenceSuccesses = 0;
int maxSequenceSuccesses = 0;
for (int i = 0; i < (int)windowCap; ++i)
{
if (i < bufCap)
{
int readIdx = i + pMovementServices[6] - bufCap;
if (i + pMovementServices[6] < bufCap)
readIdx = i + pMovementServices[6];
char sym = *(_BYTE *)(readIdx + *((_QWORD *)pMovementServices + 1));
if (sym != 0)
{
totalValid++;
if (sym == 2) totalOverlaps++;
else if (sym == 1) curSequenceSuccesses++;
}
}
// Actualización de ventana deslizante
if (i >= seqLen && (i - seqLen) >= 0)
{
if ((i - seqLen) < bufCap)
{
int popIdx = i + pMovementServices[6] - seqLen - bufCap;
if (i + pMovementServices[6] - seqLen < bufCap)
popIdx = i + pMovementServices[6] - seqLen;
if (*(_BYTE *)(popIdx + *((_QWORD *)pMovementServices + 1)) == 1)
curSequenceSuccesses--;
}
}
if (maxSequenceSuccesses < curSequenceSuccesses)
maxSequenceSuccesses = curSequenceSuccesses;
}
int minAttempts = *GetConVarInt(&unk_181DDBD20, &qword_181DDBD28);
float dynamicLimit = 0.0f;
if (totalValid >= minAttempts)
{
int minSuccessThreshold = *GetConVarInt(&unk_181DDBD50, &qword_181DDBD58);
if (maxSequenceSuccesses >= minSuccessThreshold)
{
float successRatio = 0.0f;
if (seqLen > minSuccessThreshold)
{
successRatio = (float)(maxSequenceSuccesses - minSuccessThreshold) /
(float)(seqLen - minSuccessThreshold);
}
float lowerPct = *GetConVarFloat(&unk_181DDBD70, &qword_181DDBD78); // Por defecto 20.0%
float upperPct = *GetConVarFloat(&unk_181DDBD60, &qword_181DDBD68); // Por defecto 5.0%
dynamicLimit = (lowerPct - upperPct) * successRatio + upperPct;
}
}
float observedOverlapPct = ((float)totalOverlaps / (float)totalValid) * 100.0f;
// Condición de Violación: El límite dinámico supera la proporción de solapamiento observada
if (dynamicLimit > observedOverlapPct)
{
sub_1801ECEA0(pMovementServices, 0); // Vaciar estado del buffer
bool bEnableKick = *GetConVarByte(&unk_181DDBD90, &qword_181DDBD98);
if (bEnableKick)
{
__int64 pEngine = qword_182012050;
void (__fastcall *pfnKickClient)(__int64, unsigned int, _QWORD, __int64) =
*(void (__fastcall **)(__int64, unsigned int, _QWORD, __int64))(*(_QWORD *)pEngine + 768i64);