ELAM 驱动程序要求

驱动程序安装必须使用现有工具进行联机和脱机安装,通过典型的 INF 处理注册驱动程序。 有关示例 ELAM 驱动程序代码,请参阅以下内容: https://github.com/Microsoft/Windows-driver-samples/tree/main/security/elam

AM 驱动程序安装

为了确保驱动程序安装兼容性,ELAM 驱动程序将自身播发为启动驱动程序,类似于所有其他启动驱动程序。 INF 将启动类型设置为 SERVICE_BOOT_START (0) ,这指示驱动程序应由启动加载程序加载并在内核初始化期间初始化。 ELAM 驱动程序将其组宣传为“提前启动”。 此组中驱动程序的早期启动行为将在 Windows 中实现,如下一部分所述。

下面是 ELAM 驱动程序 INF 的驱动程序安装部分的示例。

[SampleAV.Service]
DisplayName    = %SampleAVServiceName%
Description    = %SampleAVServiceDescription%
ServiceType    = 1       ; SERVICE_KERNEL_DRIVER
StartType      = 0       ; SERVICE_BOOT_START
ErrorControl   = 3       ; SERVICE_ERROR_CRITICAL
LoadOrderGroup = “Early-Launch”

由于 AM 驱动程序不拥有任何设备,因此必须将 AM 驱动程序安装为旧版,以便驱动程序仅作为服务添加到注册表中。 (如果 AM 驱动程序作为普通 PNP 驱动程序安装,它将添加到注册表的枚举部分,因此将具有 PDO 引用,这将导致卸载驱动程序时出现不需要的行为。)

还需要在 ELAM 驱动程序的 INF 文件中包括 SignatureAttributes 节

备份驱动程序安装

为了在 ELAM 驱动程序意外损坏时提供恢复机制,ELAM 安装程序还会在备份位置安装驱动程序的副本。 这将允许 WinRE 检索干净副本并恢复安装。

安装程序从中存储的 BackupPath 密钥读取备份文件位置

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\EarlyLaunch

然后,安装程序将备份副本放在 regkey 中指定的文件夹中。

AM 驱动程序初始化

Windows 启动加载程序 Winload 在移交给 Windows 内核之前,将所有启动启动驱动程序及其依赖 DLL 加载到内存中。 启动驱动程序表示在初始化磁盘堆栈之前需要初始化的设备驱动程序。 这些驱动程序包括磁盘堆栈和卷管理器,以及操作系统设备的文件系统驱动程序和总线驱动程序。

AM 驱动程序回调接口

ELAM 驱动程序使用回调为 PnP 管理器提供每个启动驱动程序和依赖 DLL 的说明,并且可以将每个启动映像分类为已知良好的二进制文件、已知错误的二进制文件或未知二进制文件。

默认操作系统策略不初始化已知错误的驱动程序和 DLL。 策略可以配置,并由 Winload 作为启动证明的一部分进行度量。

PnP 使用 AM 驱动程序提供的策略和分类来决定是否初始化每个启动映像。

注册表回调

提前启动驱动程序可以使用注册表或启动驱动程序回调来监视和验证用作每个启动启动驱动程序输入的配置数据。 配置数据存储在系统注册表配置单元中,该配置单元由 Winload 加载,在启动驱动程序初始化时可用。

注意

在系统启动之前,将放弃对 ELAM 注册表配置单元所做的任何更改。 因此,ELAM 驱动程序应使用适用于 Windows (ETW 的标准事件跟踪) 日志记录,而不是写入注册表。

这些回调在 ELAM 驱动程序的生存期内有效,在卸载驱动程序时将取消注册。 有关详细信息,请参阅:

启动驱动程序回调

使用 IoRegisterBootDriverCallbackIoUnRegisterBootDriverCallback 注册和注销 BOOT_DRIVER_CALLBACK_FUNCTION

此回调提供从 Windows 到 ELAM 驱动程序的状态更新,包括所有启动启动驱动程序已初始化且回调工具不再正常运行的时间。

回调类型

BDCB_CALLBACK_TYPE枚举描述了两种类型的回调:

  • 为 ELAM 驱动程序提供状态更新的回调 (BdCbStatusUpdate)
  • AM 驱动程序用于在初始化 BdCbInitializeImage (映像之前对启动启动驱动程序和依赖 DLL 进行分类的回调)

这两种回调类型具有提供特定于回调的其他信息的唯一上下文结构。

状态更新回调的上下文结构包含描述 Windows 标注的单个枚举类型。

初始化映像回调的上下文结构更为复杂,其中包含每个已加载映像的哈希和证书信息。 结构还包含一个字段,该字段是 AM 驱动程序在其中存储驱动程序分类类型的输出参数。

状态更新回调返回的错误被视为严重错误,并导致系统 bug 检查。 这为 ELAM 驱动程序提供了指示何时达到 AM 策略之外的状态的能力。 例如,如果未加载和初始化 AM 运行时驱动程序,则提前启动驱动程序可能会使准备卸载回调失败,以防止 Windows 在没有加载 AM 驱动程序的情况下进入状态。

当从初始化映像回调返回错误时,图像被视为未知图像。 根据 OS 策略初始化或跳过未知驱动程序的初始化。

恶意软件签名

恶意软件签名数据由 AM ISV 确定,但至少应包含已批准的驱动程序哈希列表。 签名数据存储在注册表中,位于 Winload 加载的 HKLM 下的新“提前启动驱动程序”配置单元中。 每个 AM 驱动程序都有一个唯一的密钥,用于存储其签名二进制大型对象 (BLOB) 。 注册表路径和项采用以下格式:

HKLM\ELAM\<VendorName>\

在密钥中,供应商可以自由定义和使用任何值。 有三个定义的二进制 Blob 值由测量启动测量,供应商可以使用每个值:

  • 测量
  • 策略
  • Config

提前启动反恶意软件使用 ELAM 配置单元后,将卸载该配置单元的性能。 如果用户模式服务想要更新签名数据,则应从文件位置 \Windows\System32\config\ELAM 装载 hive 文件。 例如,可以生成 UUID,将其转换为字符串,并将其用作将配置单元装载到的唯一键。 这些数据 BLOB 的存储和检索格式由 ISV 决定,但签名数据必须经过签名,以便 AM 驱动程序可以验证数据的完整性。

验证恶意软件签名

验证恶意软件签名数据完整性的方法由每个 AM ISV 决定。 CNG 加密基元函数可用于帮助验证恶意软件签名数据的数字签名和证书。

恶意软件签名失败

如果 ELAM 驱动程序检查签名数据的完整性,并且该检查失败,或者如果没有签名数据,则 ELAM 驱动程序的初始化仍然成功。 在这种情况下,对于每个启动驱动程序,ELAM 驱动程序必须为每个初始化回调返回“未知”。 此外,ELAM 驱动程序应在启动后将此信息传递到运行时 AM 组件。

卸载 AM 驱动程序

当回调 StatusType 为 BdCbStatusPrepareForUnload 时,这表示 AM 驱动程序已初始化所有启动驱动程序,并且 AM 驱动程序应准备卸载。 在卸载之前,早期启动 AM 驱动程序需要取消注册其回调。 在回调期间无法进行注销;相反,它必须发生在 DriverUnload 函数中,驱动程序可以在 DriverEntry 期间指定该函数。

若要保持恶意软件防护的连续性并确保正确切换,应在卸载早期启动 AM 驱动程序之前启动运行时 AM 引擎。 这意味着,运行时 AM 引擎应是提前启动 AM 驱动程序验证的启动驱动程序。

性能

驱动程序必须满足下表中定义的性能要求:

方案

开始时间

结束时间

上限

在允许其初始化之前,评估加载的启动关键驱动程序。 这还包括状态更新回调。

内核调用反恶意软件驱动程序以评估加载的启动关键驱动程序。

反恶意软件驱动程序返回评估结果。

0.5 毫秒

评估所有加载的启动关键驱动程序

内核调用反恶意软件驱动程序以评估第一个加载的启动关键驱动程序。

反恶意软件驱动程序返回上次启动关键驱动程序的评估结果。

50 毫秒

占用 (驱动程序 + 内存) 中的配置数据

空值

空值

128kB

初始化驱动程序

ELAM 驱动程序评估启动驱动程序后,内核将使用 ELAM 返回的分类来决定是否初始化驱动程序。 此决定由策略决定,存储在以下位置的注册表中:

HKLM\System\CurrentControlSet\Control\EarlyLaunch\DriverLoadPolicy

这可以通过在已加入域的客户端上组策略进行配置。 反恶意软件解决方案可能需要在非托管方案中向最终用户公开此功能。 为 DriverLoadPolicy 定义了以下值:

PNP_INITIALIZE_DRIVERS_DEFAULT 0x0  (initializes known Good drivers only)
PNP_INITIALIZE_UNKNOWN_DRIVERS 0x1  
PNP_INITIALIZE_BAD_CRITICAL_DRIVERS 0x3 (this is the default setting)
PNP_INITIALIZE_BAD_DRIVERS 0x7

启动失败

如果由于初始化策略而跳过启动驱动程序,内核将继续尝试初始化列表中的下一个启动驱动程序。 这会一直持续到驱动程序全部初始化,或者启动失败,因为跳过的启动驱动程序对启动至关重要。 如果在启动磁盘堆栈后发生崩溃,则存在故障转储,其中包含有关原因或崩溃的一些信息,以包含有关缺少驱动程序的信息。 这可以在 WinRE 中用于确定失败的原因并尝试修正。

ELAM 和测量启动

如果 ELAM 驱动程序 (rootkit(例如) )检测到策略冲突,它应立即调用 Tbsi_Revoke_Attestation ,使指示系统处于良好状态的 PCR 失效。 如果测量的启动出现问题(例如系统上没有 TPM),该函数将返回错误。

Tbsi_Revoke_Attestation 可从内核模式调用。 它将 PCR[12] 扩展为未指定的值,并递增 TPM 中的事件计数器。 这两个操作都是必需的,因此,从此处向前创建的所有引号中的信任都会断开。 因此,测量的启动日志在启动 TPM 的剩余时间内不会反映 TPM 的当前状态,并且远程系统将无法在系统的安全状态中形成信任。