Entwicklungsleitfaden für VBS-Enklaven (virtualisierungsbasierte Sicherheit)

In diesem Entwicklungsleitfaden wird beschrieben, wie Sie eine einfache VBS-Enklave erstellen, unterschreiben und debugen.

Voraussetzungen

Um mit VBS-Enklaven zu beginnen, müssen Sie die folgenden Anforderungen erfüllen:

  • Anzeigen und Erfüllen der Geräteanforderungen in der VBS-Enklavenübersicht.
  • Anzeigen und Erfüllen von Entwicklungsvoraussetzungen in der Übersicht über VBS-Enklaven.
    • Es wird empfohlen, die Desktopentwicklung mit C++-Workload über das Visual Studio-Installationsprogramm zu installieren. Es installiert alle erforderlichen Tools, einschließlich des Windows Software Development Kit (SDK).
  • Laden Sie den Beispielcode von GitHub herunter. Es veranschaulicht den Lebenszyklus einer VBS-Enklave, einschließlich der Art, wie Funktionsaufrufe in die Enklave ausgeführt werden.
    • Jede Enklave muss über eine Host-App verfügen. Der Beispielcode enthält eine Visual Studio-Projektmappe mit zwei Projekten – dem Enklaven-Host und der Test-Enklave.

Erste Schritte

Nachdem Sie die oben genannten Voraussetzungen erfüllt haben, sollten Sie die Lösungsdatei aus dem VbsEnklave-Beispiel in Visual Studio öffnen und kompilieren können. Es erstellt eine Testanwendung zusammen mit der entsprechenden Enklave. Sie können die Anwendung jedoch erst erfolgreich ausführen, wenn die Enklave mit einem gültigen Zertifikat signiert ist.

In dieser Anleitung wird beschrieben, wie Sie eine einfache VBS-Enklave auf Ihrem Entwicklungscomputer erstellen. Die Schritte zum Erstellen einer VBS-Enklave sind:

  1. Schreiben einer VBS-Enklaven-DLL und einer entsprechenden Hostanwendung
  2. Kompilieren der DLL und des Hosts
  3. Signieren der VBS-Enklaven-DLL
  4. Debuggen der VBS-Enklave

Beginnen wir damit, den Lebenszyklus einer Enklave zu verstehen. Die Enklaven-APIs werden in der folgenden Reihenfolge aufgerufen:

Diagramm zur Veranschaulichung der Reihenfolge, in der VBS-Enklaven-APIs aufgerufen werden

Schritt 1: Schreiben von VBS-Enklaven

Sehen wir uns den Beispielcode an, um zu verstehen, wie eine Anwendung geschrieben wird, die eine VBS-Enklave verwendet.

Schreiben des Enklaven-Hosts

Denken Sie daran, dass eine VBS-Enklaven-DLL einfach eine DLL ist und daher eine Hostanwendung erfordert. Die Hostanwendung ist nichts anderes als eine Windows-Standardanwendung. Um VBS-Enklaven zu verwenden, muss der Host Windows-Enklaven-APIs aus dem enclaveapi.h-Header verwenden. Das Einschließen windows.h in Ihre Hostanwendung bietet Zugriff auf diese APIs.

Schreiben der DLL zum Laden in eine Testenklave

Im Test-Enklaven-Projekt finden Sie Beispielcode, der zusammen mit den nachstehenden Schritten ausgeführt werden soll.

In unserem Enklaven-Beispiel erstellen wir eine einfache Enklave, mit der XORs die Eingabe mit 0xDADAF00D verwendet und das Ergebnis zurückgibt. Gehen wir wie folgt vor:

  1. Beginnen Sie mit dem Einschließen von winenclave.h. Beziehen Sie sich im Beispielcode auf Samples/VbsEnclave/Test enclave/precomp.h:

    #include <winenclave.h>
    

    winenclave.h ist die zentrale einschließende Datei für VBS-Enklaven und enthält selbst windows.h, ntenclv.h und winenclaveapi.h.

  2. Jede in einer Enklave geladene DLL erfordert eine Konfiguration. Diese Konfiguration wird mithilfe einer globalen const-Variablen mit dem Namen IMAGE_ENCLAVE_CONFIG der Art __enclave_config definiert. Beziehen Sie sich im Beispielcode auf 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
    };
    

    Hinweis

    Pro Enklave kann nur ein primäres Bild vorhanden sein. Wenn Sie mehrere primäre Bilder laden, wird das geladene zuerst als primär behandelt, und der Rest wird als Abhängigkeiten behandelt. In diesem Beispiel gibt es keine Abhängigkeiten außer den Enklaven-Plattform-DLLs.

  3. Die DllMain()-Funktion ist obligatorisch und definiert den Einstiegspunkt in die Enklave. Sie wird während InitializeEnclave() aufgerufen. Beziehen Sie sich im Beispielcode auf 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. Alle Funktionen innerhalb der Enklave, die von der Hostanwendung aufgerufen werden, müssen exportiert und vom Typ LPENCLAVE_ROUTINE sein. Die Signatur der Funktion sieht folgendermaßen aus:

    void* CALLBACK enclaveFunctionName(_In_ void* Context)
    

    Beziehen Sie sich im Beispielcode auf 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);
    }
    

    Hinweis

    Nur auf die vom primären Enklaven-Bild exportierten Funktionen kann über die Hostanwendung zugegriffen werden.

    Anschließend können Sie die Funktion mithilfe einer .DEF-Datei exportieren. Beziehen Sie sich im Beispielcode auf Samples/VbsEnclave/Test enclave/vbsenclave.def. Weitere Informationen finden Sie unter Exportieren aus einer DLL mithilfe von DEF-Dateien.

So wird eine einfache VBS-Enclave-DLL geschrieben.

Schritt 2: Kompilieren von VBS-Enklaven

Nachdem wir unsere VBS-Enclave-DLL geschrieben haben, kompilieren wir sie.

Kompilieren des Enklaven-Hosts

Das Kompilieren der Host-App ist identisch mit der Kompilierung einer beliebigen Windows-Anwendung, aber mit dem Hinzufügen von onecore.lib zur Liste der Abhängigkeiten beim Verknüpfen.

Kompilieren der Test-Enclave-DLL

Bevor wir die Test-Enclave-DLL erstellen können, sind einige Änderungen an den Compiler- und Linker-Konfigurationen erforderlich:

  1. Der MSVC-Linker stellt ein /ENCLAVE-Flag bereit, mit dem die Enklaven-Konfigurationsdetails aufgenommen werden. Das /ENCLAVE-Flag ist nicht mit inkrementellen Verknüpfungen kompatibel, daher müssen wir /INCREMENTAL:NO festlegen.

  2. [Debug config only] /EDITANDCONTINUE ist nicht mit /INCREMENTAL:NO kompatibel. Daher verwenden wir /Zi anstelle von /ZI für Debug Information Format im Compiler.

  3. [Nur Debug-Konfiguration] Die Konfiguration für grundlegende Runtime-Überprüfungen muss auf Standard festgelegt werden. Runtime-Fehlerüberprüfung werden in VBS-Enklaven nicht unterstützt.

  4. Die digitale Signatur einer Enclave-DLL muss zur Ladezeit überprüft werden und erfordert das Festlegen des /INTEGRITYCHECK-Flags im Linker.

  5. Enklaven-DLLs müssen für Ablaufsteuerungsschutz (CFG) instrumentiert werden, für die wir das /GUARD:MIXED-Flag im Linker verwenden.

  6. Enklaven verfügen über eigene Versionen von Plattform-, Startup-, Runtime- und UCRT-Bibliotheken. Um sicherzustellen, dass die Nicht-Enklaven-Versionen nicht verknüpft werden, verwenden Sie das /NODEFAULTLIB-Flag. Fügen Sie anschließend die richtigen Bibliotheken unter AdditionalDependencieshinzu. Im Beispielcode werden diese Bibliotheken unter dem VBS_Enclave_Dependencies-Makro gekapselt. Im Folgenden sind die VBS-Enklaven-Bibliotheken aufgeführt:

    1. libcmt.lib und libvcruntime.lib: Zu finden im Ordner enclave mit den Visual C++ Build-Tools, siehe C-Laufzeit (CRT) und C++ Standardbibliothek (STL) .lib-Dateien.
    2. vertdll.lib und bcrypt.lib: Zu finden im Ordner um mit den Windows SDK-Bibliotheken.
    3. ucrt.lib: Zu finden im Ordner ucrt_enclave mit den Windows SDK-Bibliotheken.

Hinweis

In VBS-Enklaven werden keine anderen Plattformbibliotheken unterstützt.

Zusammenfassend sind die folgenden Änderungen erforderlich:

Compiler (nur Debug-Konfiguration):

  • Debuginformationsformat /Zi
  • Grundlegende Laufzeitüberprüfungen Default

Linker:

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

Sie können jetzt die Enklaven-DLL kompilieren.

Sichern mit VEIID

VEIID (das VBS-Enklaven Import-ID Bindunggsdienstprogramm) ist ein Tool im Windows SDK, das die Importtabellen in einer VBS-Enklave mit bekannten IDs für Plattform-DLLs aktualisiert. Dadurch wird die Sicherheit von VBS-Enklaven verbessert, indem verhindert wird, dass eine bösartige (signierte) DLL mit demselben Namen wie eine der Plattform-DLLs geladen wird.

Im Beispielcode erfolgt dies automatisch als Post-Buildereignis.

Hinweis

Es wird nachdrücklich empfohlen, die Verwendung eigener nicht primärer DLLs über die Plattform-DLLs hinaus zu vermeiden. Behalten Sie stattdessen den gesamten Code innerhalb der Enklaven-DLL selbst bei.

Schritt 3: Signieren von VBS-Enclave-DLLs

VBS-Enklaven müssen signiert werden, um erfolgreich geladen zu werden. Die Signatur auf einer Enklave enthält Informationen über den Enklaven-Autor. Dies wird verwendet, um die Autor-ID für eine Enklave abzuleiten. Sie können Ihre Enklave testen, bevor Sie sie für die Produktion signieren.

Testsignatur – Lokal

Jedes Enklaven-Signaturzertifikat erfordert mindestens 3 EKUs:

  1. Codesignatur-EKU - 1.3.6.1.5.5.7.3.3

  2. Enklaven-EKU - 1.3.6.1.4.1.311.76.57.1.15

  3. Autor-EKU - Die EKU ist von der Art 1.3.6.1.4.1.311.97.X.Y.Z, wobei X größer als 999 ist.

    Für Tests können Sie eine beliebige Autor-EKU verwenden, die diesem Muster entspricht. Für die Produktion wird eine Autoren-EKU als Teil des Produktionszertifikats bereitgestellt (weitere Details zur Produktionssignierung finden Sie unten).

    Beispiel: 1.3.6.1.4.1.311.97.814040577.346743379.4783502.105532346

Wenn Sie ihre Enklaven-DLL während der Entwicklung signieren möchten, aktivieren Sie die Testsignierung. Mit aktivierter Testsignatur können Sie ein Zertifikat erstellen, das diese drei EKUs enthält, und Ihre Enklave damit signieren. Verwenden Sie das Cmdlet New-SelfSignedCertificate, um ein Zertifikat zu erstellen. Beachten Sie, dass Enklaven-DLLs als Seiten-Hash signiert sein müssen.

Hinweis

Sobald Sie über ein Zertifikat verfügen, können Sie den Anmeldevorgang im Post-Buildereignis automatisieren.

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

Mit der signierten Enklave-DLL können Sie sie jetzt in einer Umgebung laden, in der die Testsignatur aktiviert ist.

Produktionssignierung – Trusted Signing (früher Azure Code Signing)

Die Produktionssignatur für Enklaven wird über das VBS-Enklavenzertifikatprofil in Trusted Signing bereitgestellt. Ausführliche Informationen zur Verwendung von Trusted Signing finden Sie in der Dokumentation.

Mit Trusted Signing können Sie auch Ihre Enklave an der Befehlszeile signieren. Dadurch wird eine fertige, signierte Enklave ausgegeben, wenn Sie Ihre Enklave in Visual Studio erstellen.

Schritt 4: Debuggen von VBS-Enklaven

Normalerweise wird der Speicher einer Enklaven vor Debuggern ausgeblendet und vor VTL0 geschützt. Wenn Sie jedoch Ihre VBS-Enclave-DLL debuggen möchten, können Sie sie erstellen, um sie während der Entwicklung zu debuggen. Enklaven sind ein VTL1-Benutzermodusprozess und können daher mit einem Benutzermodus-Debugger gedebuggt werden.

So können Sie Ihre Enklave debuggierbar machen:

  1. Die Enclave-DLL-Image-Konfiguration muss das Debugging zulassen – Setzen Sie dazu das IMAGE_ENCLAVE_POLICY_DEBUGGABLE-Flag in IMAGE_ENCLAVE_CONFIG.
  2. Das Debuggen muss während der Erstellung von Enklaven zulässig sein – Dies erfolgt durch Festlegen des Flags ENCLAVE_VBS_FLAG_DEBUG in der Struktur ENCLAVE_CREATE_VBS_INFO, die an den CreateEnclave-Aufruf übergeben wird.

So debuggen Sie Ihre Enklave:

  1. Fügen Sie den Benutzermodus-Debugger an den Enklaven-Hostprozess an.
  2. Laden Sie die Enklaven-Symbole neu, nachdem der Hostprozess das Enklaven-Bild im Speicher geladen hat.
  3. Legen Sie Haltepunkte für die Funktionen innerhalb der Enklave fest. Der Debugger wird in einen Enklaven-Aufruf eingegliedert.

Sie können auch die Haltepunkte für den Benutzermodus für CreateEnclave, InitializeEnklave usw. unterbrechen, die weiter in den entsprechenden Code in ntdll.dll gelangen.

Hinweis

Verwenden Sie nie debuggierbare Enklaven in Produktionsumgebungen.

Damit können Sie jetzt Ihre erste VBS-Enklave erstellen und bereitstellen. Bei Fragen wenden Sie sich bitte an Windows Developer Support.

Übersicht über VBS-Enclaves

Azure Trusted Signing

enclaveapi.h-Header

In VBS-Enklaven verfügbare APIs