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

Исходник [Сурс] Windows — Подмена статуса Secure Boot и обход TPM Attestation (C++)

  • Автор темы Автор темы hex_cat
  • Дата начала Дата начала
Sloppy
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
13 Фев 2026
Сообщения
567
Реакции
15
Народ, кто сейчас ковыряет обходы для Ring 0, подкинул вам годноту по части эмуляции Secure Boot. Слил базу, потому что сам в свое время намучался с аттестацией TPM и кривыми рег-ключами.

Суть в том, что обычный спуфер или патч может не помочь, если античит делает полноценную проверку через TPM-аттестацию. Этот код позволяет пропатчить значения в ядре и подправить реестр (WCBL), чтобы система «думала», что Secure Boot включен, даже если вы его отключили для тестов или работы с драйверами.

Технические моменты:
  1. Работа с NtosKrnl: Используется паттерн для поиска HalEfiRuntimeServicesTable. Работает как на десятке, так и на одиннадцатой винде.
  2. WCBL Fix: Функция SetWCBLFile и SetWCBLRegistry лезут в логи платформы и правят байты, отвечающие за статус Secure Boot.
  3. KUSER_SHARED_DATA: Классика — форсим DbgSecureBootEnabled в единицу прямо в структуре данных ядра.

Код:
Expand Collapse Copy
#include "Driver.h"
 
//48 8B 05 ? ? ? ? 48 8B ? 0F 11 45 ? 48 85 C0 = HalEfiRuntimeServicesTable -> works on win11 and win10!
 
VOID SetSecureBootNtosValue()
{
    static CHAR szSig[] = "C1 E8 03 24 01 88 42 01";  
 
    pDriver->ulSecureBootValueAddress = FindPattern( pDriver->ulNtosKrnlBase, pDriver->ulNtosKrnlSize, szSig, -0x6, TRUE, 0x2 ); 
 
    memset( szSig, 0, sizeof(szSig) ); 
 
    //DBGPRINT( "SetSecureBootNtosValue::ulAddress: %p", ulAddress ); 
 
    if(!pDriver->ulSecureBootValueAddress)
        return; 
 
    ULONG ulValue = *(ULONG*)(pDriver->ulSecureBootValueAddress); 
    pDriver->ulSecureBootOrigValue = ulValue; 
 
    //DBGPRINT( "SetSecureBootNtosValue::Value 1: %x", ulValue ); 
 
    ulValue |= 0x1; 
    ulValue |= 0x8; 
 
    *(ULONG*)(pDriver->ulSecureBootValueAddress) = ulValue; 
 
    //DBGPRINT( "SetSecureBootNtosValue::Value 2: %x", ulValue ); 
}
 
VOID SetSecureBootRegKey()
{
    CHAR szSecureBootState[128] = {0}; 
    GetDecryptedString( STRING_REG_KEYPATH_SECUREBOOTSTATE, szSecureBootState ); 
 
    CHAR szUEFISecureBootEnabled[128] = {0}; 
    GetDecryptedString( STRING_REG_KEYNAME_UEFISECUREBOOTENABLED, szUEFISecureBootEnabled ); 
 
    WCHAR wzSecureBootState[128] = {0};
    mbstowcs( wzSecureBootState, szSecureBootState, 128 ); 
 
    WCHAR wzUEFISecureBootEnabled[128] = {0}; 
    mbstowcs( wzUEFISecureBootEnabled, szUEFISecureBootEnabled, 128 ); 
 
    UNICODE_STRING usKeyPath, usValueName;  
    RtlInitUnicodeString( &usKeyPath, wzSecureBootState ); 
    RtlInitUnicodeString( &usValueName, wzUEFISecureBootEnabled );  
 
    OBJECT_ATTRIBUTES obj; 
    InitializeObjectAttributes( &obj, &usKeyPath, OBJ_CASE_INSENSITIVE, NULL, NULL ); 
 
    HANDLE hKey = 0;
    NTSTATUS ntRet = ZwOpenKey( &hKey, KEY_ALL_ACCESS, &obj );
 
    if(ntRet == STATUS_SUCCESS)
    {
        DWORD dwValue = 0x1; 
        ZwSetValueKey( hKey, &usValueName, 0, REG_DWORD, (PVOID)&dwValue, sizeof(DWORD) ); 
 
        ZwClose( hKey ); 
    }
} 
 
VOID SetWCBLFile( PWCHAR pPath )
{
    UNICODE_STRING usPath;
    RtlInitUnicodeString( &usPath, pPath ); 
 
    OBJECT_ATTRIBUTES Obj;
    InitializeObjectAttributes( &Obj, &usPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL ); 
 
    CHAR szStatus[256] = {0}; 
    HANDLE hFile = 0;
    NTSTATUS ntRet = ZwCreateFile( &hFile, FILE_ALL_ACCESS, &Obj, (PIO_STATUS_BLOCK)&szStatus[0], NULL, 
        FILE_ATTRIBUTE_SYSTEM, 0, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
 
    //DBGPRINT( "SetWCBLFile::ntRet: %x", ntRet ); 
    
    if(ntRet == STATUS_SUCCESS)
    {
        //DBGPRINT( "SetWCBLFile::Querying...." ); 
 
        FILE_STANDARD_INFORMATION FileInfo = {0};
        if(ZwQueryInformationFile( hFile, (PIO_STATUS_BLOCK)&szStatus, (PVOID)&FileInfo, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation ) == STATUS_SUCCESS)
        {
            ULONG ulFileLen = FileInfo.EndOfFile.LowPart;
 
            //DBGPRINT( "SetWCBLFile::dwFileLen: %x", ulFileLen ); 
 
            if(ulFileLen > 0x10)
            {
                PBYTE pAlloc = (PBYTE)ExAllocatePool( NonPagedPool, ulFileLen + 1 );
 
                //DBGPRINT( "SetWCBLFile::pAlloc: %p", pAlloc ); 
 
                if(pAlloc)
                {
                    CHAR szStatus[256] = {0}; 
 
                    LARGE_INTEGER liOffset = {0}; 
                    ntRet = ZwReadFile( hFile, NULL, NULL, NULL, (PIO_STATUS_BLOCK)&szStatus[0], pAlloc, ulFileLen, &liOffset, NULL ); 
 
                    if(ntRet == STATUS_SUCCESS)
                    {            
                        //DBGPRINT( "SetWCBLFile::Read Succeeded!" ); 
 
                        memset( szStatus, 0, 256 ); 
 
                        INT iSecureBootIndex = 0, iSizeIndex = 0, iSecureBootIndex2 = 0; 
 
                        //DBGPRINT( "SetWCBLFile::FileSize: %x", ulFileLen ); 
 
                        for(int i = 0; i < (int)(ulFileLen - 0x10); i++)
                        {
                            if( *(ULONG_PTR*)(&pAlloc[i]) == 0x0075006300650053 ) //S.e.c.u
                            {
                                iSizeIndex = i - 0x24;
                                iSecureBootIndex = i + 0x14; 
                                iSecureBootIndex2 = i - 0x8; 
                                break; 
                            }
                        }
 
                        //DBGPRINT( "SetWCBLFile::iSizeIndex: %x", iSizeIndex ); 
                        //DBGPRINT( "SetWCBLFile::iSecureBootIndex: %x", iSecureBootIndex ); 
 
                        if(pAlloc[iSizeIndex] == 0x34)
                        {
                            //DBGPRINT( "SetWCBLFile::Fixing Size!" ); 
 
                            memcpy( &pAlloc[iSecureBootIndex + 1], &pAlloc[iSecureBootIndex], ulFileLen - iSecureBootIndex );
 
                            pAlloc[iSizeIndex] += 0x1; 
                            pAlloc[iSecureBootIndex] = 0x1; 
                            pAlloc[iSecureBootIndex2] = 0x1; 
 
                            ulFileLen += 1; 
                        }
                        else if(pAlloc[iSizeIndex] == 0x35)
                        {
                            pAlloc[iSecureBootIndex] = 0x1; 
                            pAlloc[iSecureBootIndex2] = 0x1; 
 
                            //DBGPRINT( "SetWCBLFile::Set SB Byte!" ); 
                        }
 
                        liOffset.QuadPart = 0; 
                        ntRet = ZwWriteFile( hFile, 0, 0, 0, (PIO_STATUS_BLOCK)&szStatus[0], (PVOID)pAlloc, ulFileLen, &liOffset, 0 );
 
                        //DBGPRINT( "SetWCBLFile::ZwWriteFile: %x", ntRet ); 
                    }
                    else
                    {
                        //DBGPRINT( "SetWCBLFile::READ FAILED ON BOOTFILE: %x", ntRet ); 
                    }
 
                    ExFreePool( pAlloc ); 
                }
            }
        }
        else
        {
            //DBGPRINT( "SetWCBLFile::QUERY FAILED ON BOOTFILE!" ); 
        }
 
        ZwClose( hFile ); 
    }
    else
    {
        //DBGPRINT( "SetWCBLFile::ZwCreateFile: %x", ntRet ); 
    }
}
 
VOID SetRegistryKey( PWCHAR wPath, PWCHAR wKeyName, INT Type, PVOID pData, INT Len )
{
    HANDLE hKey = 0;
    UNICODE_STRING usKeyPath, usValueName;  
 
    RtlInitUnicodeString( &usKeyPath, wPath ); 
    RtlInitUnicodeString( &usValueName, wKeyName ); 
 
    OBJECT_ATTRIBUTES obj; 
    InitializeObjectAttributes( &obj, &usKeyPath, OBJ_CASE_INSENSITIVE, NULL, NULL ); 
 
    NTSTATUS ntRet = ZwOpenKey( &hKey, KEY_ALL_ACCESS, &obj );
 
    if(ntRet == STATUS_SUCCESS)
    {
        ZwSetValueKey( hKey, &usValueName, 0, Type, (PVOID)pData, Len );
 
        ZwClose( hKey ); 
    }
}
 
VOID SetWCBLRegistry()
{    
    CHAR szIntegrityServices[128] = {0}; 
    GetDecryptedString( STRING_REG_KEYPATH_INTEGRITYSERVICES, szIntegrityServices ); 
 
    CHAR szWBCL[128] = {0}; 
    GetDecryptedString( STRING_REG_KEYNAME_WBCL, szWBCL ); 
 
    WCHAR wzIntegrityServices[128] = {0};
    mbstowcs( wzIntegrityServices, szIntegrityServices, 128 ); 
 
    WCHAR wzWBCL[128] = {0}; 
    mbstowcs( wzWBCL, szWBCL, 128 ); 
 
    UNICODE_STRING usKeyPath, usValueName;  
    RtlInitUnicodeString( &usKeyPath, wzIntegrityServices ); 
    RtlInitUnicodeString( &usValueName, wzWBCL ); 
 
    OBJECT_ATTRIBUTES obj; 
    InitializeObjectAttributes( &obj, &usKeyPath, OBJ_CASE_INSENSITIVE, NULL, NULL ); 
 
    HANDLE hKey = 0;
    if(ZwOpenKey( &hKey, KEY_ALL_ACCESS, &obj ) == STATUS_SUCCESS)
    {
        PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool( NonPagedPool, WBCL_SIZE * 2 );  //Make this alloc static inside driver so A/C can't see the allocs???
 
        if(pKeyInfo)
        {
            ULONG ulOutSize = 0; 
            NTSTATUS ntRet = ZwQueryValueKey( hKey, &usValueName, KeyValuePartialInformation, (PVOID)pKeyInfo, WBCL_SIZE * 2, &ulOutSize );
 
            if(ntRet == STATUS_SUCCESS )
            {
                INT iSecureBootIndex = 0, iSizeIndex = 0, iSecureBootIndex2 = 0; 
 
                for(int i = 0; i < (int)(pKeyInfo->DataLength - 0x10); i++)
                {
                    if( *(ULONG_PTR*)(&pKeyInfo->Data[i]) == 0x0075006300650053 ) //S.e.c.u
                    {
                        iSizeIndex = i - 0x24;
                        iSecureBootIndex = i + 0x14; 
                        iSecureBootIndex2 = i - 0x8; 
                        break; 
                    }
                }
 
                //DBGPRINT( "SetWCBLRegistry::DataLength: %x", pKeyInfo->DataLength ); 
                //DBGPRINT( "SetWCBLRegistry::iSizeIndex: %x", iSizeIndex ); 
                //DBGPRINT( "SetWCBLRegistry::iSecureBootIndex: %x", iSecureBootIndex ); 
 
                if(pKeyInfo->Data[iSizeIndex] == 0x34)
                {
                    //DBGPRINT( "SetWCBLRegistry::Fixing Size!" ); 
 
                    memcpy( &pKeyInfo->Data[iSecureBootIndex + 1], &pKeyInfo->Data[iSecureBootIndex], pKeyInfo->DataLength - iSecureBootIndex );
 
                    pKeyInfo->Data[iSizeIndex] += 0x1; 
                    pKeyInfo->Data[iSecureBootIndex] = 0x1; 
                    pKeyInfo->Data[iSecureBootIndex2] = 0x1; 
 
                    pKeyInfo->DataLength += 1; 
                }
                else if(pKeyInfo->Data[iSizeIndex] == 0x35)
                {
                    *(BYTE*)(&pKeyInfo->Data[iSecureBootIndex]) = 0x1; 
 
                    //DBGPRINT( "SetWCBLRegistry::Set SB Byte!" ); 
                }
 
                if(iSecureBootIndex && iSizeIndex)
                {
                    SetRegistryKey( wzIntegrityServices, wzWBCL, REG_BINARY, (PVOID)pKeyInfo->Data, pKeyInfo->DataLength );
                }
 
                //DBGPRINT( "SetWCBLRegistry::WBCL REGISTRY SET!" ); 
            }
 
            ExFreePool( pKeyInfo ); 
        }
 
        ZwClose( hKey ); 
    }
}
 
BOOL GetPlatformLogFilePath( PWCHAR pOut )
{
    CHAR szIntegrityServices[128] = {0}; 
    GetDecryptedString( STRING_REG_KEYPATH_INTEGRITYSERVICES, szIntegrityServices ); 
 
    CHAR szPlatformLogFile[128] = {0}; 
    GetDecryptedString( STRING_REG_KEYNAME_PLATFORMLOGFILE, szPlatformLogFile ); 
 
    WCHAR wzIntegrityServices[128] = {0};
    mbstowcs( wzIntegrityServices, szIntegrityServices, 128 ); 
 
    WCHAR wzPlatformLogFile[128] = {0}; 
    mbstowcs( wzPlatformLogFile, szPlatformLogFile, 128 ); 
 
    UNICODE_STRING usKeyPath, usValueName;  
    RtlInitUnicodeString( &usKeyPath, wzIntegrityServices ); 
    RtlInitUnicodeString( &usValueName, wzPlatformLogFile ); 
 
    OBJECT_ATTRIBUTES obj; 
    InitializeObjectAttributes( &obj, &usKeyPath, OBJ_CASE_INSENSITIVE, NULL, NULL ); 
 
    BOOL bRet = FALSE; 
 
    HANDLE hKey = 0;
    if(ZwOpenKey( &hKey, KEY_ALL_ACCESS, &obj ) == STATUS_SUCCESS)
    {
        PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool( NonPagedPool, 256 * sizeof(WCHAR) );  //Make this alloc static inside driver so A/C can't see the allocs???
 
        if(pKeyInfo)
        {
            ULONG ulOutSize = 0; 
            if(ZwQueryValueKey( hKey, &usValueName, KeyValuePartialInformation, (PVOID)pKeyInfo, 256 * sizeof(WCHAR), &ulOutSize ) == STATUS_SUCCESS )
            {
                swprintf( pOut, L"%s", (PWCHAR)pKeyInfo->Data );
 
                bRet = TRUE; 
            }
 
            ExFreePool( pKeyInfo ); 
        }
 
        ZwClose( hKey );
    }
 
    return bRet; 
}
 
VOID SetTPMRegister()
{
    WCHAR wzPlatformFilePath[256] = {0}; 
    if(GetPlatformLogFilePath( wzPlatformFilePath ) )
    {
        SetWCBLFile( wzPlatformFilePath ); 
        SetWCBLRegistry();
    }
}
 
VOID SetUserSharedDataSecureBoot()
{
    _KUSER_SHARED_DATA2* pSharedData = (_KUSER_SHARED_DATA2*)KI_USER_SHARED_DATA;
 
    //DBGPRINT( "pSharedData->DbgSecureBootEnabled 1: %d", pSharedData->DbgSecureBootEnabled ); 
 
    _KUSER_SHARED_DATA2* pAlloc = (_KUSER_SHARED_DATA2*)ExAllocatePool( NonPagedPool, sizeof(_KUSER_SHARED_DATA2) ); 
 
    if(pAlloc)
    {
        memcpy( pAlloc, pSharedData, sizeof(_KUSER_SHARED_DATA2) ); 
 
        pAlloc->DbgSecureBootEnabled = 1; 
 
        SafeWrite( (PVOID)&pSharedData->SharedDataFlags, (PVOID)&pAlloc->SharedDataFlags, sizeof(ULONG) );
 
        ExFreePool( pAlloc ); 
    }
 
    //DBGPRINT( "pSharedData->DbgSecureBootEnabled 2: %d", pSharedData->DbgSecureBootEnabled ); 
}

Важно для понимания:
Код — это база. Как правильно заметили в источнике, если АС серьезный (типа Вангарда или жесткого Ricochet), то аттестация TPM может вас слить в момент. Лучший вариант — врубать Secure Boot в BIOS и юзать мануальный маппинг с хорошим драйвером, который умеет обходить Driver Signature Enforcement без отключения SB. Но для специфичных нужд или тестов на виртуалках/вторичках — самое то.

Братва, кто уже пробовал прокидывать подобные хуки через ZwQueryValueKey на актуальных билдах? Не отлетаете в пермач по Kernel Callback? Делитесь опытом, кто допиливал под себя, кидайте свои правки или методы оптимизации аллокаций, чтобы АС не палил ExAllocatePool.
 
Назад
Сверху Снизу