一個簡易的方式在UEFI Shell底下,先找到TPM2 的ACPI Table ,再從Table中找到紀錄TCG log的記憶體位址(一般UEFI PCD目前都是設定0x10000 大小,但進入OS後,OS有可能會加大這塊的內容) ,然後分析TCG log中的每一筆紀錄的Event , 然後重新計算Digest ,這樣子可以呈現出BIOS交給OS前,TCG log中所記錄的TPM PCR可能的值會是甚麼. 底下是部分實作的程式碼,幫助大家了解流程.
PrintHexAndAscii((UINT8 *) Tpm2Table->Lasa, (UINTN) Tpm2Table->Laml); // Print partial event data
MY_ACPI_TCG2_EVENT *TcgEvent = (MY_ACPI_TCG2_EVENT *)(UINTN)Tpm2Table->Lasa;
//TODO: 1. 處理EV_NO_ACTION
2.CalculateDigest (CombinedData, CombinedDataSize, PcrDigests[PcrIndex].Digest, AlgId);
...
// 1.找到事件起始位置。
// 2.依序讀出:
// PCRIndex(4 bytes)
// EventType(4 bytes)
// DigestCount(4 bytes)
// 3.每個 Digest 結構:
// AlgorithmId(2 bytes)
// Digest(對 SHA128 而言,是 20 bytes, SHA256 而言,是 32 bytes..etc)
// 3.接著是 EventDataSize(4 bytes)
// 4.再來是 EventData
#pragma pack(1)
typedef struct {
UINT32 PCRIndex; // 4 bytes
UINT32 EventType; // 4 bytes
UINT32 DigestCount; // 4 bytes
// 之後是 DigestList 和 EventData
UINT8 Event[]; // 可變長度,儲存 Digest 和 EventData (參考前面說明)
} MY_ACPI_TCG2_EVENT;
#pragma pack()
#define PCR_COUNT 24 // PCR0 到 PCR23,共 24 個 PCR
// 儲存每個 PCR 的最後一筆 Digest
typedef struct {
UINT8 Digest[64]; // 假設 Digest 最長為 64 字節 (可以根據實際需要調整)
UINTN DigestSize; // Digest 大小
} PCRDigest;
UINTN
GetHashSizeFromAlgo(
IN TPMI_ALG_HASH HashAlgo
)
{
switch (HashAlgo) {
case TPM_ALG_SHA1: return 20;
case TPM_ALG_SHA256: return 32;
case TPM_ALG_SHA384: return 48;
case TPM_ALG_SHA512: return 64;
case TPM_ALG_SM3_256:return 32;
default: return 0;
}
}
// Hex + ASCII Dump
VOID
PrintHexAndAscii(IN UINT8 *Data, IN UINTN Length)
{
for (UINTN i = 0; i < Length; i += 16) {
Print(L"%08x: ", i);
// Print hex
for (UINTN j = 0; j < 16; j++) {
if ((i + j) < Length) {
Print(L"%02x ", Data[i + j]);
} else {
Print(L" ");
}
}
Print(L" ");
// Print ASCII
for (UINTN j = 0; j < 16; j++) {
if ((i + j) < Length) {
CHAR8 c = (CHAR8)Data[i + j];
if (c >= 0x20 && c <= 0x7E) {
Print(L"%c", c);
} else {
Print(L".");
}
}
}
Print(L"\n");
}
}
// Covert to EventType string
CONST CHAR16* GetEventTypeString(UINT32 EventType)
{
// Standard event types
switch (EventType) {
case EV_PREBOOT_CERT: return L"EV_PREBOOT_CERT(0x00000000)";
case EV_POST_CODE: return L"EV_POST_CODE(0x00000001)";
case EV_NO_ACTION: return L"EV_NO_ACTION(0x00000003)";
case EV_SEPARATOR: return L"EV_SEPARATOR(0x00000004)";
case EV_ACTION: return L"EV_ACTION(0x00000005)";
case EV_EVENT_TAG: return L"EV_EVENT_TAG(0x00000006)";
case EV_S_CRTM_CONTENTS: return L"EV_S_CRTM_CONTENTS(0x00000007)";
case EV_S_CRTM_VERSION: return L"EV_S_CRTM_VERSION(0x00000008)";
case EV_CPU_MICROCODE: return L"EV_CPU_MICROCODE(0x00000009)";
case EV_PLATFORM_CONFIG_FLAGS: return L"EV_PLATFORM_CONFIG_FLAGS(0x0000000A)";
case EV_TABLE_OF_DEVICES: return L"EV_TABLE_OF_DEVICES(0x0000000B)";
case EV_COMPACT_HASH: return L"EV_COMPACT_HASH(0x0000000C)";
case EV_NONHOST_CODE: return L"EV_NONHOST_CODE(0x0000000F)";
case EV_NONHOST_CONFIG: return L"EV_NONHOST_CONFIG(0x00000010)";
case EV_NONHOST_INFO: return L"EV_NONHOST_INFO(0x00000011)";
case EV_OMIT_BOOT_DEVICE_EVENTS: return L"EV_OMIT_BOOT_DEVICE_EVENTS(0x00000012)";
// EFI specific event types (0x80000000 and above)
case EV_EFI_VARIABLE_DRIVER_CONFIG: return L"EV_EFI_VARIABLE_DRIVER_CONFIG(0x80000001)";
case EV_EFI_VARIABLE_BOOT: return L"EV_EFI_VARIABLE_BOOT(0x80000002)";
case EV_EFI_BOOT_SERVICES_APPLICATION: return L"EV_EFI_BOOT_SERVICES_APPLICATION(0x80000003)";
case EV_EFI_BOOT_SERVICES_DRIVER: return L"EV_EFI_BOOT_SERVICES_DRIVER(0x80000004)";
case EV_EFI_RUNTIME_SERVICES_DRIVER: return L"EV_EFI_RUNTIME_SERVICES_DRIVER(0x80000005)";
case EV_EFI_GPT_EVENT: return L"EV_EFI_GPT_EVENT(0x80000006)";
case EV_EFI_ACTION: return L"EV_EFI_ACTION(0x80000007)";
case EV_EFI_PLATFORM_FIRMWARE_BLOB: return L"EV_EFI_PLATFORM_FIRMWARE_BLOB(0x80000008)";
case EV_EFI_HANDOFF_TABLES: return L"EV_EFI_HANDOFF_TABLES(0x80000009)";
case EV_EFI_PLATFORM_FIRMWARE_BLOB2: return L"EV_EFI_PLATFORM_FIRMWARE_BLOB2(0x8000000A)";
case EV_EFI_HANDOFF_TABLES2: return L"EV_EFI_HANDOFF_TABLES2(0x8000000B)";
case EV_EFI_HCRTM_EVENT: return L"EV_EFI_HCRTM_EVENT(0x80000010)";
case EV_EFI_VARIABLE_AUTHORITY: return L"EV_EFI_VARIABLE_AUTHORITY(0x800000E0)";
case EV_EFI_SPDM_FIRMWARE_BLOB: return L"EV_EFI_SPDM_FIRMWARE_BLOB(0x800000E1)";
case EV_EFI_SPDM_FIRMWARE_CONFIG: return L"EV_EFI_SPDM_FIRMWARE_CONFIG(0x800000E2)";
// Add
//case EV_EFI_SPDM_DEVICE_BLOB: return L"EV_EFI_SPDM_DEVICE_BLOB(0x800000E1)"; // 和 EV_EFI_SPDM_FIRMWARE_BLOB 相同
//case EV_EFI_SPDM_DEVICE_CONFIG: return L"EV_EFI_SPDM_DEVICE_CONFIG(0x800000E2)"; // 和 EV_EFI_SPDM_FIRMWARE_CONFIG 相同
default: return L"UNKNOWN(0x%08x)"; // Unknown event type
}
}
#pragma pack(1)
typedef struct { // Refer to Tcg2Acpi.c
EFI_ACPI_DESCRIPTION_HEADER Header; // "TPM2"
// Flags field is replaced in version 4 and above
// BIT0~15: PlatformClass This field is only valid for version 4 and above
// BIT16~31: Reserved
UINT32 Flags;
UINT64 AddressOfControlArea;
UINT32 StartMethod;
UINT8 PlatformSpecificParameters[12]; // size up to 12
UINT32 Laml; // Optional
UINT64 Lasa; // Optional
} EFI_TPM2_ACPI_TABLE_V4;
#pragma pack()
// Signature macro
//#define SIGNATURE_32(A,B,C,D) ((UINT32)(A) | ((UINT32)(B)<<8) | ((UINT32)(C)<<16) | ((UINT32)(D)<<24))
EFI_STATUS
GetAcpiTableBySignature (
IN UINT32 Signature,
OUT EFI_ACPI_DESCRIPTION_HEADER **OutTable
)
{
EFI_CONFIGURATION_TABLE *ConfigTable = gST->ConfigurationTable;
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp = NULL;
EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
UINT64 *EntryPtr;
UINTN EntryCount;
// Step 1: Find RSDP
for (UINTN i = 0; i < gST->NumberOfTableEntries; i++) {
if (CompareGuid(&ConfigTable[i].VendorGuid, &gEfiAcpi20TableGuid)) {
Rsdp = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)ConfigTable[i].VendorTable;
break;
}
}
if (Rsdp == NULL) {
Print(L"[Error] ACPI 2.0 RSDP not found\n");
return EFI_NOT_FOUND;
}
// Step 2: Get XSDT
Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->XsdtAddress);
if (Xsdt->Signature != EFI_ACPI_6_3_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
Print(L"[Error] XSDT Signature mismatch (found: %08X)\n", Xsdt->Signature);
return EFI_NOT_FOUND;
}
// Step 3: Traverse XSDT entries
EntryCount = (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
EntryPtr = (UINT64 *)(Xsdt + 1); // entries come right after the header
for (UINTN i = 0; i < EntryCount; i++) {
EFI_ACPI_DESCRIPTION_HEADER *Hdr = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)EntryPtr[i];
if (Hdr->Signature == Signature) {
*OutTable = Hdr;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
EFI_STATUS
EFIAPI
CalculateDigest (
IN UINT8 *Data,
IN UINTN DataSize,
OUT UINT8 *Digest,
IN UINT16 AlgId
)
{
BOOLEAN Status;
if (AlgId == TPM_ALG_SHA256) {
Status = Sha256HashAll (Data, DataSize, Digest);
} else {
// 支援其他演算法
return EFI_UNSUPPORTED;
}
if (!Status) {
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
沒有留言:
張貼留言