共用方式為


保護反惡意代碼服務

Windows 8.1 引進了受保護的服務的新概念,以保護反惡意代碼服務,這是惡意代碼攻擊的常見目標。

瞭解如何保護反惡意代碼 (AM) 使用者模式服務,以及如何選擇在反惡意代碼服務中包含這項功能。

此資訊適用於下列作業系統及其後續專案:

  • Windows 8.1
  • Windows Server 2012 R2

本主題結尾會列出此處討論的參考和資源。

簡介

大部分的反惡意代碼解決方案都包含使用者模式服務,可執行特製化作業,以偵測和移除系統中的惡意代碼。 此使用者模式服務也經常負責下載最新的病毒定義和簽章。 此使用者模式服務會成為惡意代碼的常見目標,因為它是停用系統上保護的單一失敗點。 若要抵禦使用者模式服務的攻擊,反惡意代碼廠商必須為其軟體新增許多功能和啟發學習法。 不過,這類技術並非完全萬無一失,而且容易出錯,因為它們必須識別 Windows 在其服務上執行的功能,並選擇性地啟用該功能。

在 Windows 8.1 中,已引進受保護的服務新概念,以允許以受保護的服務的形式啟動反惡意代碼使用者模式服務。 服務啟動為受保護之後,Windows 會使用程式代碼完整性,只允許信任的程式代碼載入受保護的服務。 Windows 也會保護這些程式免於程式代碼插入和其他來自系統管理程序的攻擊。

本文件說明具有早期啟動反惡意代碼 (ELAM) 驅動程式的反惡意代碼廠商如何選擇加入這項功能,並啟動其反惡意代碼服務作為受保護的服務。

系統保護的進程

從 Windows 8.1 開始,核心已備妥新的安全性模型,以更好地防範系統關鍵元件的惡意攻擊。 這個新的安全性模型會將用於特定案例的受保護進程基礎結構舊版 Windows 延伸為一般用途模型,以供第三方反惡意代碼廠商使用。 受保護的進程基礎結構只允許信任、簽署的程式代碼載入,並內建防禦程式代碼插入式攻擊。

注意

下列腳本 DLL 在受保護的進程內禁止使用下列腳本 DLL,例如透過 WinVerifyTrust 或 WinVerifyTrustEx,透過 AuthentiCode 檢查腳本簽章:scrobj.dll、、scrrun.dlljscript.dlljscript9.dllvbscript.dll

如需受保護進程的詳細資訊,請參閱 Windows Vista 中的受保護進程。

新的安全性模型會使用稍微不同的保護程式基礎結構變體,稱為系統保護進程,此功能更適合此功能,因為這樣會將DRM內容分開。 每個系統保護的進程都有相關聯的層級或屬性,指出允許在進程內載入之已簽署程式代碼的簽章原則。 反惡意代碼服務選擇進入受保護的服務模式之後,只有使用反惡意代碼廠商憑證簽署的 Windows 簽署程式碼或程式碼才能載入該程式。 同樣地,其他受保護的進程層級也有 Windows 強制執行的不同程式碼原則。

需求

若要讓反惡意代碼使用者模式服務以受保護的服務身分執行,反惡意代碼廠商必須在 Windows 電腦上安裝 ELAM 驅動程式。 除了現有的 ELAM 驅動程式認證需求之外,驅動程式還必須有內嵌的資源區段,其中包含用來簽署使用者模式服務二進位檔的憑證資訊。

重要

在 Windows 8.1 中,認證鏈結必須是驅動程式驗證所決定的已知跟證書,或必須包含跟證書。

在開機程式期間,系統會從 ELAM 驅動程式擷取此資源區段,以驗證憑證資訊並註冊反惡意代碼服務。 反惡意代碼服務也可以在反惡意代碼軟體安裝程式期間註冊,方法是呼叫特殊的 API,如本檔稍後所述。

成功從 ELAM 驅動程式擷取資源區段並註冊使用者模式服務之後,即允許服務啟動為受保護的服務。 服務啟動為受保護之後,系統上的其他非受保護進程將無法插入線程,而且不允許它們寫入受保護進程的虛擬記憶體。

此外,載入受保護進程的任何非 Windows DLL 都必須使用適當的憑證簽署。

如需 ELAM 驅動程式的詳細資訊,請參閱 早期啟動反惡意程式碼 軟體。

反惡意代碼服務簽署需求

必須以受保護的身分啟動的使用者模式服務,才能使用有效的憑證簽署。 服務 EXE 必須是分頁哈希簽署,而且載入服務的任何非 Windows DLL 也必須使用相同的憑證簽署。 這些憑證的哈希必須新增至資源檔,這會連結至 ELAM 驅動程式。

注意

您必須使用 SHA256 檔案/頁面哈希,不過憑證可能繼續是 SHA1。

我們建議反惡意代碼廠商使用其現有的 Authenticode 憑證來簽署其反惡意代碼服務二進位檔,而且此 Authenticode 憑證的哈希會包含在資源區段中,以指出用來簽署服務二進位檔的憑證。 如果您更新此憑證,則必須使用更新的憑證哈希來發行較新版本的 ELAM 驅動程式。

次要簽章 (選擇性)

反惡意代碼廠商可以選擇設定私人 CA,並使用來自此 CA 的憑證,將反惡意代碼服務二進位檔簽署為次要簽章。 使用私人 CA 的主要優點是,它可讓廠商建立具有特殊 EKU 屬性的憑證,這可用來區分多個產品與同一廠商。 它也會減少因憑證到期而更新 ELAM 驅動程式的需求,因為私人 CA 憑證通常會有較長的到期日。

請注意,如果服務二進位檔是使用私人 CA 憑證簽署,則二進位檔也必須使用現有的 Authenticode 憑證進行雙重簽署。 如果二進位檔不是由已知的受信任 CA 簽署(例如 VeriSign),則計算機的使用者對二進位檔沒有信心,因為它們無法信任私人 CA。 使用現有 Authenticode 憑證雙重簽署二進位檔也允許二進位檔在下層操作系統上執行。

如需如何設定及安裝證書頒發機構單位的詳細資訊,請參閱 設定證書頒發機構單位安裝證書頒發機構單位

注意

為了與 Windows Vista 或 Windows XP 相容(或不含 SHA2 修補程式的 Windows 7),您可以使用 “/as” 參數,使用 SHA256 檔案/頁面哈希簽署 二進位檔時使用 SignTool.exe 。 這會將簽章新增為檔案的次要簽章。 SHA1 會先簽署檔案,因為 Windows XP、Windows Vista 和 Windows 7 只會看到第一個簽章。

DLL 簽署需求

如先前所述,載入受保護服務的任何非 Windows DLL 都必須使用用來簽署反惡意代碼服務的相同憑證簽署。

目錄簽署

反惡意代碼廠商可以包含由其他公司開發的套件,而不需更新二進位簽章。 這可以藉由將二進位檔包含在使用其 Authenticode 憑證簽署的目錄中,方法是遵循下列步驟來完成:

  1. 使用 MakeCat產生目錄
  2. 將不含適當簽章的所有二進位檔新增至目錄
  3. 使用 Authenticode 憑證簽署目錄,就像任何其他二進位檔一樣
  4. 使用 add catalog 函式,將目錄與應用程式一起包含。

當程式代碼完整性遇到沒有適當簽章的套件時,它會搜尋具有已核准簽章的目錄。 只要遵循這些步驟並隨應用程式一起安裝,就會找到此目錄。

資源文件資訊

資源文件必須建立並連結至 ELAM 驅動程式。 憑證的哈希以及其他憑證信息必須新增在資源檔中。

資源區段必須位於下列配置中,系統才能成功從二進位映射擷取資源,並驗證內嵌憑證資訊。

MicrosoftElamCertificateInfo  MSElamCertInfoID
{
      3, // count of entries
      L”CertHash1\0”,
      Algorithm,
      L”EKU1\0”,
      L”CertHash2\0”,
      Algorithm,
      L”\0”, //No EKU for cert hash 2
      L”CertHash3\0”,
      Algorithm,
      L”EKU3a;EKU3b;EKU3c\0”,  //multiple EKU entries supported (max: 3)
}

如需使用者定義資源文件的詳細資訊,請參閱 使用者定義的資源

CertHash

用來簽署反惡意代碼服務的憑證哈希。 隨附於 Windows SDK 的 CertUtil.exe 工具可用來取得哈希。

certutil.exe –v <path to the signed file>

例如:

anti-malware protected service certificate hash (certhash)

演算法

演算法值代表憑證的演算法。 支援這些演算法值:

0x8004 – SHA1 0x800c – SHA256 0X800d – SHA384 0x800e – SHA512

請記得包含演算法的值(如上所示),而不是演算法的實際名稱。 例如,如果憑證是以SHA256演算法為基礎,請在資源區段中包含0x800c。

EKU

EKU 物件代表憑證的單一擴充金鑰使用方式 (EKU) 屬性。 如果沒有任何 EKU 與憑證相關聯,則這是選擇性的,而且應該指定 “\0”。在相同系統上執行的單一反惡意代碼廠商有多個產品和服務的情況下,反惡意代碼廠商可以使用私人 CA 憑證的 EKU 屬性來區分一項服務與另一個服務。 例如,如果系統上有兩個服務來自同一個反惡意代碼廠商且由同一個 CA 簽署,則必須以受保護的身分啟動服務,可以使用包含特殊 EKU 的 CA 所發出的憑證簽署。 此 EKU 必須新增至資源區段。 然後,系統會註冊 EKU,並與憑證哈希配對,以驗證並啟動受保護的服務。

請注意,憑證鏈結必須包含程式代碼簽署 EKU (1.3.6.1.5.5.7.3.3),但此 EKU 不得包含在 ELAM 驅動程式的資源區段中。

注意

如果 EKU 資訊包含在 ELAM 驅動程式的憑證資訊中,則簽署二進位檔時必須使用相同的 EKU。

注意

EKU 中 OID 的 Windows 程式代碼完整性字串表示,長度上限為 64 個字元,包括零終止字元。  

注意

如果您指定多個 EKU,則會使用 AND 邏輯來評估它們。 結束實體憑證必須滿足指定專案之 ELAM 資源區段中指定的所有 EKU。

計數

如果反惡意代碼服務二進位檔是以 Authenticode 憑證和私人 CA 憑證簽署,則只有私人 CA 憑證資訊必須在資源區段中新增。

將反惡意代碼服務啟動為受保護

註冊服務

反惡意代碼服務必須先向系統註冊,才能以受保護的方式啟動。 在安裝反惡意代碼軟體期間,安裝程式可以安裝 ELAM 驅動程式,並重新啟動系統以自動註冊服務。 系統會在開機時註冊服務,方法是從連結至 ELAM 驅動程式的上述資源檔擷取憑證資訊。

在安裝階段期間,強烈建議重新啟動系統,讓 ELAM 驅動程式載入並驗證系統的狀態。 不過,針對必須避免重新啟動的情況,Windows 也會公開反惡意代碼安裝程序的機制,以使用 API 將服務註冊為受保護的服務。

註冊服務而不重新啟動系統

在安裝期間,反惡意代碼軟體安裝程式可以呼叫 InstallELAMCertificateInfo API,並提供 ELAM 驅動程式檔案的句柄。 系統會開啟 ELAM 驅動程式、呼叫內部例程,以確定 ELAM 驅動程式已正確簽署,並從與 ELAM 驅動程式相關聯的資源區段擷取憑證資訊。 如需函式語法,請參閱 InstallELAMCertificateInfo

程式碼範例:

HANDLE FileHandle = NULL;

FileHandle = CreateFile(<Insert Elam driver file name>,
                        FILE_READ_DATA,
                        FILE_SHARE_READ,
                        NULL,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL
                        );

if (InstallElamCertificateInfo(FileHandle) == FALSE)
{
    Result = GetLastError();
    goto exitFunc;
}

將服務啟動為受保護

安裝程式可以遵循下列步驟來建立、設定及啟動受保護的服務:

  1. 呼叫 CreateService API 來建立服務物件,並將它新增至服務控制管理員 (SCM) 資料庫。

  2. 呼叫 SetServiceObjectSecurity API,以設定在步驟 1 中建立之服務對象的安全性描述元。

  3. 呼叫 ChangeServiceConfig2 API 將服務標示為受保護,並指定 Winsvc.h 中新增的新SERVICE_CONFIG_LAUNCH_PROTECTED列舉值(從 Windows 8.1 開始)。

    程式碼範例:

    SERVICE_LAUNCH_PROTECTED_INFO Info;
    SC_HANDLE hService;
    
    Info.dwLaunchProtected = SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT;
    
    hService = CreateService (/* ... */);
    
    if (ChangeServiceConfig2(hService,
                             SERVICE_CONFIG_LAUNCH_PROTECTED,
                             &Info) == FALSE)
    {
        Result = GetLastError();
    }
    
  4. 呼叫 StartService API 以啟動服務。 當啟動受保護的服務時,SCM 會檢查程式代碼完整性 (CI) 子系統,以驗證憑證資訊。 CI 驗證憑證信息之後,SCM 會將服務啟動為受保護。

    1. 請注意,如果您尚未呼叫 InstallELAMCertificateInfo API 來註冊服務,此步驟將會失敗。
    2. 如果服務已設定為在系統啟動階段自動啟動,您可以避免此步驟,並直接重新啟動系統。 重新啟動期間,系統會自動註冊服務(如果 ELAM 驅動程式成功啟動),並以受保護的模式啟動服務。
    3. 如果服務無法啟動,請參閱程式代碼完整性事件記錄和系統稽核中的資訊,以及下列主題。 在那裡,您會發現更詳細的錯誤訊息,說明程式代碼完整性系統為何無法啟動服務。 這些記錄也可以協助您識別服務嘗試載入但無法載入的 DLL。

啟動受保護的子進程

新的安全性模型也允許反惡意代碼保護的服務啟動受保護的子進程。 這些子進程將會在與父服務相同的保護層級執行,而且其二進位檔必須使用透過 ELAM 資源區段註冊的相同憑證進行簽署。

為了允許反惡意代碼保護的服務啟動受保護的子進程,新的擴充屬性密鑰PROC_THREAD_ATTRIBUTE_PROTECTION_LEVEL已公開,且必須與 UpdateProcThreadAttribute API 搭配使用。 PROTECTION_LEVEL_SAME屬性值的指標必須傳遞至 UpdateProcThreadAttribute API。

注意:

  • 若要使用這個新屬性,服務也必須在 CreateProcess 呼叫的進程建立旗標參數中指定CREATE_PROTECTED_PROCESS
  • 您必須使用 /ac 參數簽署您的服務二進位檔,以包含交叉憑證,將其鏈結至已知的 CA。 自我簽署的憑證若未正確鏈結至已知的根 CA 將無法運作。

程式碼範例:

DWORD ProtectionLevel = PROTECTION_LEVEL_SAME;
SIZE_T AttributeListSize;

STARTUPINFOEXW StartupInfoEx = { 0 };

StartupInfoEx.StartupInfo.cb = sizeof(StartupInfoEx);

if (InitializeProcThreadAttributeList(NULL,
                                      1,
                                      0,
                                      &AttributeListSize) == FALSE)
{
    Result = GetLastError();
    goto exitFunc;
}

StartupInfoEx.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST) HeapAlloc(
    GetProcessHeap(),
    0,
    AttributeListSize
    );

if (InitializeProcThreadAttributeList(StartupInfoEx.lpAttributeList,
                                      1,
                                      0,
                                      &AttributeListSize) == FALSE)
{
    Result = GetLastError();
    goto exitFunc;
}

if (UpdateProcThreadAttribute(StartupInfoEx.lpAttributeList,
                              0,
                              PROC_THREAD_ATTRIBUTE_PROTECTION_LEVEL,
                              &ProtectionLevel,
                              sizeof(ProtectionLevel),
                              NULL,
                              NULL) == FALSE)
{
    Result = GetLastError();
    goto exitFunc;
}

PROCESS_INFORMATION ProcessInformation = { 0 };

if (CreateProcessW(ApplicationName,
                   CommandLine,
                   ProcessAttributes,
                   ThreadAttributes,
                   InheritHandles,
                   EXTENDED_STARTUPINFO_PRESENT | CREATE_PROTECTED_PROCESS,
                   Environment,
                   CurrentDirectory,
                   (LPSTARTUPINFOW)&StartupInfoEx,
                   &ProcessInformation) == FALSE)
{
    Result = GetLastError();
    goto exitFunc;
}

更新 與服務

反惡意代碼服務啟動為受保護之後,其他非受保護的進程(甚至系統管理員)都無法停止服務。 在服務二進位檔更新的情況下,反惡意代碼服務必須接收安裝程式的回呼,才能自行停止,以便進行服務。 停止服務之後,反惡意代碼安裝程式可以執行升級,然後依照註冊服務及將服務啟動為受保護區段中所述的步驟,註冊憑證並啟動服務為受保護

請注意,服務應該確保只有受信任的呼叫端可以停止服務。 允許不受信任的呼叫端這樣做會失敗保護服務的目的。

取消註冊服務

當您卸載受保護的服務時,服務必須藉由呼叫 ChangeServiceConfig2 API 將本身標示為未受保護。 請注意,由於系統不允許任何非受保護的進程改變受保護服務的組態,因此必須由受保護的服務本身呼叫 ChangeServiceConfig2 服務重新設定為以未受保護的方式執行之後,卸載程式只需採取適當的步驟,即可從系統移除反惡意代碼軟體。

偵錯受反惡意代碼保護的服務

做為受保護進程安全性模型的一部分,其他非受保護的進程無法插入線程或寫入受保護進程的虛擬記憶體。 不過,允許核心調試程式 (KD) 偵錯任何受反惡意代碼保護的進程。 KD 也可以用來檢查反惡意代碼服務是否以受保護方式執行:

dt –r1 nt!_EPROCESS <Process Address>
+0x67a Protection       : _PS_PROTECTION
      +0x000 Level            : 0x31 '1'
      +0x000 Type             : 0y0001
      +0x000 Signer           : 0y0011

如果 Type 成員的值是 0y0001,服務就會以受保護的狀態執行。

此外,反惡意代碼保護的服務只允許下列SC命令:

  • sc config start=Auto
  • sc qc
  • sc start
  • sc interrogate
  • sc sdshow

如果附加調試程式,請在登錄中使用下列旗標,在未簽署的二進位檔載入到反惡意代碼保護的服務時,在調試程式中中斷。

Key:   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CI
Value: DebugFlags      REG_DWORD

將值設定為 00000400 ,以在簽章驗證失敗時中斷調試程式。

注意

受保護的進程限制:

  1. 具有UI或 GUI 的進程無法受到保護,因為核心鎖定記憶體中的進程的方式,而且不允許寫入它。
  2. 在 Windows 10 版本 1703 之前(Creators 更新),受保護的進程無法使用 TLS 或 SSL 通訊協定,因為本機安全性授權單位 (LSA) 與受保護進程之間憑證共用的限制。

資源

如需詳細資訊,請參閱:

本文會參考這些 Windows API 函式: