Partilhar via


Guia de desenvolvimento para enclaves de segurança baseada em virtualização (VBS)

Aplica-se a:✅ Windows 11 Build 26100.2314 ou posterior ✅ Windows Server 2025 ou posterior

Este guia de desenvolvimento descreve como criar, assinar e testar um enclave VBS básico.

Pré-requisitos

Para começar a usar o VBS Enclaves, você precisa atender aos seguintes requisitos:

  • Veja e preencha os requisitos do dispositivo na Visão Geral dos Enclaves VBS.
  • Visualize e satisfaça os pré-requisitos de desenvolvimento na visão geral do VBS Enclaves.
    • É recomendável instalar o desenvolvimento para desktop com C++ através do instalador do Visual Studio. Ele instalará todas as ferramentas necessárias, incluindo o Windows Software Development Kit (SDK).
  • Baixe o código de exemplo do GitHub. O texto demonstra o ciclo de vida de um enclave VBS, incluindo como realizar chamadas de funções para dentro do enclave.
    • Cada enclave deve ter um aplicativo host. O código de exemplo contém uma solução do Visual Studio com dois projetos – o host do enclave e o enclave de teste.

Advertência

Certifique-se de que reviu o suporte do sistema operativo para enclaves VBS acima, pois recentemente houve alterações.

Como Começar

Depois de satisfazer os pré-requisitos acima, você deve ser capaz de abrir o arquivo de solução do exemplo VbsEnclave no Visual Studio e compilá-lo. Ele cria um aplicativo de teste junto com o enclave correspondente. No entanto, você não pode executar seu aplicativo com êxito até que o enclave seja assinado com um certificado válido.

Este guia detalha como criar um enclave VBS básico em sua máquina de desenvolvimento. As etapas para construir um enclave VBS são:

  1. Escreva uma DLL de enclave VBS e uma aplicação host respetiva
  2. Compilar a DLL e o ambiente host
  3. Assine a DLL do VBS enclave
  4. Depurar o enclave VBS

Comecemos por compreender o ciclo de vida de um enclave. As APIs do enclave são chamadas na seguinte ordem:

Diagrama ilustrando a ordem em que as APIs do VBS Enclaves são chamadas

Etapa 1: Escrevendo enclaves VBS

Vamos examinar o código de exemplo e entender como escrever um aplicativo que emprega um enclave VBS.

Escrevendo o anfitrião do enclave

Lembre-se de que uma DLL de enclave VBS é simplesmente uma DLL, e portanto requer uma aplicação anfitriã. O aplicativo host nada mais é do que um aplicativo padrão do Windows. Para empregar enclaves VBS, o host deve usar APIs de enclave do Windows a partir do cabeçalho enclaveapi.h. Incluir windows.h em seu aplicativo host fornecerá acesso a essas APIs.

Gravando a DLL para carregar em um enclave de teste

Consulte o código de exemplo no projeto de enclave de teste para seguir as etapas abaixo.

No nosso enclave de exemplo, criamos um enclave simples que aplica um XOR à entrada com 0xDADAF00D e retorna o resultado. Vamos detalhar como fazemos isso:

  1. Comece por incluir winenclave.h. No código de exemplo, consulte Samples/VbsEnclave/Test enclave/precomp.h:

    #include <winenclave.h>
    

    winenclave.h é o arquivo de inclusão central para enclaves VBS e inclui windows.h, ntenclv.h, winenclaveapi.h.

  2. Cada DLL carregada em um enclave requer uma configuração. Essa configuração é definida usando uma variável global const chamada __enclave_config do tipo IMAGE_ENCLAVE_CONFIG. No código de exemplo, consulte Samples/VbsEnclave/Test enclave/enclave.c:

    const IMAGE_ENCLAVE_CONFIG __enclave_config = {
        sizeof(IMAGE_ENCLAVE_CONFIG),
        IMAGE_ENCLAVE_MINIMUM_CONFIG_SIZE,
        IMAGE_ENCLAVE_POLICY_DEBUGGABLE,    // DO NOT SHIP DEBUGGABLE ENCLAVES TO PRODUCTION
        0,
        0,
        0,
        { 0xFE, 0xFE },    // family id
        { 0x01, 0x01 },    // image id
        0,                 // version
        0,                 // SVN
        0x10000000,        // size
        16,                // number of threads
        IMAGE_ENCLAVE_FLAG_PRIMARY_IMAGE
    };
    

    Observação

    Só pode haver uma imagem primária por enclave. Se você carregar várias imagens primárias, a carregada primeiro será tratada como primária e as demais serão tratadas como dependências. Neste exemplo, não há dependências além das DLLs da plataforma de enclave.

  3. A DllMain() função é obrigatória e define o ponto de entrada no enclave. É chamado durante InitializeEnclave(). No código de exemplo, consulte Samples/VbsEnclave/Test enclave/enclave.c.

    BOOL
    DllMain(
        _In_ HINSTANCE hinstDLL,
        _In_ DWORD dwReason,
        _In_ LPVOID lpvReserved
    )
    {
        UNREFERENCED_PARAMETER(hinstDLL);
        UNREFERENCED_PARAMETER(lpvReserved);
    
        if (dwReason == DLL_PROCESS_ATTACH) {
            InitialCookie = 0xDADAF00D;
        }
    
        return TRUE;
    }
    
  4. Todas as funções dentro do enclave que são chamadas a partir do aplicativo host devem ser exportadas e ser do tipo LPENCLAVE_ROUTINE. A assinatura da função tem esta aparência:

    void* CALLBACK enclaveFunctionName(_In_ void* Context)
    

    No código de exemplo, consulte Samples/VbsEnclave/Test enclave/enclave.c.

    void*
    CALLBACK
    CallEnclaveTest(
        _In_ void* Context
    )
    {
        WCHAR String[32];
        swprintf_s(String, ARRAYSIZE(String), L"%s\n", L"CallEnclaveTest started");
        OutputDebugStringW(String);
    
        return (void*)((ULONG_PTR)(Context) ^ InitialCookie);
    }
    

    Observação

    Somente as funções exportadas pela imagem do enclave primário podem ser acessadas a partir do aplicativo host.

    Em seguida, você pode exportar a função usando um .DEF arquivo. No código de exemplo, consulte Samples/VbsEnclave/Test enclave/vbsenclave.def. Para obter mais informações, consulte Exportando de uma DLL usando arquivos DEF.

E é assim que se escreve uma DLL básica de enclave VBS.

Importante

Note que para ler/gravar memória normal (não-enclave), usar os acessores de memória do enclave (EnclaveCopyOutOfEnclave e EnclaveCopyIntoEnclave) são fortemente recomendados. Certifique-se de que todos os acessos de memória à memória normal são feitos através destes acessórios.

Etapa 2: Compilação de enclaves VBS

Agora que escrevemos nossa DLL de enclave VBS, vamos compilá-la.

Compilando o host do enclave

Compilar o aplicativo host é o mesmo que compilar qualquer aplicativo do Windows, mas com a adição de onecore.lib à lista de dependências durante a vinculação.

Compilando a DLL do enclave de teste

Antes de podermos criar a DLL do enclave de teste, algumas alterações nas configurações do compilador e do vinculador são necessárias:

  1. O vinculador MSVC fornece um /ENCLAVE sinalizador que capta os detalhes de configuração do enclave. O /ENCLAVE sinalizador é incompatível com a vinculação incremental, por isso precisamos definir /INCREMENTAL:NO.

  2. [Somente configuração de depuração]/EDITANDCONTINUE é incompatível com /INCREMENTAL:NO, por isso usamos /Zi em vez de /ZI para Debug Information Format no compilador.

  3. [Somente configuração de depuração] A configuração Basic Runtime Checks precisa ser definida como Default. Não há suporte para verificações de erros de tempo de execução em enclaves VBS.

  4. A assinatura digital de uma DLL de enclave deve ser verificada no momento em que é carregada e precisa configurar a /INTEGRITYCHECK flag no vinculador.

  5. As DLLs de enclave devem ser instrumentadas para o Control Flow Guard (CFG), para o qual usamos o /GUARD:MIXED sinalizador no vinculador.

  6. Os enclaves têm suas próprias versões de plataforma, inicialização, tempo de execução e bibliotecas UCRT. Para garantir que não ligamos as versões sem enclave, use o /NODEFAULTLIB sinalizador. Posteriormente, adicione as libs corretas em AdditionalDependencies. No código de exemplo, essas bibliotecas são encapsuladas sob a macro VBS_Enclave_Dependencies . A seguir estão as bibliotecas do enclave VBS:

    1. libcmt.lib e libvcruntime.lib - Encontrado na enclave pasta com as ferramentas de compilação do Visual C++, consulte C runtime (CRT) e C++ standard library (STL) .lib files.
    2. vertdll.lib e bcrypt.lib - Encontrado na um pasta com as bibliotecas do SDK do Windows.
    3. ucrt.lib - Encontrado na ucrt_enclave pasta com as bibliotecas do SDK do Windows.

Observação

Nenhuma outra biblioteca de plataforma é suportada em enclaves VBS.

Em resumo, são necessárias as seguintes alterações:

Compilador (somente configuração de depuração):

  • Formato de informação de depuração: /Zi
  • Verificações básicas de tempo de execução: Default

Vinculador:

  • /ENCLAVE
  • /NODEFAULTLIBS + AdditionalDependencies
  • /INCREMENTAL:NO
  • /INTEGRITYCHECK
  • /GUARD:MIXED

Agora você pode compilar a DLL do enclave.

Protegendo com VEIID

VEIID (o utilitário de vinculação do VBS Enclave Import ID) é uma ferramenta no Kit de Desenvolvimento de Software (SDK) do Windows que atualiza as tabelas de importação dentro de um enclave VBS com IDs conhecidas para DLLs da plataforma. Isso melhora a segurança dos enclaves VBS, impedindo que uma DLL maliciosa (assinada) com o mesmo nome de uma das DLLs da plataforma seja carregada.

No código de exemplo, isso é feito automaticamente como um evento pós-compilação.

Observação

É altamente recomendável evitar o uso de suas próprias DLLs não primárias além das DLLs da plataforma. Em vez disso, mantenha todo o seu código dentro da própria DLL do enclave.

Etapa 3: Assinatura das DLLs da enclave VBS

Os enclaves VBS devem ser assinados para serem carregados com sucesso. A assinatura em um enclave contém informações sobre o autor do enclave. Isso é usado para derivar a ID do autor para um enclave. Você pode testar e assinar seu enclave antes de assiná-lo para produção.

Assinatura de Teste – Local

Cada certificado de assinatura de enclave requer pelo menos 3 EKUs:

  1. Assinatura de código EKU - 1.3.6.1.5.5.7.3.3

  2. Enclave EKU - 1.3.6.1.4.1.311.76.57.1.15

  3. Autor EKU - O EKU é da forma 1.3.6.1.4.1.311.97.X.Y.Z..., onde X é maior que 999. O ... indica valores adicionais no formato EKU. Veja o exemplo abaixo para esclarecimentos.

    Para fins de testes, podes optar por usar qualquer EKU de autor que corresponda a esse padrão. Para a produção, um EKU de autor será fornecido como parte do certificado de produção (mais detalhes sobre a assinatura da produção estão abaixo).

    Exemplo: 1.3.6.1.4.1.311.97.814040577.346743379.4783502.105532346

Se você quiser assinar sua DLL de enclave ao desenvolvê-la, habilite a assinatura de teste. Com a assinatura de teste habilitada, você pode criar um certificado contendo esses três EKUs e assinar seu enclave com ele. Você pode usar o cmdlet New-SelfSignedCertificate para criar um certificado. Observe que as DLLs do Enclave devem ser assinadas com hash de página.

Observação

Depois de ter um certificado, você pode automatizar o processo de assinatura no evento pós-compilação.

New-SelfSignedCertificate -CertStoreLocation Cert:\\CurrentUser\\My -DnsName "MyTestEnclaveCert" -KeyUsage DigitalSignature -KeySpec Signature -KeyLength 2048 -KeyAlgorithm RSA -HashAlgorithm SHA256 -TextExtension "2.5.29.37={text}1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.76.57.1.15,1.3.6.1.4.1.311.97.814040577.346743379.4783502.105532346"
signtool sign /ph /fd SHA256 /n "MyTestEnclaveCert" vbsenclave.dll

Com sua DLL de enclave assinada, agora você pode carregá-la em um ambiente que tenha a assinatura de teste habilitada.

Assinatura de Produção – Assinatura Confiável (anteriormente conhecido como Assinatura de Código do Azure)

A assinatura de produção para enclaves é fornecida por meio do perfil de certificado de enclave VBS em Assinatura Confiável. Para obter detalhes sobre como usar a Assinatura Confiável, consulte a documentação.

A Assinatura Confiável também permite que você assine seu enclave na linha de comando. Isso gera um enclave assinado pronto para ser executado quando você cria seu enclave no Visual Studio.

Etapa 4: Depurando enclaves VBS

Normalmente, a memória de um enclave é ocultada dos depuradores e é protegida contra VTL0. No entanto, se desejar depurar as suas DLLs de enclave VBS, pode compilá-las com opções de depuração durante o desenvolvimento. Enclaves são um processo de modo de usuário VTL1 e, portanto, podem ser depurados com um depurador de modo de usuário.

Para tornar o seu enclave depurável:

  1. A configuração da imagem DLL do enclave precisa permitir a depuração – Isso é feito definindo o flag IMAGE_ENCLAVE_POLICY_DEBUGGABLE no IMAGE_ENCLAVE_CONFIG.
  2. A depuração precisa ser permitida durante a criação do enclave – Isso é feito configurando o sinalizador ENCLAVE_VBS_FLAG_DEBUG na estrutura ENCLAVE_CREATE_VBS_INFO passada na chamada CreateEnclave.

Para debugar o seu enclave:

  1. Anexe o depurador de modo de usuário ao processo de host do enclave.
  2. Recarregue os símbolos do enclave depois que o processo do host tiver carregado a imagem do enclave na memória.
  3. Defina pontos de interrupção nas funções dentro do enclave. O depurador interrompe numa chamada de enclave.

Você também pode quebrar os pontos de interrupção do modo de usuário para CreateEnclave, InitializeEnclave, etc., que entram no código correspondente em ntdll.dll.

Observação

Nunca use enclaves depuráveis em ambientes de produção.

Com isso, agora você pode criar e implantar seu primeiro enclave VBS. Se você tiver alguma dúvida, entre em contato com o suporte ao desenvolvedor do Windows.

Visão geral do VBS Enclaves

Assinatura Confiável do Azure

cabeçalho de enclaveapi.h

APIs disponíveis em enclaves VBS