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

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

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
13 Фев 2026
Сообщения
180
Реакции
5
Народ, кто сейчас ковыряет обходы для 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.
 
Назад
Сверху Снизу