共用方式為


虛擬化型安全性的開發指南 (VBS) 記憶體保護區

此開發指南說明如何建置、簽署和偵錯基本 VBS 記憶體保護區。

必要條件

若要開始使用 VBS 記憶體保護區,您需要符合下列需求:

  • VBS 記憶體保護區概觀中檢視並滿足裝置需求。
  • 在 VBS 記憶體保護區概觀檢視並滿足開發必要條件。
    • 建議您透過Visual Studio安裝程式,透過 C++ 工作負載安裝桌面開發。 它會安裝所有必要的工具,包括 Windows 軟體開發工具套件 (SDK)。
  • 從 GitHub 下載範例程式代碼。 它示範 VBS 記憶體保護區的生命週期,包括如何對記憶體保護區進行函式呼叫。
    • 每個記憶體保護區都必須有主機應用程式。 範例程式代碼包含具有兩個專案的Visual Studio解決方案: 記憶體保護區主機測試記憶體保護區

開始使用

滿足上述必要條件之後,您應該能夠從 Visual Studio 中的 VbsEnclave 範例開啟方案檔並加以編譯。 它會建立測試應用程式以及對應的記憶體保護區。 不過,在記憶體保護區使用有效憑證簽署之前,您無法成功執行應用程式。

本指南詳細說明如何在開發計算機上建置基本 VBS 記憶體保護區。 建置 VBS 記憶體保護區的步驟如下:

  1. 寫入 VBS 記憶體保護區 DLL 和對應的主機應用程式
  2. 編譯 DLL 和主機
  3. 簽署 VBS 記憶體保護區 DLL
  4. 對 VBS 記憶體保護區進行偵錯

讓我們從瞭解記憶體保護區的生命周期開始。 記憶體保護區 API 會依下列順序呼叫:

說明 VBS 記憶體保護區 API 呼叫順序的圖表

步驟 1:撰寫 VBS 記憶體保護區

讓我們檢查範例程式代碼,並瞭解如何撰寫採用 VBS 記憶體保護區的應用程式。

寫入記憶體保護區主機

請記住,VBS 記憶體保護區 DLL 只是 DLL,因此需要主應用程式。 主應用程式只不過是標準 Windows 應用程式。 若要採用 VBS 記憶體保護區,主機必須使用記憶體保護區api.h 標頭中的 Windows 記憶體保護區 API。 在您的主應用程式中包含 windows.h ,將會提供這些 API 的存取權。

寫入 DLL 以載入測試記憶體保護區

請參閱測試記憶體保護區專案中的範例程序代碼,以遵循下列步驟。

在我們的記憶體保護區範例中,我們會建立簡單的記憶體保護區,其中 XOR 會使用 0xDADAF00D 輸入並傳回結果。 讓我們來細分如何執行:

  1. 從包含 winenclave.h開始。 在範例程式代碼中,請參閱 Samples/VbsEnclave/Test enclave/precomp.h

    #include <winenclave.h>
    

    winenclave.h是 VBS 記憶體保護區的中央包含檔案,本身包含 windows.hntenclv.hwinenclaveapi.h

  2. 在記憶體保護區中載入的每個 DLL 都需要設定。 此組態是使用名為 __enclave_config IMAGE_ENCLAVE_CONFIG 類型的全域const變數來定義。 在範例程式代碼中,請參閱 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
    };
    

    注意

    每個記憶體保護區只能有一個主要映像。 如果您載入多個主要映像,則第一個載入的第一個映像會被視為主要映像,其餘則視為相依性。 在此範例中,記憶體保護區平臺 DLL 沒有相依性。

  3. DllMain() 式是必要函式,並定義記憶體保護區的進入點。 它會在期間 InitializeEnclave()呼叫。 在範例程式代碼中,請參閱 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. 從主應用程式呼叫的記憶體保護區內的任何函式都必須匯出且類型 為 LPENCLAVE_ROUTINE。 函式簽章看起來像這樣:

    void* CALLBACK enclaveFunctionName(_In_ void* Context)
    

    在範例程式代碼中,請參閱 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);
    }
    

    注意

    只有主要記憶體保護區映像導出的函式可以從主應用程式存取。

    然後,您可以使用 檔案匯出函 .DEF 式。 在範例程式代碼中,請參閱 Samples/VbsEnclave/Test enclave/vbsenclave.def。 如需詳細資訊,請參閱 使用DEF檔案從 DLL 匯出。

這就是您撰寫基本 VBS 記憶體保護區 DLL 的方式。

步驟 2:編譯 VBS 記憶體保護區

既然我們已撰寫 VBS 記憶體保護區 DLL,讓我們來編譯它。

編譯記憶體保護區主機

編譯主機應用程式與編譯任何 Windows 應用程式相同,但在連結時加入 onecore.lib 相依性清單。

編譯測試記憶體保護區 DLL

我們必須先對編譯程式和鏈接器設定進行一些變更,才能建置測試記憶體保護區 DLL:

  1. MSVC 連結器提供 /ENCLAVE 旗標,以挑選記憶體保護區組態詳細數據。 旗 /ENCLAVE 標與累加連結不相容,因此我們需要設定 /INCREMENTAL:NO

  2. [僅偵錯設定]/EDITANDCONTINUE/INCREMENTAL:NO不相容,因此我們會在編譯程式中針對偵錯資訊格式使用 /Zi ,而不是 /ZI

  3. [僅偵錯設定] 基本 運行時間檢查 組態必須設定為 [預設]。 VBS 記憶體保護區不支援運行時間錯誤檢查。

  4. 記憶體保護區 DLL 的數位簽名必須在載入時檢查,而且需要在連結器中設定 /INTEGRITYCHECK 旗標。

  5. 記憶體保護區 DLL 必須針對 控制流程防護 (CFG)進行檢測,我們在此連結器中使用 /GUARD:MIXED 旗標。

  6. 記憶體保護區有自己的平臺、啟動、運行時間和 UCRT lib 版本。 為了確保我們不會連結非記憶體保護區版本,請使用 /NODEFAULTLIB 旗標。 接著,在底下 AdditionalDependencies新增正確的連結庫。 在範例程式代碼中,這些連結庫會封裝在 VBS_Enclave_Dependencies 宏底下。 以下是 VBS 記憶體保護區連結庫:

    1. libcmt.liblibvcruntime.lib - 使用 Visual C++ 建置工具在 enclave 資料夾中找到,請參閱 C 運行時間 (CRT) 和 C++ 標準連結庫 (STL) .lib 檔案
    2. vertdll.libbcrypt.lib - 在具有 Windows SDK 連結庫的資料夾中找到 um
    3. ucrt.lib - 在 ucrt_enclave 具有 Windows SDK 連結庫的資料夾中找到。

注意

VBS 記憶體保護區內不支援其他平台連結庫。

總而言之,需要下列變更:

編譯程式 (僅限偵錯組態):

  • 偵錯資訊格式: /Zi
  • 基本執行時間檢查: Default

連線:

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

您現在可以編譯記憶體保護區 DLL。

使用 VEIID 保護

VEIID (VBS 記憶體保護區匯入標識符系結公用程式)是 Windows SDK 中的工具,可更新 VBS 記憶體保護區內具有平臺 DLL 已知標識符的匯入數據表。 這可藉由防止與其中一個平臺 DLL 相同的惡意 (已簽署) DLL 載入,來改善 VBS 記憶體保護區的安全性。

在範例程式代碼中,這會自動做為建置後事件。

注意

強烈建議您避免除了平臺 DLL 之外,使用您自己的非主要 DLL。 相反地,請將所有程式代碼保留在記憶體保護區 DLL 本身內。

步驟 3:簽署 VBS 記憶體保護區 DLL

必須簽署 VBS記憶體保護區才能成功載入。 記憶體保護區上的簽章包含記憶體保護區作者的相關信息。 這是用來衍生記憶體保護區的作者標識符。 您可以先測試簽署記憶體保護區,再將記憶體保護區簽署以供生產環境使用。

測試簽署 – 本機

每個記憶體保護區簽署憑證至少需要 3 個 EKU:

  1. 程式代碼簽署 EKU - 1.3.6.1.5.5.7.3.3

  2. 記憶體保護區 EKU - 1.3.6.1.4.1.311.76.57.1.15

  3. 作者 EKU - EKU 的格式 1.3.6.1.4.1.311.97.X.Y.Z為 ,其中 X 大於 999

    若要進行測試,您可以選擇使用任何符合此模式的 Author EKU。 針對生產環境,將會在生產憑證中提供作者 EKU(以下提供生產簽署的詳細數據)。

    範例: 1.3.6.1.4.1.311.97.814040577.346743379.4783502.105532346

如果您想要在開發記憶體保護區 DLL 時簽署, 請啟用測試簽署。 啟用測試簽署后,您可以建立包含這三個 EKU 的憑證,並使用其簽署記憶體保護區。 您可以使用 New-SelfSignedCertificate Cmdlet 來建立憑證。 請注意,記憶體保護區 DLL 必須是頁面哈希簽署。

注意

擁有憑證之後,您就可以在建置後事件中自動執行簽署程式。

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

在簽署記憶體保護區 DLL 之後,您現在可以在已啟用測試簽署的環境中載入它。

生產簽署 – 信任簽署 (先前稱為 Azure 程式代碼簽署)

記憶體保護區的生產簽署是透過信任簽署中的 VBS 記憶體保護區憑證配置檔來提供。 如需如何使用 信任簽署的詳細資訊,請參閱

信任的簽署也可讓您在命令行簽署記憶體保護區。 當您在Visual Studio中建置記憶體保護區時,這會輸出可立即執行的已簽署記憶體保護區。

步驟 4:偵錯 VBS 記憶體保護區

一般而言,記憶體保護區的記憶體會從調試程序隱藏,並受到 VTL0 的保護。 不過,如果您想要對 VBS 記憶體保護區 DLL 進行偵錯,您可以在開發期間加以建置以偵錯。 記憶體保護區是 VTL1 使用者模式進程,因此可以使用使用者模式調試程式進行偵錯。

若要讓您的記憶體保護區可偵錯:

  1. 記憶體保護區 DLL 映射組態必須允許偵錯 – 這是藉由在 IMAGE_ENCLAVE_CONFIG設定IMAGE_ENCLAVE_POLICY_DEBUGGABLE旗標來完成。
  2. 在記憶體保護區建立期間必須允許偵錯 – 這是藉由在傳遞至 CreateEnclave 呼叫的ENCLAVE_CREATE_VBS_INFO結構中設定ENCLAVE_VBS_FLAG_DEBUG旗標來完成。

若要對記憶體保護區進行偵錯:

  1. 將使用者模式調試程式附加至記憶體保護區主機進程。
  2. 在主機進程在記憶體中載入記憶體保護區映像之後,重載記憶體保護區符號。
  3. 在記憶體保護區內的函式上設定斷點。 調試程式會在記憶體保護區呼叫上中斷。

您也可以在 CreateEnclave、InitializeEnclave 等的使用者模式斷點上中斷,進一步逐步執行 中的ntdll.dll對應程式代碼。

注意

請勿在生產環境中使用可偵錯的記憶體保護區。

如此一來,您現在可以建置並部署您的第一個 VBS 記憶體保護區。 如果您有任何問題,請連絡 Windows 開發人員支援

VBS 記憶體保護區概觀

Azure 信任簽署

enclaveapi.h 標頭

VBS 記憶體保護區中可用的 API