UEFI原理 · 2021年4月15日 24

BIOS写保护机制

BIOS写保护机制原理及访问寄存器方法。

PCI总线配置空间

CPU通过PCI设备的设备号以及配置空间中的寄存器编号来访问配置空间寄存器。

PCI有三个相互独立的物理地址空间:设备存储器地址空间、I/O地址空间和配置空间。

配置空间是PCI所特有的一个物理空间。由于PCI支持设备即插即用,所以PCI设备不占用固定的内存地址空间或I/O地址空间,而是由操作系统决定其映射的基址。系统加电时,BIOS检测PCI总线,确定所有连接在PCI总线上的设备以及它们的配置要求,并进行系统配置。所以,所有的PCI设备必须实现配置空间,从而能够实现参数的自动配置,实现真正的即插即用。

要访问PCI总线设备的配置空间,必须先查找该设备。查找的基本根据是各PCI设备的配置空间里都存有特定的设备号(Device ID)及销售商号(Vendor ID),它们占用配置空间的00h地址。而查找的目的是获得该设备的总线号和设备号。

查找的基本过程如下:用I/O命令写配置空间的地址寄存器(CONFIG_ADDRESS)CF8h,使其最高位为1,总线号及设备为0,功能号及寄存器号为0,即往I/O端口CF8h80000000h;然后用I/O命令读取配置空间的数据寄存器(CONFIG_DATA) 0xCFC。如果该寄存器值与该PCI设备的Device ID及Vendor ID不相符,则依次递增设备号/总线号,重复上述操作直到找到该设备为止。如果查完所有的设备号/总线号(1~5)仍不能找到该设备,则应当考虑硬件上的问题。对于多功能设备,只要设备配置寄存器相应的功能号值,其余步骤与单功能设备一样。

Intel® 7 Series / C216 Chipset Family Platform Controller Hub datasheet的13章《LPC Interface Bridge Registers (D31:F0)》:

PCH的LPC bridge函数位于PCI Device 31:Function 0中。该函数包含许多函数单元,如DMA、中断控制器、计时器、电源管理、系统管理、GPIO、RTC和LPC配置寄存器。

LPC接口PCI寄存器地址映射表(LPC I/F – D31:F0)如下:

image-20210415162020665
image-20210415162032730

SPI(Serial Peripheral Interface)

SPI位于内存映射空间中,其包含允许对SPI接口上的设备进行设置和编程的寄存器,所有寄存器(包括内存映射寄存器)必须按byte、word和DWord进行寻址。

SPI Host接口寄存器在基址(SPIBAR)为3800h的RCRB(Root Complex Register Block)芯片组寄存器空间中进行内存映射,位于3800h-39FFh范围内。

RCRB的地址可以在RCBA寄存器中找到,通过SPIBAR + Offset可以访问各个寄存器,偏移表如下:

image-20210416104301774
image-20210416104315169

写保护机制

英特尔硬件提供两种主要机制来保护位于主板上的SPI ROM芯片不被操作系统上的软件写入:

  • 通过PCI配置空间访问的平台控制器集线器(PCH)中BIOS_CNTL寄存器的BIOS Write Enable (BIOSWE) 和、BIOS Lock Enable (BLE)位和SMM BIOS Write Protect Disable(SMM_BWP)
  • SPI保护区域寄存器PR0-PR5。同时,PCH中 HSFS 寄存器的FLOCKDN位用于保护PR寄存器不被覆盖。

Intel® 7 Series / C216 Chipset Family Platform Controller Hub datasheet13.1.33节对BIOS_CNTL寄存器的描述如下图:

image-20210415151842706

BIOSWE位用于控制对闪存芯片的写访问, 置零后只允许读取访问。BLE位用于保护BIOSWE位不被SMM代码进行未经授权的修改:

  1. 在早期引导阶段,系统固件将BIOSWE位置零并设置BLE位,一旦BLE位被设为1——直到下一次平台重置,它都不能被修改。
  2. BLE = 1时,每次尝试设置BIOSWE位都会引发系统管理中断(SMI) —— 最高优先级的中断,将挂起操作系统的执行并将CPU切换到系统管理模式。
  3. 在SMI调度期间,SMM代码将BIOSWE位清零,并恢复OS执行,因此,在OS下运行的攻击者代码可以重新设置BIOSWE

SMM_BWP位设置后,仅当所有内核在系统管理模式(SMM)中运行且BIOSWE位设置为1时,SMM BIOS写保护禁用(SMM_BWP)才允许BIOS固件可写。

BIOS_CNTl寄存器位于LPC I/F – D31:F0的0xDC偏移处,默认值为0x20(未开启写保护的默认值),大小为8字节。

Intel® 7 Series / C216 Chipset Family Platform Controller Hub datasheet22.1.2节对HSFS寄存器的描述如下图:

image-20210416104705353

FLOCKDN位用于保护SPI保护区域寄存器PR0-PR5不被修改,一旦设置为1,则只能通过硬件复位来清除此位。

用Chipsec 访问寄存器

使用chipsec.utilcmd.pci_cmd模块访问PCI配置空间寄存器,用法:

chipsec_util pci enumerate #枚举PCI/PCIe设备
chipsec_util pci <bus> <device> <function> <offset> [width] [value] #读写PCI配置寄存器
chipsec_util pci dump [<bus> <device> <function>] #dump PCI配置空间数据
chipsec_util pci xrom [<bus> <device> <function>] [xrom_address] #枚举PCI/PCIe ROM
chipsec_util pci cmd [mask] [class] [subclass]

使用命令python chipsec_util.py pci enumerate对PCI设备进行枚举,可以看到设备号为1F处为LPC控制器:

image-20210415162422534

读取LPC控制器的数据,偏移为0xDC处为BIOS_CNTL寄存器的值:

python chipsec_util.py pci dump 0 0x1f 0
image-20210415160223419

python chipsec_main.py -m common.bios_wp命令读取出来的BIOS_CNTL寄存器值实际上也是0x2A:

image-20210415162946593

chipsec.utilcmd.mmio_cmd模块访问SPI寄存器:

>>> chipsec_util mmio list
>>> chipsec_util mmio dump <MMIO_BAR_name>
>>> chipsec_util mmio read <MMIO_BAR_name> <offset> <width>
>>> chipsec_util mmio write <MMIO_BAR_name> <offset> <width> <value>python chipsec_util.py mmio dump SPIBAR #dump SPIBAR基址及对应偏移寄存器的值
image-20210416111511524

对应0x4偏移处为HSFS寄存器,其值为0xE008,用python chipsec_main.py -m chipsec.modules.common.spi_lock检查HSFS寄存器各位的值:

image-20210416113818368