Mattiwatti/EfiGuard
GitHub: Mattiwatti/EfiGuard
一款在UEFI启动阶段禁用Windows PatchGuard和驱动签名强制的bootkit工具,支持从Vista到Win11全系列x64系统。
Stars: 2349 | Forks: 383
# 概述
EfiGuard 是一个便携式的 x64 UEFI bootkit,它在启动时修补 Windows 启动管理器、启动加载器和内核,以禁用 PatchGuard 和驱动程序签名强制 执行。
如果你只是想尝试 EfiGuard,请跳转到 [用法](#usage)。
# 功能
- 目前支持所有已发布的 EFI 兼容版本的 Windows x64,从 Vista SP1 到 Windows 11。
- 易于使用:可以通过 USB 闪存盘或 Windows EFI 分区启动,加载器会自动查找并启动 Windows。也可以使用 UEFI shell 或加载器手动加载和配置驱动程序。
- 广泛使用 [Zydis](https://github.com/zyantific/zydis) 反汇编库进行快速运行时指令解码,以支持比特征码匹配更稳健的分析,后者通常需要随着新的操作系统更新进行修改。
- 被动工作:驱动程序不加载或启动 Windows 启动管理器。相反,它通过启动选择菜单或 EFI 应用程序(如加载器)对固件启动管理器加载 `bootmgfw.efi` 的行为进行操作。如果启动非 Windows 操作系统,驱动程序将自动卸载。
- 支持四级修补,用于 `bootmgfw.efi` 启动 `bootmgr.efi` 而不是 `winload.efi` 的情况。当加载 WIM 文件以启动 WinPE、Windows 安装程序或 Windows 恢复模式时就是这种情况。
- 优雅恢复:如果修补失败,驱动程序将显示错误信息并提示按 ESC 键继续启动或重新启动。即使在最后的内核修补阶段也是如此,因为最后的修补阶段发生在调用 `ExitBootServices` 之前。许多 UEFI Windows bootkit 挂钩 `OslArchTransferToKernel`,虽然通过模式匹配很容易找到,但这是一个在 `ExitBootServices` 之后以保护模式执行的函数。这意味着没有启动服务可用于告知用户出了问题。

模拟的修补失败及错误信息
- 可调试:可以在内核修补阶段向内核调试器和屏幕(虽然是缓冲的)输出消息,并在启动管理器和启动加载器修补阶段向串口或屏幕(非缓冲)输出消息。如果驱动程序是使用 PDB 调试信息编译的,则可以通过指定虚拟 DXE 驱动程序基址并在 HAL 初始化后的任何时间点加载调试符号,像调试常规 NT 驱动程序一样调试它。
- DSE 绕过:可以作为启动时直接的 [UPGDSED](https://github.com/hfiref0x/UPGDSED)-风格的 DSE 禁用,或作为对 `SetVariable()` EFI 运行时服务的挂钩。后者作为一个任意内核模式读/写后门,可以使用 `NtSetSystemEnvironmentValueEx` 从 Windows 调用,并允许将 `g_CiEnabled`/`g_CiOptions` 设置为所需的值。提供了一个名为 `EfiDSEFix.exe` 的小型 DSEFix 风格应用程序,可用于执行此操作。也可以保留 DSE 启用而仅禁用 PatchGuard。加载器将默认使用 `SetVariable` 挂钩方法,因为一些反作弊和杀毒软件通常无法区分作弊软件或恶意软件与自签名驱动程序,并将目标对准 UPGDSED 修复。
- 通过在每个阶段修补 `ImgpValidateImageHash` 以及 `ImgpFilterValidationFailure`,支持磁盘上修改过的内核和启动加载器,后者可能会静默地将某些违规行为报告给 TPM 或 SI 日志文件。
- 允许 Secure Boot 与 Windows 7 配合使用(这不是开玩笑!)。Windows 7 本身对 Secure Boot 一无所知,因为它不支持它,或者(官方)甚至不支持在没有 CSM 的情况下启动。这对于希望在需要 WHQL Secure Boot 的锁定设备上使用 Windows 7 的人很有用。关于如何实现此功能的 Wiki 条目在[这里](https://github.com/Mattiwatti/EfiGuard/wiki/Secure-boot-on-Windows-7)。

启用 Secure Boot 的 Windows 7 上的 [WinObjEx64](https://github.com/hfiref0x/WinObjEx64)
# 问题和限制
- EfiGuard 无法禁用 Hypervisor-enforced Code Integrity (HVCI 或 HyperGuard),因为 HVCI 在更高的权限级别运行。EfiGuard **可以**与 HVCI 共存,甚至成功禁用普通内核中的 PatchGuard,但这在实践中没有用处,因为 HVCI 会捕获 PatchGuard 以前所做的事情。两种类型的 DSE 绕过都被 HVCI 渲染为无用:启动时修补无效,因为内核将完整性检查推迟到安全内核,如果使用 `SetVariable` 挂钩写入 `g_CiOptions` 将导致 `SECURE_KERNEL_ERROR` 错误检查。
- 不支持已检查内核,这是由于禁用的优化和添加的断言导致 PatchGuard 和 DSE 初始化代码的差异,以及已检查内核中 PatchGuard 的其他更改。这应该不是问题,因为已检查内核在没有附加内核调试器的情况下通常没有用处,而调试器会禁用 PatchGuard。
# 用法
有两种使用 EfiGuard 的方法:启动 **加载器应用程序**,它会为你加载驱动程序并启动 Windows;或者将驱动程序安装为 **UEFI 驱动程序条目**,以便由固件自动加载。
在某些高级配置中(例如多重引导时),安装驱动程序可能更可取,但加载器最易于使用,并且在所有配置中都应该运行良好。请参阅下表了解这两种方法之间最重要的区别。如果不确定,请选择 **加载器应用程序**。
| | 位置 | 安装 | 可跳过? | 启动哪个操作系统? |
|-------------------|----------------|----------------|--------------------|---------------------|
| UEFI Driver Entry | 必须在 ESP 上 | 通过 UEFI Shell | :x: | 与以前相同 |
| Loader | 任意位置 | 不需要 | :heavy_check_mark: | Windows |
加载器 vs UEFI 驱动程序条目比较
## 启动加载器
1. 下载 EfiGuard 并将 `EFI/Boot/Loader.efi` 重命名为 `bootx64.efi`。
2. 将文件放在启动驱动器上,例如 FAT32 格式的 USB 闪存盘(用于物理机)或 ISO/虚拟磁盘(用于虚拟机)。
假设驱动器为 `X:`,这两个文件的路径现在应该是 `X:/EFI/Boot/{bootx64|EfiGuardDxe}.efi`
3. 从你在步骤 2 中使用的驱动器启动机器。
大多数固件提供通过 F8/F10/F11/F12 访问的启动菜单来执行此操作。如果没有,你需要配置 BIOS 从新驱动器启动。
4. Windows 现在应该启动,你应该在启动期间看到 EfiGuard 消息。
5. 如果你使用 `SetVariable` 挂钩(默认设置)启动,请在启动后从管理员命令提示符运行 `EfiDSEFix.exe -d` 以禁用 DSE,或运行 `EfiDSEFix.exe` 查看完整的选项列表。
请注意,你 **不需要为加载器使用单独的驱动器**。如果需要,你可以将 EfiGuard 安装在 Windows 已安装的 ESP 上。但是,这稍微复杂一些,因为你需要为加载器添加 UEFI 启动条目。
为此,请使用 `mountvol X: /S` 将 ESP 挂载到 `X:` 并按照上述步骤操作,但 **不要** 重命名加载器,只需将两个文件复制到 `X:/EFI/Boot`。之后,你需要从 [UEFI Shell](https://github.com/tianocore/edk2/blob/edk2-stable201903/ShellBinPkg/UefiShell/X64/Shell.efi?raw=true) 使用 `bcfg boot addp 0 Loader.efi "EfiGuard"` 手动添加 UEFI 启动条目,或者使用 `efibootmgr` (Linux)、EasyUEFI (Windows) 或类似工具。
## 安装驱动程序
1. 使用 `mountvol X: /S` 将 ESP 挂载到 `X:`。
2. 将 `EfiGuardDxe.efi` 复制到 `X:/EFI/Boot/EfiGuardDxe.efi`。
3. 启动到 [UEFI Shell](https://github.com/tianocore/edk2/blob/edk2-stable201903/ShellBinPkg/UefiShell/X64/Shell.efi?raw=true) 并添加 UEFI 驱动程序条目:`bcfg driver add 0 EfiGuardDxe.efi "EfiGuardDxe"`。
4. Windows 现在应该启动,你应该在启动期间看到 EfiGuard 消息。
5. 如果你使用 `SetVariable` 挂钩(默认设置)启动,请在启动后从管理员命令提示符运行 `EfiDSEFix.exe -d` 以禁用 DSE,或运行 `EfiDSEFix.exe` 查看完整的选项列表。
**注意**:根据你的固件,你可能需要在步骤 3 中使用 "add**p**" 而不是 "add"。已知 VirtualBox 需要这样做,可能一些主板固件也需要。
**注意**:一些非常旧或不合规的固件可能根本不支持这种安装方法。在这些系统上,你别无选择,只能使用加载器。
# 编译
## 编译 EfiGuardDxe 和加载器
EfiGuard 需要 EDK2 才能构建。如果你没有安装 EDK2,请先按照 [Getting Started with EDK2](https://github.com/tianocore/tianocore.github.io/wiki/Getting-Started-with-EDK-II) 中的步骤操作,因为 EDK2 构建系统设置起来相当复杂。本节假设你有一个 `workspace` 目录,你的 `WORKSPACE` 环境变量指向该目录,并且在 `workspace/edk2` 中检出了 EDK2 的副本。支持的编译器是 MSVC、Clang、GCC 和 ICC。
1. 将 EfiGuard 仓库克隆到 `workspace/edk2/EfiGuardPkg`。
2. 打开设置 EDK2 环境变量的命令提示符或 shell。
3. 运行 `build -a X64 -t VS2019 -p EfiGuardPkg/EfiGuardPkg.dsc -b RELEASE`,将你的工具链替换 VS2019。
这将在 `workspace/Build/EfiGuard/RELEASE_VS2019/X64` 中生成 `EfiGuardDxe.efi` 和 `Loader.efi`。
## 编译 EfiDSEFix
EfiDSEFix 需要 Visual Studio 来构建。
1. 打开 `EfiGuard.sln` 并构建解决方案。
输出二进制文件 `EfiDSEFix.exe` 将位于 `Application/EfiDSEFix/bin` 中。
Visual Studio 解决方案还包括 `EfiGuardDxe.efi` 和 `Loader.efi` 的项目,可与 [VisualUefi](https://github.com/ionescu007/VisualUefi) 一起使用,但这些项目默认不构建,因为没有额外的代码它们无法链接,并且构建输出将不如 EDK2 生成的(更大)。`Loader.efi` 根本无法链接,因为 VisualUefi 缺少 UefiBootManagerLib。因此,这些项目文件仅用作开发辅助,EFI 文件仍应使用 EDK2 编译。为此目的设置 VisualUefi,请将仓库克隆到 `workspace/VisualUefi` 并打开 `EfiGuard.sln`。
# 架构

虽然 EfiGuard 是一个 UEFI bootkit,但它最初并不是作为 bootkit 开始的。EfiGuard 最初是一个在 NT 上运行的磁盘修补程序(类似于 [UPGDSED](https://github.com/hfiref0x/UPGDSED)),旨在测试基于反汇编器的方法的可行性,而不是使用 PDB 符号和特定于版本的签名。[PatchNtoskrnl.c](EfiGuardDxe/PatchNtoskrnl.c) 仍然看起来非常像这个原始设计。只有在这种方法被证明成功之后——在一年多的 Windows 更新中无需修改代码——UEFI 才成为进一步提高功能和易用性的一种方式。
bootkit 方法提供的一些好处包括:
- 无需对内核或引导加载程序进行磁盘修改。
- 无需使用 `bcdedit` 修改启动配置存储。
- 无需修补 `ImgpValidateImageHash`(尽管仍然可以选择这样做)。
- 具有讽刺意味的是,使用 bootkit 允许启用 Secure Boot,前提是你拥有 Platform Key 并且能够将你的个人证书添加到 `db` 存储。
EfiGuard 作为 bootkit 的最初化身是尝试让 dude719 的 [UEFI-Bootkit](https://github.com/ajkhoury/UEFI-Bootkit) 与最新版本的 Windows 10 配合使用,因为它已经过时并且不再适用于最新版本(像 UPGDSED 一样,通常由版本敏感的模式扫描引起)。虽然我最终做到了这一点,但我对结果并不满意,主要是因为选择了挂钩 `OslArchTransferToKernel`,如上所述,该函数在保护模式下并在调用 `ExitBootServices` 之后执行。除此之外,我不满意只能修补某些版本的 Windows 10;我希望 bootkit 能在迄今为止发布的每个 EFI 兼容版本的 Windows x64 上工作。因此,我重写了 bootkit,目标如下:
- 在启动的每个阶段(包括内核修补本身)提供修补信息。
- 支持所有 EFI 兼容的 Windows 版本(在撰写本文时)。
- 实现 bootkit 的延迟实例化,以及可选的内核后门,通过 EFI 系统表挂钩实现。
上图显示了最终 EfiGuard 启动流程的大致概览。有关特定组件的挂钩和修补,请参阅源文件中的 `EfiGuardDxe/PatchXxx.c`。有关驱动程序初始化/卸载和 EFI启动及运行时服务挂钩,请参阅 [EfiGuardDxe.c](EfiGuardDxe/EfiGuardDxe.c)。
# 致谢
- [UPGDSED](https://github.com/hfiref0x/UPGDSED) 由 [hfiref0x](https://github.com/hfiref0x) 和 [Fyyre](https://github.com/Fyyre) 开发
- [Zydis](https://github.com/zyantific/zydis) 由 [zyantific](https://zydis.re) 开发
- [Uninformed](http://uninformed.org/) 关于 PatchGuard [v1](http://uninformed.org/index.cgi?v=3&a=3&t=pdf), [v2](http://www.uninformed.org/?v=6&a=1&t=pdf) 和 [v3](http://uninformed.org/index.cgi?v=8&a=5&t=pdf) 的文章,由 Skyring 撰写
- [UEFI-Bootkit](https://github.com/ajkhoury/UEFI-Bootkit) 由 [dude719](https://github.com/ajkhoury) 开发
- [ReactOS](https://reactos.org)
# 许可证
EfiGuard 根据 GPLv3 授权。`EfiGuardDxe/Zydis` 子模块中的文件根据 MIT 许可证授权。
标签:Bootkit, Boot Manager, Conpot, DSE, EDR绕过, EFI驱动, PatchGuard, Rootkit, UEFI, Web报告查看器, Windows安全, Winload, Zeek, Zydis, 云资产清单, 内存修补, 内核补丁, 协议分析, 反作弊绕过, 安全意识培训, 安全攻防, 权限提升, 系统底层, 逆向工程, 驱动签名强制, 高交互蜜罐