pro*_*481 9 assembly operating-system bios bootloader uefi
我正在研究UEFI这个术语时的引导加载程序.我可以理解一些关于UEFI的事情.但是,在什么模式下(Real,Protected,Long),UEFI的系统启动了吗?如果正常的引导加载程序无法使用UEFI,那么在处理UEFI时,引导加载程序的替代方案是什么?我是否需要任何其他编程来创建一个,而不是组装?
UEFI固件在64位平台上以64位长模式运行,在32位平台上以扁平模式运行; 与BIOS不同,UEFI具有自己的架构,独立于CPU和自己的设备驱动程序.UEFI可以挂载分区并读取某些文件系统.
当配备有UEFI的x86计算机时,该接口在系统存储中搜索标记有特定全局唯一标识符(GUID)的分区,该标识将其标记为EFI系统分区(ESP).BTW Windows不会挂载此分区,您无法在操作系统中看到它.但是有一个技巧,你只需将VBR中的分区类型(使用HexWorkshop)更改为常规FAT32代码,它就会被挂载到操作系统中.
此分区包含为EFI体系结构编译的应用程序.通常,您不必处理汇编程序来编写UEFI应用程序/加载程序,它只是一个常规的C代码.默认情况下,它位于"EFI/BOOT/BOOTX64.EFI".当手动或自动选择引导加载程序时,UEFI会将其读入内存并控制引导过程.
这是这个问题的一个很好的答案:
其他现代 64 位机器具有新的 EFI 固件。这些根本不会从光盘的扇区 #0 加载引导程序。它们通过 EFI 引导管理器加载和运行 EFI 引导加载程序应用程序进行引导。此类程序在保护模式下运行。这是 EFI 引导程序。
EFI 固件通常会在退出处理器重置的几条指令内切换到保护模式。切换到保护模式是在 EFI 固件初始化的所谓“SEC 阶段”的早期完成的。从技术上讲,32 位及更高版本的 x86 处理器甚至不会以正确的实模式启动,而是以俗称的虚模式启动。(CS 寄存器的初始段描述符没有描述传统的实模式映射,这使得它“不真实”。)
因此,可以说这些 EFI 系统在本地引导到 EFI 引导加载程序时(即,当它们不使用兼容性支持模块时)从不正确进入实模式,因为它们从非实模式直接切换到保护模式并从那时起保持保护模式。
在下面,一些句子是我见过的最佳来源的副本、合并和措辞改进,然后我通过使用我自己的硬件案例研究来改进和纠正他们的未知数/错误。
引导保护
Intel Boot Guard 是 Intel 在第四代 Intel Core (Haswell) 中引入的一项技术,用于验证启动过程。这是通过在制造过程中将 BIOS 签名的公钥闪存到现场可编程熔丝 (FPF) 中来实现的,FPF 是英特尔 ME(在 PCH 中)内部的一次性可编程存储器;通过这种方式,它拥有 BIOS 的公钥,并且可以在每次后续启动时验证正确的签名。一旦由制造商启用,英特尔 Boot Guard 就不能再被禁用。
据英特尔称,Boot Guard 有两种不同的模式。典型的 PC OEM 将其配置为 “验证启动”模式。PC 制造商将他们的公钥融合到硬件本身中。如果 UEFI 固件未由 OEM 签名(即由 OEM 创建),计算机将停止并拒绝启动。这就是您无法修改 UEFI 固件的原因。还有第二个选项:“测量启动”模式,在该模式下,硬件使用英特尔 TXT 来安全存储有关启动过程的信息(在受信任的平台模块 (TPM) 中)或借助 SMX 的英特尔平台信任技术 (PTT)。然后操作系统可以检查这些信息,如果有问题,就会向用户显示错误。
安全启动
启用并完全配置后,安全启动可帮助计算机抵御恶意软件的攻击和感染。安全启动通过验证其数字签名来检测对启动加载程序、关键操作系统文件和未经授权的选项 ROM 的篡改。检测在攻击或感染系统之前被阻止运行。UEFI 安全启动假定 OEM 平台固件是可信计算库 (TCB)(即它已使用 BootGuard 技术初始化并隐式信任它)。
UEFI前阶段
当 OEM 收到 PCH 时,ME 仍处于“制造模式”并运行固件的特殊部分,该部分将从闪存 ROM 的部分复制“OEM 公钥哈希”和“引导保护配置文件配置”策略值到现场可编程熔断器 (FPF) 中,使其永久且不可更改。然后它设置一个保险丝以指示它已退出制造模式,以便固件的这部分不会再次运行。可以使用英特尔闪存映像工具 (FITC) 在闪存映像中调整这些值,但除非您有办法强制 ME 进入制造模式,否则闪存映像中的值将被忽略。
Bootguard 配置文件如下:
启用保护 BIOS 环境:如果设置,这可能意味着 ACM 将 IBB 段复制到 CPU 缓存中,以便它以缓存作为 RAM (CAR) 模式运行并禁用所有 DMA 以防止设备能够修改它。
一旦电源可用,ME CPU 从其片上启动 ROM 启动,检查一些带和保险丝以确定其配置,然后通常从 SPI 闪存的 ME 区域复制闪存分区表 (FPT)(它通常位于 BIOS 区域下方)到其片上 SRAM。它通过使用 SPI 闪存最低地址处的闪存描述符来定位 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 和虚幻模式段描述符 hack——因为这是寄存器的初始状态),它指向 SPI 闪存 BIOS 区域中某处的 FIT 表。
此图显示了 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;
Run Code Online (Sandbox Code Playgroud)
在我的系统上,在 FFFFFFC0 到 FFD90100 处有一个 FIT 指针
FIT 表指向微代码更新、ACM、BootGuard 启动策略清单(包含 IBBS)和 BootGuard 密钥清单等。
我的 FIT 不包含任何0x7 条目。记录类型 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:
....
Run Code Online (Sandbox Code Playgroud)
密钥清单包含:
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
Run Code Online (Sandbox Code Playgroud)
然后由微代码设置缓存为 RAM (CAR)(又名 AC-RAM,无填充模式和无驱逐模式)。然后在 FIT 中搜索与 CPU ID 匹配的微码更新。当前的微码将它们从闪存线性复制到 L3 缓存中,并使用片上对称 AES 密钥解密,然后使用(片上?)RSA 密钥进行验证。这些微码更新很可能还包含 ACM 的密钥散列。然后通过写入 UCODE MSR 应用微代码更新,CPU 将其读出,我假设是通过正常的内存访问。FIT 绝对必须包含一个微码补丁,它修补微码 SRAM 以补充现有的微码 ROM。[1]
接下来,微代码返回 FIT 以找到启动 ACM(又名 BIOS 或 Bootguard ACM),并将它的奇怪副本复制到 L3(看起来多个超线程正在复制 4KB 块? - 根据该来源)。ACM 包含一个 RSA 公钥;微码将其与芯片上的密钥或存储在微码更新中的密钥进行比较,如果不匹配则停止 CPU。然后微码检查 ACM 上的签名,如果不匹配则再次停止。
Startup ACM 完全运行在 L3 之外。ACM通过 MSR 从 ME接收 OEM 公钥哈希(验证密钥清单的密钥哈希)和 Bootguard配置文件。
ACM 将 BootGuard 密钥清单从 SPI 闪存(由 FIT 指向并由 标识__KEYM__)读取到 L3 中,并散列存储在其中的 RSA 公钥。如果它与 OEM 公钥哈希不匹配,或者密钥清单上的 OEM 公钥签名或者如果存储的 KmSvn 不正确,ACM 将根据 Bootguard 配置文件位采取行动。如果匹配,它会在 FIT 中定位 Bootguard 策略(并由 标识__ACBP__)并将其复制到 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
Run Code Online (Sandbox Code Playgroud)
启动 ACM 始终是最终的 ACM,它GETSEC[EXITAC]指向0xFEE90000bootguard 策略清单中的 IBBS 基址 + 入口点地址(位于第一个 IBB 中),该清单似乎位于 ME 区域中,并且可能包含切换 CPU 的代码回到虚幻模式并跳转到第 4 个 IBB 段中的传统重置向量。GETSEC只能在保护模式下执行,所以很明显CPU在启动ACM中处于保护模式,所以必须在进入前通过微码使能。传统复位向量位于 0xFFFFFFF0,在我的系统上是相对跳转到 FFFFFFF5 - 3BD = FFFFFC38,这是 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
.
.
.
Run Code Online (Sandbox Code Playgroud)