Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Гайд [Сурс] Spoofing SecureBoot & EFI — манипуляция состоянием системы без хуков

Sloppy
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
13 Фев 2026
Сообщения
635
Реакции
17
Задолбали проверки Secure Boot в современных античитах?

Когда античит требует включить Secure Boot (привет, Vanguard и свежие апдейты Faceit), большинство идет крутить настройки BIOS. Но если вы пишете свой драйвер или маппер, вешать хуки на системные вызовы — это слишком громко и чревато быстрым детектом по сигнатурам.

Нашел интересный метод прямой манипуляции переменными в ядре. Суть в том, чтобы пропатчить флаги в CI.dll и подменить кэшированные данные в hal.dll без использования стандартных техник перехвата.

Что внутри реализации:
  1. Скан CI.dll: ищем глобальную переменную g_CiOptions. Код находит инструкцию через паттерн, резолвит смещение относительно RIP и ручками выставляет бит включенной проверки целостности (CI), одновременно отключая Test Signing.
  2. Реестр: В коде прописан проброс стандартных ключей в SecureBoot\State и CI\Protected. Это база, которую чекают простые АС через юзермод.
  3. Скан секций hal.dll: Самое интересное. Код проходит по секциям инициализированных данных HAL, ищет Unicode-строку "SecureBoot" и патчит связанные с ней значения EFI-переменных прямо в памяти.

Код:
Expand Collapse Copy
//  CI.dll kernel variable + registry
 
inline void SpoofSecureBoot()
{
 
        ULONG ciSize = 0;
        PVOID ciBase = GetKernelModule("CI.dll", &ciSize);
        if (ciBase && ciSize)
        {
            // CiInitialize references g_CiOptions via:
            //   "or dword ptr [rip+disp32], imm8"  → 83 0D XX XX XX XX YY
            // We find this pattern and resolve the global variable.
            UCHAR pat[] = { 0x83, 0x0D };
            char  msk[] = "xx";
 
            PUCHAR found = PatternScan(ciBase, ciSize, pat, msk, 2);
            if (found && MmIsAddressValid(found))
            {
                // Instruction: 83 0D [disp32] [imm8] = 7 bytes total
                if (MmIsAddressValid(found + 2) && MmIsAddressValid(found + 5))
                {
                    LONG disp = *(LONG*)(found + 2);
                    PUCHAR target = found + 7 + disp;   // RIP after 7-byte instruction
                    if (MmIsAddressValid(target) && MmIsAddressValid(target + 3))
                    {
                        ULONG* ciOpt = (ULONG*)target;
                        // Bit 0 = CI enabled, bit 3 = test signing
                        // Set CI enabled, clear test signing
                        *ciOpt = (*ciOpt | 0x1) & ~0x8;
                    }
                }
            }
    }
 
    // ── Registry Layer ───────────────────────────────────────────────
    RegSetDw(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
        L"\\Control\\SecureBoot\\State", L"UEFISecureBootEnabled", 1);
    RegSetDw(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
        L"\\Control\\CI\\Protected", L"Licensed", 1);
    RegSetDw(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
        L"\\Control\\CI", L"UMCIAuditMode", 0);
}
 
//  HAL module data section scan
 
inline void SpoofEfiVars()
{
    ULONG halSize = 0;
    PVOID halBase = GetKernelModule("hal.dll", &halSize);
    if (!halBase || !halSize) return;
 
    // Scan hal.dll data sections for cached "SecureBoot" variable
    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)halBase;
    if (!MmIsAddressValid(dos) || dos->e_magic != IMAGE_DOS_SIGNATURE) return;
    PIMAGE_NT_HEADERS64 nt = (PIMAGE_NT_HEADERS64)((PBYTE)halBase + dos->e_lfanew);
    if (!MmIsAddressValid(nt) || nt->Signature != IMAGE_NT_SIGNATURE) return;
 
    PIMAGE_SECTION_HEADER sec = IMAGE_FIRST_SECTION(nt);
    for (USHORT si = 0; si < nt->FileHeader.NumberOfSections; si++, sec++)
    {
        if (!MmIsAddressValid(sec)) break;
        if (!(sec->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)) continue;
 
        PBYTE secBase = (PBYTE)halBase + sec->VirtualAddress;
        ULONG secLen = sec->Misc.VirtualSize;
 
 
        const WCHAR target[] = L"SecureBoot";
        ULONG tgtBytes = sizeof(target) - sizeof(WCHAR); // 20 bytes
 
        for (ULONG off = 0; off + tgtBytes + 8 < secLen; off += 2)
        {
            if (!MmIsAddressValid(secBase + off)) { off = (off | 0xFFF) + 1; continue; }
 
            BOOLEAN match = TRUE;
            for (ULONG c = 0; c < tgtBytes; c++) {
                if (!MmIsAddressValid(secBase+off+c)) { match = FALSE; break; }
                if (secBase[off+c] != ((PUCHAR)target)[c]) { match = FALSE; break; }
            }
            if (!match) continue;
 
            // Found "SecureBoot" string in HAL.
            // The variable data (0 or 1) is typically stored in a structure
            // near/after the variable name. Scan forward for a single-byte
            // value field (0x00 or 0x01).
            for (ULONG v = tgtBytes; v < tgtBytes + 128; v += 4) {
                if (!MmIsAddressValid(secBase+off+v)) break;
                // Look for a DWORD-aligned value of 0 or 1
                ULONG val = *(ULONG*)(secBase+off+v);
                if (val == 0 || val == 1) {
                    *(ULONG*)(secBase+off+v) = 1;  // Set SecureBoot = enabled
                }
            }
        }
    }
}

Технические нюансы:
Паттерн 83 0D для CI — это классика, но учитывайте, что в разных билдах Windows инструкции могут меняться. Обязательно проверяйте смещения перед тем, как кастить указатель к ULONG. Прямая запись в ciOpt и секции HAL может триггернуть PatchGuard (BSOD CRITICAL_STRUCTURE_CORRUPTION), если делать это в неподходящий момент или на системах с активным HVCI.

\Registry\Machine\SYSTEM\CurrentControlSet\Control\SecureBoot\State -> UEFISecureBootEnabled = 1
\Registry\Machine\SYSTEM\CurrentControlSet\Control\CI\Protected -> Licensed = 1
\Registry\Machine\SYSTEM\CurrentControlSet\Control\CI -> UMCIAuditMode = 0

Для полноценного обхода сейчас одного этого мало (нужно еще возиться с TPM и имитировать состояние реестра для конкретного процесса античита), но как кусок тех-базы для своего проекта метод отличный.

Кто как сейчас борется с проверками на Windows 11, делитесь идеями по обходу HVCI и TPM в комментариях.
 
Назад
Сверху Снизу