Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
أدوات/GitHubGitHub/misterdengi/cve-2026-1801c
تحليل الثغرات الأمنيةالاستغلالالهندسة العكسيةتحليل الملفات الثنائيةالأوراق والأبحاث
GitHubmisterdengi/cve-2026-1801c

CVE-2026-1801C

تحليل هندسة عكسية ثابتة لاستدلالات إدخال الحركة في محرك Source 2، مع تحديد الحالات الحدودية البنيوية في أتمتة الإدخال وروتينات الحد من معدل القفز.

عرض المستودع
2منذ 5س 47دلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

CVE-2026-1801C (QUANTUM-SHIFT) / CVE-2026-180A7 (BAL-JUMP): تحليل ثابت لخوارزميات التحقق من مدخلات الحركة في Source 2 (server.dll)

الملخص

تقدّم هذه الورقة تحليلاً هندسيًا عكسيًا ثابتًا لروتينين للتحقق من الحركة من جانب العميل مطبّقين في محرك Counter-Strike 2 (server.dll): مُقيّم أتمتة الإدخال / SOCD (sub_1801C6B30، المعيّن CVE-2026-1801C / QUANTUM-SHIFT) ومُحدِّد معدل طلبات القفز (sub_180A7EDB0، المعيّن CVE-2026-180A7 / BAL-JUMP). من خلال تحليل التفكيك والنمذجة الرياضية الرسمية لآلات الحالة الأساسية، نُظهر حالات حافة بنيوية في كلا الخوارزميتين. على وجه التحديد، نوثّق كيف يُنشئ التكميم الزمني المنفصل في sub_1801C6B30 حدًا تصنيفيًا ثابتًا تحت إزاحات طورية ثابتة بإطار واحد، وكيف يعتمد sub_180A7EDB0 على مقياس فاصل زمني أحادي المتغير ($\Delta t$) يبقى ثابتًا تحت محفزات نبضية مفردة مقفلة الطور.


1. التحقق من أتمتة الإدخال (sub_1801C6B30)

1.1 مواصفات الروتين

  • الملف الثنائي المستهدف: server.dll (إصدار Win64 Retail)
  • إزاحة الرمز: 0x1C6B30
  • الواجهة: void __fastcall sub_1801C6B30(int *pMovementServices, __int64 pPlayerController, __int64 pUserCmdPB)

1.2 خط أنابيب التنفيذ وتمثيل الحالة

يقيّم الروتين أحداث انتقال أزرار الحركة (+moveleft / +moveright) المُرسلة عبر حمولات CBaseUserCmdPB من العميل. يتبع التنفيذ خط أنابيب شرطيًا:

  1. بوابة السرعة: يجب أن يتجاوز مربع مقدار السرعة العددية ثنائية الأبعاد للشخصية عتبة ثابتة: $$|v_{xy}|^2 > (0.52 \cdot 260.0)^2 = 18279.04 \text{ وحدة}^2/\text{ثانية}^2$$
  2. التكميم الزمني: يتم تكميم فروق طور الانتقال ($\Delta t_{\text{trans}}$) إلى وحدات إطارات منفصلة: $$k = \text{round}\left( \frac{\Delta t_{\text{trans}}}{\tau_{\text{tick}}} \right), \quad \tau_{\text{tick}} \approx 15.625\text{ مللي ثانية}$$
  3. التصنيف الرمزي: القيمة الصحيحة $k \in [0, 15]$ تُرسم إلى رمز حدث منفصل $c \in {1, 2, 3}$: $$c = \begin{cases} 1 & \text{إذا كان } k = 0 \text{ (انتقال مثالي بصفر إطار)} \ 2 & \text{إذا كان } k \ge 1 \text{ والحالة Overlap} \ 3 & \text{إذا كان } k \ge 1 \text{ والحالة Underlap} \end{cases}$$
  4. تخزين الحلقة الدائرية: يُخزَّن رمز التصنيف $c$ في مصفوفة تاريخ دائرية بسعة $N$ (sv_auto_cstrafe_attempt_window، الافتراضي 100).

1.3 المنطق المُفكَّك (sub_1801C6B30)

root@kitploit:~
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]);
    
    // Gating: Minimum velocity threshold
    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;

    // Symbol Assignment
    char symbolCode;
    if (roundedTicks == 0)
        symbolCode = 1; // Success / Perfect 0-tick
    else
        symbolCode = bIsOverlap ? 2 : 3; // Overlap or Underlap

    // Fetch ConVar configuration pointers
    unsigned int windowCap = *GetConVarUInt(&unk_181DDBD30, &qword_181DDBD38);
    if (windowCap - 1 > 999)
        return;

    sub_1801ECEA0(pMovementServices, windowCap);

    // Append symbol to circular buffer
    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;
        }
    }

    // Update discrete tick frequency histograms
    if (bIsOverlap)
        pMovementServices[roundedTicks + 7]++;
    else
        pMovementServices[roundedTicks + 23]++;

    int seqLen = *GetConVarInt(&unk_181DDBD40, &qword_181DDBD48);
    if ((unsigned int)(seqLen - 1) > 999)
        return;

    // Evaluate sliding window sequence metrics
    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++;
            }
        }

        // Sliding window update
        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); // Default 20.0%
            float upperPct = *GetConVarFloat(&unk_181DDBD60, &qword_181DDBD68); // Default 5.0%
            
            dynamicLimit = (lowerPct - upperPct) * successRatio + upperPct;
        }
    }

    float observedOverlapPct = ((float)totalOverlaps / (float)totalValid) * 100.0f;

    // Violation Condition: Dynamic limit exceeds observed overlap ratio
    if (dynamicLimit > observedOverlapPct)
    {
        sub_1801ECEA0(pMovementServices, 0); // Flush buffer state
        
        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);
            
            // Disconnect Code 162: NETWORK_DISCONNECT_KICKED_INPUTAUTOMATION
            pfnKickClient(pEngine, (unsigned int)(slotIdx - 1), 0, 162);
        }
    }
}

1.4 النموذج الرياضي وتحليل التصنيف

لنفترض أن $\mathbf{S} = {s_1, s_2, \dots, s_N}$ يمثل تسلسل رموز الأحداث في مخزن التاريخ بحجم $N$. تشير المعلمة $S_{\text{max}}$ إلى الحد الأقصى لعدد رموز الكود $1$ ($s_i = 1$) داخل أي تسلسل فرعي متصل بطول $L$:

$$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{إذا كان } S_{\text{max}} \ge S_{\text{thresh}} \ 0 & \text{إذا كان } S_{\text{max}} < S_{\text{thresh}} \end{cases}$$

حيث تُعرَّف قيم التكوين الافتراضية على النحو التالي:

  • $L = 15$ (sv_auto_cstrafe_sequence_length)
  • $S_{\text{thresh}} = 10$ (sv_auto_cstrafe_success_threshold)
  • $\theta_{\text{lower}} = 20.0$ (sv_auto_cstrafe_lower_overlap_pct_threshold)
  • $\theta_{\text{upper}} = 5.0$ (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$:

  1. $s_i \in {2, 3}$ لجميع $i$، مما ينتج $\mathbb{I}(s_i = 1) = 0$.
  2. وبالتالي، $S_{\text{max}} = 0$.
  3. بما أن $0 < S_{\text{thresh}}$، فإن $T(S_{\text{max}}) = 0$ يتحقق بشكل مطابق.
  4. المتباينة $0 > P_{\text{overlap}}$ تُقيَّم على أنها خاطئة لجميع قيم $P_{\text{overlap}}$ غير السالبة. يبقى مسار التقييم المنتهي عند pfnKickClient غير منفَّذ.

2. تحديد معدل القفز (sub_180A7EDB0)

2.1 مواصفات الروتين

  • الملف الثنائي المستهدف: server.dll (إصدار Win64 Retail)
  • إزاحة الرمز: 0x1A7EDB0
  • الواجهة: void* __fastcall sub_180A7EDB0(__int64 pMovementServices, __int64 pMoveData)

2.2 المنطق المُفكَّك (sub_180A7EDB0)

root@kitploit:~
void *__fastcall sub_180A7EDB0(__int64 pMovementServices, __int64 pMoveData)
{
    __int64 pPawn = *(_QWORD *)(pMovementServices + 8);
    sub_180C28550(pPawn, 2i64);
    
    if (!*(_QWORD *)(pPawn + 56))
        nullsub_908(pPawn);

    // Collision hull & ground contact evaluation
    (*(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;

    // Check IN_JUMP bit (0x2) in command button mask
    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

            // Interval evaluation: curTime > lastJumpTime + penaltyInterval
            if (curTime > (penaltyInterval + lastJumpTime))
            {
                if (*pPenaltyActive)
                {
                    sub_180A99DE0(pMovementServices + 16, 0xFFFFFFFFi64, 0xFFFFFFFFi64);
                    *pPenaltyActive = 0; // Clear penalty state
                }

                // Apply jump impulse
                sub_180A7F550(pMovementServices, pMoveData);

                if (!*pPenaltyActive)
                {
                    sub_180A99DE0(pPenaltyActive, 0xFFFFFFFFi64, 0xFFFFFFFFi64);
                    *pPenaltyActive = 1; // Engage penalty state
                }

                if (sub_180C28550(*(_QWORD *)(pMovementServices + 8), 2i64))
                {
                    // Store jump timestamp: 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)
        {
            // Apply jump impulse when penalty debug is disabled
            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;
}

2.3 نموذج التوقيت وتقييم الفاصل الزمني

لنفترض أن $t_n$ يشير إلى الطابع الزمني لتنفيذ طلب القفز رقم $n$، وأن $\tau_{\text{penalty}}$ يشير إلى قيمة sv_jump_spam_penalty_time (عادةً إطار واحد، أو $\approx 15.625\text{ مللي ثانية}$). يُعرَّف انتقال الحالة لعلامة العقوبة $P \in {0, 1}$ وتفعيل الدفعة $I \in {0, 1}$ على النحو التالي:

$$I_n = \begin{cases} 1 & \text{إذا كان } P_{n-1} = 0 \text{ أو } t_n - t_{n-1} > \tau_{\text{penalty}} \ 0 & \text{إذا كان } P_{n-1} = 1 \text{ و } t_n - t_{n-1} \le \tau_{\text{penalty}} \end{cases}$$

تحليل التردد العالي مقابل المدخلات المقفلة بحالة الأرض

  1. تدفقات الإدخال عالية التردد: تنتج تدفقات الإدخال المنفصلة المُولَّدة عبر إطارات متتالية فترات زمنية $t_n - t_{n-1} \approx \tau_{\text{tick}} \le \tau_{\text{penalty}}$. تحت هذا الشرط، $I_n = 0$، مما يمنع توليد الدفعة الرأسية.
  2. قفل الطور بحالة الأرض: إذا صدر أمر القفز حصريًا عند الانتقال إلى 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{ مللي ثانية}$$

بما أن $T_{\text{flight}} \gg \tau_{\text{penalty}}$، فإن المسند $t_n - t_{n-1} > \tau_{\text{penalty}}$ يتحقق بشكل غير مشروط لجميع $n$، مما يمنع تفعيل مسار القمع.


3. ملخص المعالجة البنيوية

المكوّنالرمز المستهدفالبدائية الحاليةالضعف التحليليالمعالجة المقترحة
أتمتة الإدخالsub_1801C6B30تصنيف ثنائي ($k=0$ مقابل $k \ge 1$) + تحديد عتبةإزاحة الطور الثابتة ($k=1$) تنتج $S_{\text{max}} = 0$ بشكل مطابقتقييم تباين العينة $\sigma^2(\Delta t)$ عبر جميع قيم $k$؛ وضع علامة على التوزيعات منخفضة التباين بغض النظر عن فهرس الحاوية
تحديد معدل القفزsub_180A7EDB0مقارنة فرق زمني قياسي ($t_n - t_{n-1} > \tau$)ثابت تحت تأخيرات الطور الجوي ($T_{\text{flight}} \gg \tau$)تقييم استمرارية متجه السرعة ومدة ملامسة الأرض ($\Delta t_{\text{contact}}$)
تنزيل الأداة