在下文中,一些句子是我见过的最佳资源的复制、合并和措辞改进,然后我通过使用我自己的硬件案例研究来改进和纠正它们的未知数/错误。
引导保护
英特尔 Boot Guard 是英特尔在第四代英特尔酷睿 (Haswell) 中引入的一项技术,用于验证引导过程。这是通过在制造过程中将 BIOS 签名的公钥刷入现场可编程熔断器 (FPF) 来实现的,FPF 是英特尔 ME 内的一次性可编程存储器(在 PCH 中);通过这种方式,它拥有 BIOS 的公钥,并且可以在每次后续引导期间验证正确的签名。一旦制造商启用,英特尔 Boot Guard 将无法再禁用。
据英特尔称,Boot Guard 有两种不同的模式。典型的 PC OEM 将其配置为 “验证启动” 模式。 PC 制造商将其公钥融合到硬件本身中。如果 UEFI 固件未经 OEM 签名(即由 OEM 创建),计算机将停止并拒绝启动。这就是您无法修改 UEFI 固件的原因。还有第二个选项:“Measured Boot” 模式,其中硬件使用英特尔 TXT 来安全存储有关引导过程的信息(在受信任的平台模块 (TPM) 中)或英特尔平台信任技术 (PTT) ) 在 SMX 的帮助下。然后,操作系统可以检查这些信息,如果有问题,就会向用户显示错误。
安全启动
启用并完全配置后,安全启动可帮助计算机抵御恶意软件的攻击和感染。 Secure Boot 通过验证其数字签名来检测对引导加载程序、关键操作系统文件和未经授权的选项 ROM 的篡改。检测在攻击或感染系统之前被阻止运行。 UEFI 安全启动假定 OEM 平台固件是可信计算库 (TCB)(即它已使用 BootGuard 技术进行初始化并隐式信任它)。
验证启动过程
预 UEFI 阶段
当 OEM 收到 PCH 时,ME 仍处于“制造模式”并运行固件的特殊部分,该部分将从其部分复制“OEM 公钥哈希”和“引导保护配置文件配置”策略值将闪存 ROM 插入现场可编程熔断器 (FPF),使其永久不变。然后它会设置一个保险丝以指示它已退出制造模式,因此这部分固件将不会再次运行。可以使用英特尔闪存映像工具 (FITC) 在闪存映像中调整这些值,但除非您有办法强制 ME 进入制造模式,否则闪存映像中的值将被忽略。
Bootguard 配置文件如下:
Protect BIOS Environment Enabled:如果设置,这可能意味着 ACM 会将 IBB 段复制到 CPU 缓存中,以便它在缓存作为 RAM (CAR) 模式下运行,并禁用所有 DMA 以防止设备可以修改。
一旦电源可用,ME CPU 就会从其片上引导 ROM 启动,检查一些带和保险丝以确定其配置,然后通常从 ME 区域复制闪存分区表 (FPT) SPI 闪存(通常位于 BIOS 区域下方)到其片上 SRAM。它通过使用 SPI flash 最低地址的 flash 描述符来定位 ME 区域。
引导 ROM 使用 FPT 定位 FTPR 分区,并将其从 SPI 闪存复制到片上 SRAM。然后,它检查存储在分区清单中的密钥的 SHA-1 哈希值是否与其片内 ROM 中的哈希值匹配,并验证分区清单其余部分上的 RSA 签名。分区表包含分区中每个模块的哈希值,允许在将模块复制到片上 SRAM 执行后对其进行验证。
当 ME 启动 x86 CPU 时,可能在 bup.met 中。 BIST 和 BSP MP 初始化算法发生。 CS:FFF0(其中 CS 为 0xF000,段描述符缓存包含基址 0xFFFF0000)处的传统复位向量不再是 x86 CPU 在复位时执行的第一条指令。相反,片上微码在 0xFFFFFFC0 处获取 FIT 指针(使用 0xF000:FFC0 和虚幻模式段描述符破解 - 因为this 是寄存器的初始状态),它指向 SPI 闪存 BIOS 中某处的 FIT 表地区。
This image 显示 16 字节的 FIT 条目,它们的模式距离末尾 3 个字节。
#pragma pack (1)
typedef struct {
UINT64 Address;
UINT8 Size[3];
UINT8 Rsvd;
UINT16 Version;
UINT8 Type:7;
UINT8 C_V:1;
UINT8 Checksum;
} FIRMWARE_INTERFACE_TABLE_ENTRY;
在我的系统上,在 FFFFFFC0 处有一个指向 FFD90100 的 FIT 指针
FIT 表指向微码更新、ACM、BootGuard 引导策略清单(包含 IBBS)和 BootGuard 密钥清单等。
我的 FIT 不包含任何 0x7 entries。记录类型 7 仅由旧版英特尔® TXT FIT 引导使用,如果不使用后者,则不需要。
BootGuard 引导策略 (IBBM) 包含:
Intel BootGuard Boot Policy Manifest found at base FD3C00h
Tag: ACBP Version: 10h HeaderVersion: 01h
PMBPMVersion: 10h PBSVN: 00h ACMSVN: 02h NEMDataStack: 0010h
Initial Boot Block Element found at base FD3C28h
Tag: IBBS Version: 10h Unknown: 0Fh
Flags: 00000000h IbbMchBar: FED10000h VtdBar: 00000000h
PmrlBase: FED90000h PmrlLimit: 00000000h EntryPoint: 00100000h
Post IBB Hash:
0000000000000000000000000000000000000000000000000000000000000000
IBB Digest:
B9CCC06B77AEACC51768981D07CBE9E43D34DB6795752C4B998312241B26F874
IBB Segments:
Flags: 0000h Address: FFE10000h Size: 001C3C00h
Flags: 0000h Address: FFFD4C00h Size: 00000080h
Flags: 0000h Address: FFFD5C80h Size: 0000A380h
Flags: 0000h Address: FFFE8000h Size: 00018000h
Boot Policy Signature Element found at base FD3CDDh
Tag: PMSG Version: 10h
Boot Policy RSA Public Key (Exponent: 10001h):
....
Boot Policy RSA Public Key Hash:
....
Boot Policy RSA Signature:
....
密钥清单包含:
Intel BootGuard Key Manifest (KEYM) found at base FD4C80h
Tag: KEYM Version: 10h KmVersion: 10h KmSvn: 00h KmId: 0Fh
Key Manifest RSA Public Key Hash:
...
Boot Policy RSA Public Key Hash:
...
Key Manifest RSA Public Key (Exponent: 10001h):
...
Key Manifest RSA Signature:
... //it does actually contain a signature, I just removed these for space
然后由微码设置缓存为 RAM (CAR)(又名 AC-RAM,无填充模式和无驱逐模式)。然后在 FIT 中搜索与 CPU ID 匹配的微码更新。当前的微码将它们从闪存线性复制到 L3 缓存中,并使用片上对称 AES 密钥解密,然后使用(片上?)RSA 密钥进行验证。这些微码更新很可能还包含 ACM 的密钥散列。然后通过写入 UCODE MSR 来应用微码更新,CPU 会通过正常的内存访问将其读出。 FIT 绝对必须包含一个微码补丁,它对微码 SRAM 进行补丁以补充现有的微码 ROM。 [1]
接下来,微码返回 FIT 以查找 Startup ACM(又名 BIOS 或 Bootguard ACM)并将其复制到 L3 中(看起来多个超线程正在复制 4KB 块?--根据该来源) . ACM 包含一个 RSA 公钥;微码将其与芯片上的密钥或存储在微码更新中的密钥进行比较,如果不匹配则停止 CPU。微码然后检查 ACM 上的签名,如果不匹配则再次停止。
Startup ACM 完全用完 L3。 ACM 通过 MSR 从 ME 接收 OEM 公钥哈希 (the Key Hash that verifies the Key Manifest) 和 Bootguard Profile。
ACM 将 BootGuard 密钥清单从 SPI 闪存(由 FIT 指向并由 __KEYM__ 标识)读取到 L3 并散列存储在其中的 RSA 公钥。如果它与 OEM 公钥哈希不匹配,或者如果密钥清单上的 OEM 公钥签名或者如果存储的 KmSvn 不正确,ACM 将根据 Bootguard 配置文件位采取措施。如果匹配,它会在 FIT(并由 __ACBP__ 标识)中找到 Bootguard 策略并将其复制到 L3。然后,ACM 计算策略中 RSA 公钥的哈希值,并将其与存储在密钥清单中的 SHA256 哈希值进行比较。如果匹配失败,或者策略上的 RSA 签名不匹配,则 ACM 会再次根据配置文件设置采取措施。
ACM 使用现已验证的 Bootguard 策略结构将初始引导块 (IBB) 段读入 L3,并在复制它们时对其进行散列处理。如果此计算的哈希与策略中的“IBB 摘要”不匹配,ACM 将根据配置文件设置采取措施。第 4 个 IBB 段包含重置向量,因此它可以防止被修改。目前尚不清楚它是否让 CPU 处于 CAR 模式,或者是否只是将它们缓存在 L3 中但没有禁用驱逐,即没有启用 CAR 模式。然而,SEC 需要(禁用)并设置新的 CAR 模式。
使用 RwEverything 转储物理内存,或为您的 ME 版本下载 CSME 系统工具,然后执行 fptw64 -d -me -bios dump.bin 将转储闪存(通常您只能转储 BIOS 区域而不是 ME 区域) .现在可以在 UEFITool NE Alpha 58 中分析转储,并且 FIT 在正文中显示 ACM 的入口点。因此,如果您右键单击,将其解压缩并在 IDA 中以 32 位格式打开,入口点将位于 3BB1h + 18h = 3BC9h
3BC9 mov ax, ds
3BCC mov ss, ax
3BCF mov es, ax
3BD2 mov fs, ax
3BD5 mov gs, ax
3BD8 mov esp, ebp
3BDA add esp, 1000h
3BE0 mov eax, ebp
3BE2 add eax, 4C8h
3BE7 lidt fword ptr [eax]
3BEA push ebp
3BEB call sub_392A
3BF0 mov ebx, eax
3BF2 mov edx, 0
3BF7 mov eax, 3
3BFC getsec
启动 ACM 始终是最终 ACM,它 GETSEC[EXITAC]s 到引导保护策略清单中的 IBBS 基地址 + 入口点地址(0xFEE90000,位于第一个 IBB 中),它似乎在 ME 中区域,并且可能包含将 CPU 切换回虚幻模式并跳转到第 4 个 IBB 段中的旧重置向量的代码。 GETSEC只能在保护模式下执行,所以很明显CPU在启动ACM中处于保护模式,所以进入前必须通过微码开启。旧的重置向量位于 0xFFFFFFF0,在我的系统上是相对跳转到 FFFFFFF5 - 3BD = FFFFFC38,这是 SEC 核心入口点。
SEC
SEC 核心是来自 FFFFCA14 - FFFFCA17 的原始部分,来自 FFFFCA18 - FFFFFFBB 的 PE32 图像,来自 FFFFFFBC - FFFFFFBF 的原始部分,以及来自 FFFFFFC0-FFFFFFFF 的原始部分(包含重置向量)。
复位向量跳转到的SEC Core中PE32 Image的入口点包含:
0x00: DB E3 fninit
0x02: 0F 6E C0 movd mm0, eax //move BIST value to mm0
0x05: 0F 31 rdtsc
0x07: 0F 6E EA movd mm5, edx
0x0a: 0F 6E F0 movd mm6, eax //save tsc
0x0d: 66 33 C0 xor eax, eax //clear eax
0x10: 8E C0 mov es, ax
0x12: 8C C8 mov ax, cs
0x14: 8E D8 mov ds, ax
0x16: B8 00 F0 mov ax, 0xf000
0x19: 8E C0 mov es, ax
0x1b: 67 26 A0 F0 FF 00 00 mov al, byte ptr es:[0xfff0]
0x22: 3C EA cmp al, 0xea
0x24: 74 0E je 0x34 //if ea is at ffff0h then jump to the 0xf000e05b check
0x26: BA F9 0C mov dx, 0xcf9
0x29: EC in al, dx //read port 0xcf9
0x2a: 3C 04 cmp al, 4
0x2c: 75 25 jne 0x53
0x2e: BA F9 0C mov dx, 0xcf9 //perform warm reset since if CPU only reset is issued not all MSRs are restored to their defaults
0x31: B0 06 mov al, 6
0x33: EE out dx, al
0x34: 67 66 26 A1 F1 FF 00 00 mov eax, dword ptr es:[0xfff1]
0x3c: 66 3D 5B E0 00 F0 cmp eax, 0xf000e05b
0x42: 75 0F jne 0x53 //if it isn't, move to notwarmstart
0x44: B9 1B 00 mov cx, 0x1b //if it is equal, read bsp bit from apic_base msr
0x47: 0F 32 rdmsr
0x49: F6 C4 01 test ah, 1
0x4c: 74 41 je 0x8f //if the and operation with 00000001b produces a zero result i.e. it's an AP then jump to cli, hlt
0x4e: EA F0 FF 00 F0 ljmp 0xf000:0xfff0 //if it's the BSP, exit unreal mode by far jumping to 0xffff0 which reloads the segment descriptor cache with a 0 base
notwarmstart:
0x53: B0 01 mov al, 1
0x55: E6 80 out 0x80, al //send 1 as a debug POST code
0x57: 66 BE 68 FF FF FF mov esi, 0xffffff68
0x5d: 66 2E 0F 01 14 lgdt cs:[si] //loads 32&16 GDT pointer (not 16&6, due to 66 prefix) at 16bit address fff68 in si into GDTR (base:ffffff28 limit:003f); will be accessing alias and not shadow ROM
//enter 16 bit protected mode//
0x62: 0F 20 C0 mov eax, cr0
0x65: 66 83 C8 03 or eax, 3 //Set PE bit (bit #0) & MP bit (bit #1)
0x69: 0F 22 C0 mov cr0, eax //Activate protected mode
0x6c: 0F 20 E0 mov eax, cr4
0x6f: 66 0D 00 06 00 00 or eax, 0x600 //Set OSFXSR bit (bit #9) & OSXMMEXCPT bit (bit #10)
0x75: 0F 22 E0 mov cr4, eax
//set up selectors for 32 bit protected mode entry
0x78: B8 18 00 mov ax, 0x18 //segment descriptor at 0x18 in GDT is (raw): 00cf93000000ffff
0x7b: 8E D8 mov ds, ax
0x7d: 8E C0 mov es, ax
0x7f: 8E E0 mov fs, ax
0x81: 8E E8 mov gs, ax
0x83: 8E D0 mov ss, ax
0x85: 66 BE 6E FF FF FF mov esi, 0xffffff6e
0x8b: 66 2E FF 2C ljmp cs:[si] //transition to flat 32 bit protected mode and jump to address at 0x0:0xffffff6e aka. 0xffffff6e which is fffffcd8. CS contains 0 remember (it's the base that is 0xffff) so it will load the first entry. This address is also in the SEC Core PE32 Image
0x8f: FA cli
0x90: F4 hlt
.
.
.