小華的部落格: 2025

搜尋此網誌

網頁

星期日, 5月 25, 2025

Dump TCG log

Dump TCG log

    一個簡易的方式在UEFI Shell底下,先找到TPM2 的ACPI Table ,再從Table中找到紀錄TCG log的記憶體位址(一般UEFI PCD目前都是設定0x10000 大小,但進入OS後,OS有可能會加大這塊的內容) ,然後分析TCG log中的每一筆紀錄的Event , 然後重新計算Digest ,這樣子可以呈現出BIOS交給OS前,TCG log中所記錄的TPM PCR可能的值會是甚麼. 底下是部分實作的程式碼,幫助大家了解流程. 


        // Loop through all ACPI tables to find TPM2

        Status = GetAcpiTableBySignature(SIGNATURE_32('T','P','M','2'), &Table);

        Tpm2Table =  (EFI_TPM2_ACPI_TABLE_V4 *) Table;


        if (Tpm2Table == NULL) {

            Print(L"[Fail] TPM2 ACPI Table not found\n");

            return EFI_NOT_FOUND;

        }


        Print(L"TPM2 ACPI Table found\n");

        Print(L"Event Log Start Address: 0x%lx\n", Tpm2Table->Lasa);

        Print(L"Event Log Length: %u bytes\n", Tpm2Table->Laml);

        Print(L"******** TCG Log Dump ******** \n");

        PrintHexAndAscii((UINT8 *) Tpm2Table->Lasa, (UINTN) Tpm2Table->Laml); // Print partial event data  


        Print(L"******** TCG Events ******** \n");


        // 儲存 PCR0 到 PCR23 的最後 Digest

        PCRDigest PcrDigests[PCR_COUNT];

        ZeroMem(PcrDigests, sizeof(PCRDigest) * PCR_COUNT);


        MY_ACPI_TCG2_EVENT *TcgEvent = (MY_ACPI_TCG2_EVENT *)(UINTN)Tpm2Table->Lasa;

        UINT8 *LogEnd = (UINT8 *)(UINTN)(Tpm2Table->Lasa + Tpm2Table->Laml);

        UINTN EventIndex = 0;


        while ((UINT8 *)TcgEvent < LogEnd) {

            UINT8 *EventStart = (UINT8 *)TcgEvent;

               //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;
}

星期二, 1月 21, 2025

祝大家蛇年新年快樂

 Penny 說我很久沒更新了,所以來更新一下~