
सोर्स 2 इंजन में मूवमेंट इनपुट ह्यूरिस्टिक्स का स्थैतिक रिवर्स-इंजीनियरिंग विश्लेषण, जो इनपुट ऑटोमेशन और जंप रेट लिमिटिंग रूटीन में संरचनात्मक एज केस की पहचान करता है।
server.dll) में मूवमेंट इनपुट ह्यूरिस्टिक्स का स्टैटिक विश्लेषणयह पेपर काउंटर-स्ट्राइक 2 इंजन (server.dll) में लागू दो क्लाइंट-साइड मूवमेंट सत्यापन रूटीन का स्टैटिक रिवर्स-इंजीनियरिंग विश्लेषण प्रस्तुत करता है: इनपुट ऑटोमेशन / SOCD मूल्यांकनकर्ता (sub_1801C6B30, जिसे CVE-2026-1801C / QUANTUM-SHIFT नामित किया गया है) और जंप अनुरोध दर सीमक (sub_180A7EDB0, जिसे CVE-2026-180A7 / BAL-JUMP नामित किया गया है)। डिसअसेंबली विश्लेषण और अंतर्निहित स्टेट मशीनों के औपचारिक गणितीय मॉडलिंग के माध्यम से, हम दोनों ह्यूरिस्टिक्स में संरचनात्मक एज केस प्रदर्शित करते हैं। विशेष रूप से, हम दस्तावेजित करते हैं कि कैसे sub_1801C6B30 में असतत अस्थायी क्वांटीकरण निश्चित सिंगल-टिक फेज़ ऑफसेट के तहत एक अपरिवर्तनीय वर्गीकरण सीमा बनाता है, और कैसे sub_180A7EDB0 एक यूनीवेरिएंट अंतराल मीट्रिक ($\Delta t$) पर निर्भर करता है जो फेज़-लॉक्ड सिंगल-इम्पल्स ट्रिगर्स के तहत अपरिवर्तनीय रहता है।
sub_1801C6B30)server.dll (Win64 रिटेल बिल्ड)0x1C6B30void __fastcall sub_1801C6B30(int *pMovementServices, __int64 pPlayerController, __int64 pUserCmdPB)रूटीन क्लाइंट CBaseUserCmdPB पेलोड के माध्यम से प्रस्तुत मूवमेंट बटन ट्रांज़िशन इवेंट (+moveleft / +moveright) का मूल्यांकन करता है। निष्पादन एक सशर्त पाइपलाइन का अनुसरण करता है:
sv_auto_cstrafe_attempt_window, डिफ़ॉल्ट 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]);
// गेटिंग: न्यूनतम वेलोसिटी थ्रेशोल्ड
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;
// प्रतीक असाइनमेंट
char symbolCode;
if (roundedTicks == 0)
symbolCode = 1; // सफलता / परफेक्ट 0-टिक
else
symbolCode = bIsOverlap ? 2 : 3; // ओवरलैप या अंडरलैप
// ConVar कॉन्फ़िगरेशन पॉइंटर्स प्राप्त करें
unsigned int windowCap = *GetConVarUInt(&unk_181DDBD30, &qword_181DDBD38);
if (windowCap - 1 > 999)
return;
sub_1801ECEA0(pMovementServices, windowCap);
// वृत्ताकार बफर में प्रतीक जोड़ें
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;
}
}
// असतत टिक आवृत्ति हिस्टोग्राम अपडेट करें
if (bIsOverlap)
pMovementServices[roundedTicks + 7]++;
else
pMovementServices[roundedTicks + 23]++;
int seqLen = *GetConVarInt(&unk_181DDBD40, &qword_181DDBD48);
if ((unsigned int)(seqLen - 1) > 999)
return;
// स्लाइडिंग विंडो अनुक्रम मीट्रिक का मूल्यांकन करें
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++;
}
}
// स्लाइडिंग विंडो अपडेट
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); // डिफ़ॉल्ट 20.0%
float upperPct = *GetConVarFloat(&unk_181DDBD60, &qword_181DDBD68); // डिफ़ॉल्ट 5.0%
dynamicLimit = (lowerPct - upperPct) * successRatio + upperPct;
}
}
float observedOverlapPct = ((float)totalOverlaps / (float)totalValid) * 100.0f;
// उल्लंघन की स्थिति: गतिशील सीमा अवलोकित ओवरलैप अनुपात से अधिक है
if (dynamicLimit > observedOverlapPct)
{
sub_1801ECEA0(pMovementServices, 0); // बफर स्टेट फ्लश करें
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);
int slotIdx = -1;
sub_181265470(pPlayerController, &slotIdx);
// डिस्कनेक्ट कोड 162: NETWORK_DISCONNECT_KICKED_INPUTAUTOMATION
pfnKickClient(pEngine, (unsigned int)(slotIdx - 1), 0, 162);
}
}
}
मान लें कि $\mathbf{S} = {s_1, s_2, \dots, s_N}$ आकार $N$ के इतिहास बफर में इवेंट प्रतीकों के अनुक्रम का प्रतिनिधित्व करता है। पैरामीटर $S_{\text{max}}$ लंबाई $L$ के किसी भी सन्निहित उप-अनुक्रम के भीतर कोड $1$ प्रतीकों ($s_i = 1$) की अधिकतम संख्या को दर्शाता है:
$$S_{\text{max}} = \max_{0 \le j \le N - L} \sum_{i=j}^{j+L-1} \mathbb{I}(s_i = 1)$$
अनुकूली थ्रेशोल्ड फ़ंक्शन $T(S_{\text{max}})$ $S_{\text{max}} \ge S_{\text{thresh}}$ पर सशर्त है:
$$T(S_{\text{max}}) = \begin{cases} \theta_{\text{upper}} + (\theta_{\text{lower}} - \theta_{\text{upper}}) \cdot \frac{S_{\text{max}} - S_{\text{thresh}}}{L - S_{\text{thresh}}} & \text{if } S_{\text{max}} \ge S_{\text{thresh}} \ 0 & \text{if } S_{\text{max}} < S_{\text{thresh}} \end{cases}$$
जहां डिफ़ॉल्ट कॉन्फ़िगरेशन मान इस प्रकार परिभाषित हैं:
sv_auto_cstrafe_sequence_length)sv_auto_cstrafe_success_threshold)sv_auto_cstrafe_lower_overlap_pct_threshold)sv_auto_cstrafe_upper_overlap_pct_threshold)एक उल्लंघन घोषित किया जाता है यदि और केवल यदि $T(S_{\text{max}}) > P_{\text{overlap}}$, जहां $P_{\text{overlap}}$ कोड $2$ इवेंट का नमूना अनुपात है:
$$P_{\text{overlap}} = \frac{100}{N} \sum_{i=1}^{N} \mathbb{I}(s_i = 2)$$
किसी भी इनपुट स्ट्रीम के लिए जहां फेज़ ऑफसेट $\Delta t_{\text{trans}}$ इस प्रकार प्रतिबंधित है कि $k = \text{round}(\Delta t_{\text{trans}} / \tau_{\text{tick}}) \ge 1$:
pfnKickClient पर समाप्त होने वाला मूल्यांकन पथ निष्पादित नहीं रहता है।sub_180A7EDB0)server.dll (Win64 रिटेल बिल्ड)0x1A7EDB0void* __fastcall sub_180A7EDB0(__int64 pMovementServices, __int64 pMoveData)sub_180A7EDB0)void *__fastcall sub_180A7EDB0(__int64 pMovementServices, __int64 pMoveData)
{
__int64 pPawn = *(_QWORD *)(pMovementServices + 8);
sub_180C28550(pPawn, 2i64);
if (!*(_QWORD *)(pPawn + 56))
nullsub_908(pPawn);
// कोलिजन हल और ज़मीनी संपर्क मूल्यांकन
(*(void (__fastcall **)(_QWORD))(**(_QWORD **)(pPawn + 56) + 1624i64))(*(_QWORD *)(pPawn + 56));
sub_1803CBD30(*(_QWORD *)(pPawn + 56));
sub_1803CD4C0(*(_QWORD *)(pPawn + 56), v14);
if (dword_181FDB358)
--dword_181FDB358;
// कमांड बटन मास्क में IN_JUMP बिट (0x2) जांचें
if ((*(_BYTE *)(pPawn + 88) & 2) != 0 || sub_180C28550(pPawn, 2i64))
{
_BYTE *pPenaltyActive = (_BYTE *)(pMovementServices + 16);
if (*pPenaltyActive)
{
float curTime = *((float *)off_181C9F350 + 12);
float lastJumpTime = *(float *)(pMovementServices + 20);
float penaltyInterval = sub_18029CE70(&unk_181FDB4D8, 0xFFFFFFFFi64); // sv_jump_spam_penalty_time
// अंतराल मूल्यांकन: curTime > lastJumpTime + penaltyInterval
if (curTime > (penaltyInterval + lastJumpTime))
{
if (*pPenaltyActive)
{
sub_180A99DE0(pMovementServices + 16, 0xFFFFFFFFi64, 0xFFFFFFFFi64);
*pPenaltyActive = 0; // पेनल्टी स्टेट साफ़ करें
}
// जंप इम्पल्स लागू करें
sub_180A7F550(pMovementServices, pMoveData);
if (!*pPenaltyActive)
{
sub_180A99DE0(pPenaltyActive, 0xFFFFFFFFi64, 0xFFFFFFFFi64);
*pPenaltyActive = 1; // पेनल्टी स्टेट सक्रिय करें
}
if (sub_180C28550(*(_QWORD *)(pMovementServices + 8), 2i64))
{
// जंप टाइमस्टैम्प संग्रहीत करें: lastJumpTime = curTime - frameTime
*(float *)(pMovementServices + 20) = *((float *)off_181C9F350 + 12) -
*((float *)off_181C9F350 + 13);
}
return pMovementServices;
}
}
bool bDebugSpam = *GetConVarByte(&unk_181FDB640, &qword_181FDB648);
if (!bDebugSpam)
{
// जब पेनल्टी डीबग अक्षम हो तो जंप इम्पल्स लागू करें
sub_180A7F550(pMovementServices, pMoveData);
if (!*pPenaltyActive)
{
sub_180A99DE0(pPenaltyActive, 0xFFFFFFFFi64, 0xFFFFFFFFi64);
*pPenaltyActive = 1;
}
*(float *)(pMovementServices + 20) = *((float *)off_181C9F350 + 12) -
*((float *)off_181C9F350 + 13);
}
}
return pMovementServices;
}
मान लें कि $t_n$ $n$-वें जंप अनुरोध का निष्पादन टाइमस्टैम्प दर्शाता है, और $\tau_{\text{penalty}}$ sv_jump_spam_penalty_time का मान दर्शाता है (आमतौर पर $1$ टिक, या $\approx 15.625\text{ ms}$)। पेनल्टी फ्लैग $P \in {0, 1}$ और इम्पल्स सक्रियण $I \in {0, 1}$ के लिए स्टेट ट्रांज़िशन इस प्रकार परिभाषित है:
$$I_n = \begin{cases} 1 & \text{if } P_{n-1} = 0 \text{ या } t_n - t_{n-1} > \tau_{\text{penalty}} \ 0 & \text{if } P_{n-1} = 1 \text{ और } t_n - t_{n-1} \le \tau_{\text{penalty}} \end{cases}$$
FL_ONGROUND ($P_{\text{ground}} = 1$) में स्टेट ट्रांज़िशन पर जारी किया जाता है, तो अनुरोधों के बीच की अवधि बैलिस्टिक उड़ान अवधि $T_{\text{flight}}$ के अनुरूप होती है:$$t_n - t_{n-1} = T_{\text{flight}} \ge \frac{2 \cdot v_z}{g} \approx 300\text{--}500\text{ ms}$$
चूंकि $T_{\text{flight}} \gg \tau_{\text{penalty}}$, विधेय $t_n - t_{n-1} > \tau_{\text{penalty}}$ सभी $n$ के लिए बिना शर्त सत्य है, जो दमन पथ के सक्रियण को रोकता है।
| घटक | लक्ष्य सिंबल | वर्तमान प्रिमिटिव | विश्लेषणात्मक कमजोरी | प्रस्तावित सुधार |
|---|---|---|---|---|
| इनपुट ऑटोमेशन | sub_1801C6B30 | बाइनरी वर्गीकरण ($k=0$ बनाम $k \ge 1$) + थ्रेशोल्डिंग | निश्चित फेज़ ऑफसेट ($k=1$) समान रूप से $S_{\text{max}} = 0$ देता है | सभी $k$ में नमूना विचरण $\sigma^2(\Delta t)$ का मूल्यांकन करें; बिन इंडेक्स की परवाह किए बिना कम-विचरण वितरण को फ्लैग करें |
| जंप दर सीमा | sub_180A7EDB0 | स्केलर समय डेल्टा तुलना ($t_n - t_{n-1} > \tau$) | हवाई फेज़ विलंब ($T_{\text{flight}} \gg \tau$) के तहत अपरिवर्तनीय | वेलोसिटी वेक्टर निरंतरता और ज़मीनी संपर्क अवधि ($\Delta t_{\text{contact}}$) का मूल्यांकन करें |