1793 lines
93 KiB
PowerShell
1793 lines
93 KiB
PowerShell
# APIs required to interface with the TPM service
|
|
Add-Type -ErrorAction Stop -TypeDefinition @'
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace TPMBaseServices {
|
|
public enum TPM_VERSION {
|
|
TPM_VERSION_UNKNOWN = 0,
|
|
TPM_VERSION_12,
|
|
TPM_VERSION_20
|
|
}
|
|
|
|
public enum TPM_IFTYPE : uint {
|
|
TPM_IFTYPE_UNKNOWN = 0,
|
|
TPM_IFTYPE_1,
|
|
TPM_IFTYPE_TRUSTZONE,
|
|
TPM_IFTYPE_HW,
|
|
TPM_IFTYPE_EMULATOR,
|
|
TPM_IFTYPE_SPB
|
|
}
|
|
|
|
public enum TBS_TCGLOG : uint {
|
|
TBS_TCGLOG_SRTM_CURRENT = 0,
|
|
TBS_TCGLOG_DRTM_CURRENT,
|
|
TBS_TCGLOG_SRTM_BOOT,
|
|
TBS_TCGLOG_SRTM_RESUME
|
|
}
|
|
|
|
public struct TPM_DEVICE_INFO {
|
|
public uint structVersion;
|
|
public TPM_VERSION tpmVersion;
|
|
public TPM_IFTYPE tpmInterfaceType;
|
|
public uint tpmImpRevision;
|
|
}
|
|
|
|
public class UnsafeNativeMethods {
|
|
[DllImport("tbs.dll")]
|
|
public static extern uint Tbsi_GetDeviceInfo(ulong Size, out TPM_DEVICE_INFO Info);
|
|
|
|
// This API is much more flexible than Tbsi_Get_TCG_Log because you don't need to get a TBS context.
|
|
[DllImport("tbs.dll")]
|
|
public static extern uint Tbsi_Get_TCG_Log_Ex(TBS_TCGLOG logType, IntPtr pOutputBuf, ref uint OutputBufLen);
|
|
}
|
|
}
|
|
'@
|
|
|
|
#region: enums required for multiple functions
|
|
|
|
# Used to display friendly error messages if a TBS function fails.
|
|
$Script:TBSReturnCodes = @{
|
|
([UInt32] 2150121473) = 'An internal software error occurred.'
|
|
([UInt32] 2150121474) = 'One or more parameter values are not valid.'
|
|
([UInt32] 2150121475) = 'A specified output pointer is bad.'
|
|
([UInt32] 2150121476) = 'The specified context handle does not refer to a valid context.'
|
|
([UInt32] 2150121477) = 'The specified output buffer is too small.'
|
|
([UInt32] 2150121478) = 'An error occurred while communicating with the TPM.'
|
|
([UInt32] 2150121479) = 'A context parameter that is not valid was passed when attempting to create a TBS context.'
|
|
([UInt32] 2150121480) = 'The TBS service is not running and could not be started.'
|
|
([UInt32] 2150121481) = 'A new context could not be created because there are too many open contexts.'
|
|
([UInt32] 2150121482) = 'A new virtual resource could not be created because there are too many open virtual resources.'
|
|
([UInt32] 2150121483) = 'The TBS service has been started but is not yet running.'
|
|
([UInt32] 2150121484) = 'The physical presence interface is not supported.'
|
|
([UInt32] 2150121485) = 'The command was canceled.'
|
|
([UInt32] 2150121486) = 'The input or output buffer is too large.'
|
|
([UInt32] 2150121487) = 'A compatible Trusted Platform Module (TPM) Security Device cannot be found on this computer.'
|
|
([UInt32] 2150121488) = 'The TBS service has been disabled.'
|
|
([UInt32] 2150121489) = 'The TBS event log is not available.'
|
|
([UInt32] 2150121490) = 'The caller does not have the appropriate rights to perform the requested operation.'
|
|
([UInt32] 2150121491) = 'The TPM provisioning action is not allowed by the specified flags.'
|
|
([UInt32] 2150121492) = 'The Physical Presence Interface of this firmware does not support the requested method.'
|
|
([UInt32] 2150121493) = 'The requested TPM OwnerAuth value was not found.'
|
|
# 2150121493 may be a typo in the docs for the below return code. Need to reverse tbs.dll to confirm
|
|
([UInt32] 2150121494) = "The TPM provisioning did not complete. For more information on completing the provisioning, call the Win32_Tpm WMI method for provisioning the TPM ('Provision') and check the returned information."
|
|
}
|
|
|
|
# Obtained from wbcl.h in the WDK
|
|
# These refer to Windows-specific data types for PCR 12-14 and -1 (TrustPoint)
|
|
$Script:SIPAEventMapping = @{
|
|
# SIPAEVENTTYPE_CONTAINER
|
|
# All of these types will contain embedded event data
|
|
0x40010001 = 'TrustBoundary' # SIPAEVENT_TRUSTBOUNDARY
|
|
0x40010002 = 'ELAMAggregation' # SIPAEVENT_ELAM_AGGREGATION
|
|
0x40010003 = 'LoadedModuleAggregation' # SIPAEVENT_LOADEDMODULE_AGGREGATION
|
|
0xC0010004 = 'TrustpointAggregation' # SIPAEVENT_TRUSTPOINT_AGGREGATION
|
|
0x40010005 = 'KSRAggregation' # SIPAEVENT_KSR_AGGREGATION
|
|
0x40010006 = 'KSRSignedMeasurementAggregation' # SIPAEVENT_KSR_SIGNED_MEASUREMENT_AGGREGATION
|
|
|
|
# SIPAEVENTTYPE_INFORMATION
|
|
0x00020001 = 'Information' # SIPAEVENT_INFORMATION
|
|
0x00020002 = 'BootCounter' # SIPAEVENT_BOOTCOUNTER
|
|
0x00020003 = 'TransferControl' # SIPAEVENT_TRANSFER_CONTROL
|
|
0x00020004 = 'ApplicationReturn' # SIPAEVENT_APPLICATION_RETURN
|
|
0x00020005 = 'BitlockerUnlock' # SIPAEVENT_BITLOCKER_UNLOCK
|
|
0x00020006 = 'EventCounter' # SIPAEVENT_EVENTCOUNTER
|
|
0x00020007 = 'CounterID' # SIPAEVENT_COUNTERID
|
|
0x00020008 = 'MORBitNotCancelable' # SIPAEVENT_MORBIT_NOT_CANCELABLE
|
|
0x00020009 = 'ApplicationSVN' # SIPAEVENT_APPLICATION_SVN
|
|
0x0002000A = 'SVNChainStatus' # SIPAEVENT_SVN_CHAIN_STATUS
|
|
0x0002000B = 'MORBitAPIStatus' # SIPAEVENT_MORBIT_API_STATUS
|
|
|
|
# SIPAEVENTTYPE_PREOSPARAMETER
|
|
0x00040001 = 'BootDebugging' # SIPAEVENT_BOOTDEBUGGING
|
|
0x00040002 = 'BootRevocationList' # SIPAEVENT_BOOT_REVOCATION_LIST
|
|
|
|
# SIPAEVENTTYPE_OSPARAMETER
|
|
0x00050001 = 'OSKernelDebug' # SIPAEVENT_OSKERNELDEBUG
|
|
0x00050002 = 'CodeIntegrity' # SIPAEVENT_CODEINTEGRITY
|
|
0x00050003 = 'TestSigning' # SIPAEVENT_TESTSIGNING
|
|
0x00050004 = 'DataExecutionPrevention' # SIPAEVENT_DATAEXECUTIONPREVENTION
|
|
0x00050005 = 'SafeMode' # SIPAEVENT_SAFEMODE
|
|
0x00050006 = 'WinPE' # SIPAEVENT_WINPE
|
|
0x00050007 = 'PhysicalAddressExtension' # SIPAEVENT_PHYSICALADDRESSEXTENSION
|
|
0x00050008 = 'OSDevice' # SIPAEVENT_OSDEVICE
|
|
0x00050009 = 'SystemRoot' # SIPAEVENT_SYSTEMROOT
|
|
0x0005000A = 'HypervisorLaunchType' # SIPAEVENT_HYPERVISOR_LAUNCH_TYPE
|
|
0x0005000B = 'HypervisorPath' # SIPAEVENT_HYPERVISOR_PATH
|
|
0x0005000C = 'HypervisorIOMMUPolicy' # SIPAEVENT_HYPERVISOR_IOMMU_POLICY
|
|
0x0005000D = 'HypervisorDebug' # SIPAEVENT_HYPERVISOR_DEBUG
|
|
0x0005000E = 'DriverLoadPolicy' # SIPAEVENT_DRIVER_LOAD_POLICY
|
|
0x0005000F = 'SIPolicy' # SIPAEVENT_SI_POLICY
|
|
0x00050010 = 'HypervisorMMIONXPolicy' # SIPAEVENT_HYPERVISOR_MMIO_NX_POLICY
|
|
0x00050011 = 'HypervisorMSRFilterPolicy' # SIPAEVENT_HYPERVISOR_MSR_FILTER_POLICY
|
|
0x00050012 = 'VSMLaunchType' # SIPAEVENT_VSM_LAUNCH_TYPE
|
|
0x00050013 = 'OSRevocationList' # SIPAEVENT_OS_REVOCATION_LIST
|
|
0x00050020 = 'VSMIDKInfo' # SIPAEVENT_VSM_IDK_INFO
|
|
0x00050021 = 'FlightSigning' # SIPAEVENT_FLIGHTSIGNING
|
|
0x00050022 = 'PagefileEncryptionEnabled' # SIPAEVENT_PAGEFILE_ENCRYPTION_ENABLED
|
|
0x00050023 = 'VSMIDKSInfo' # SIPAEVENT_VSM_IDKS_INFO
|
|
0x00050024 = 'HibernationDisabled' # SIPAEVENT_HIBERNATION_DISABLED
|
|
0x00050025 = 'DumpsDisabled' # SIPAEVENT_DUMPS_DISABLED
|
|
0x00050026 = 'DumpEncryptionEnabled' # SIPAEVENT_DUMP_ENCRYPTION_ENABLED
|
|
0x00050027 = 'DumpEncryptionKeyDigest' # SIPAEVENT_DUMP_ENCRYPTION_KEY_DIGEST
|
|
0x00050028 = 'LSAISOConfig' # SIPAEVENT_LSAISO_CONFIG
|
|
|
|
# SIPAEVENTTYPE_AUTHORITY
|
|
0x00060001 = 'NoAuthority' # SIPAEVENT_NOAUTHORITY
|
|
0x00060002 = 'AuthorityPubKey' # SIPAEVENT_AUTHORITYPUBKEY
|
|
|
|
# SIPAEVENTTYPE_LOADEDIMAGE
|
|
0x00070001 = 'FilePath' # SIPAEVENT_FILEPATH
|
|
0x00070002 = 'ImageSize' # SIPAEVENT_IMAGESIZE
|
|
0x00070003 = 'HashAlgorithmID' # SIPAEVENT_HASHALGORITHMID
|
|
0x00070004 = 'AuthenticodeHash' # SIPAEVENT_AUTHENTICODEHASH
|
|
0x00070005 = 'AuthorityIssuer' # SIPAEVENT_AUTHORITYISSUER
|
|
0x00070006 = 'AuthoritySerial' # SIPAEVENT_AUTHORITYSERIAL
|
|
0x00070007 = 'ImageBase' # SIPAEVENT_IMAGEBASE
|
|
0x00070008 = 'AuthorityPublisher' # SIPAEVENT_AUTHORITYPUBLISHER
|
|
0x00070009 = 'AuthoritySHA1Thumbprint' # SIPAEVENT_AUTHORITYSHA1THUMBPRINT
|
|
0x0007000A = 'ImageValidated' # SIPAEVENT_IMAGEVALIDATED
|
|
0x0007000B = 'ModuleSVN' # SIPAEVENT_MODULE_SVN
|
|
|
|
# SIPAEVENTTYPE_TRUSTPOINT
|
|
0x80080001 = 'Quote' # SIPAEVENT_QUOTE
|
|
0x80080002 = 'QuoteSignature' # SIPAEVENT_QUOTESIGNATURE
|
|
0x80080003 = 'AIKID' # SIPAEVENT_AIKID
|
|
0x80080004 = 'AIKPubDigest' # SIPAEVENT_AIKPUBDIGEST
|
|
|
|
# SIPAEVENTTYPE_ELAM
|
|
0x00090001 = 'ELAMKeyname' # SIPAEVENT_ELAM_KEYNAME
|
|
0x00090002 = 'ELAMConfiguration' # SIPAEVENT_ELAM_CONFIGURATION
|
|
0x00090003 = 'ELAMPolicy' # SIPAEVENT_ELAM_POLICY
|
|
0x00090004 = 'ELAMMeasured' # SIPAEVENT_ELAM_MEASURED
|
|
|
|
# SIPAEVENTTYPE_VBS
|
|
0x000A0001 = 'VBSVSMRequired' # SIPAEVENT_VBS_VSM_REQUIRED
|
|
0x000A0002 = 'VBSSecurebootRequired' # SIPAEVENT_VBS_SECUREBOOT_REQUIRED
|
|
0x000A0003 = 'VBSIOMMURequired' # SIPAEVENT_VBS_IOMMU_REQUIRED
|
|
0x000A0004 = 'VBSNXRequired' # SIPAEVENT_VBS_MMIO_NX_REQUIRED
|
|
0x000A0005 = 'VBSMSRFilteringRequired' # SIPAEVENT_VBS_MSR_FILTERING_REQUIRED
|
|
0x000A0006 = 'VBSMandatoryEnforcement' # SIPAEVENT_VBS_MANDATORY_ENFORCEMENT
|
|
0x000A0007 = 'VBSHVCIPolicy' # SIPAEVENT_VBS_HVCI_POLICY
|
|
0x000A0008 = 'VBSMicrosoftBootChainRequired' # SIPAEVENT_VBS_MICROSOFT_BOOT_CHAIN_REQUIRED
|
|
|
|
# SIPAEVENTTYPE_KSR
|
|
0x000B0001 = 'KSRSignature' # SIPAEVENT_KSR_SIGNATURE
|
|
}
|
|
|
|
$Script:DigestAlgorithmMapping = @{
|
|
[UInt16] 0 = 'TPM_ALG_ERROR'
|
|
[UInt16] 1 = 'TPM_ALG_RSA'
|
|
[UInt16] 4 = 'TPM_ALG_SHA1'
|
|
[UInt16] 5 = 'TPM_ALG_HMAC'
|
|
[UInt16] 6 = 'TPM_ALG_AES'
|
|
[UInt16] 7 = 'TPM_ALG_MGF1'
|
|
[UInt16] 8 = 'TPM_ALG_KEYEDHASH'
|
|
[UInt16] 10 = 'TPM_ALG_XOR'
|
|
[UInt16] 11 = 'TPM_ALG_SHA256'
|
|
[UInt16] 12 = 'TPM_ALG_SHA384'
|
|
[UInt16] 13 = 'TPM_ALG_SHA512'
|
|
[UInt16] 16 = 'TPM_ALG_NULL'
|
|
[UInt16] 18 = 'TPM_ALG_SM3_256'
|
|
}
|
|
|
|
$Script:HashAlgorithmMapping = @{
|
|
0x00008001 = 'CALG_MD2'
|
|
0x00008002 = 'CALG_MD4'
|
|
0x00008003 = 'CALG_MD5'
|
|
0x00008004 = 'CALG_SHA1'
|
|
0x0000800C = 'CALG_SHA_256'
|
|
0x0000800D = 'CALG_SHA_384'
|
|
0x0000800E = 'CALG_SHA_512'
|
|
}
|
|
|
|
$Script:OSDeviceMapping = @{
|
|
0x00000000 = 'UNKNOWN'
|
|
0x00010001 = 'BLOCKIO_HARDDISK'
|
|
0x00010002 = 'BLOCKIO_REMOVABLEDISK'
|
|
0x00010003 = 'BLOCKIO_CDROM'
|
|
0x00010004 = 'BLOCKIO_PARTITION'
|
|
0x00010005 = 'BLOCKIO_FILE'
|
|
0x00010006 = 'BLOCKIO_RAMDISK'
|
|
0x00010007 = 'BLOCKIO_VIRTUALHARDDISK'
|
|
0x00020000 = 'SERIAL'
|
|
0x00030000 = 'UDP'
|
|
}
|
|
|
|
$Script:EventTypeMapping = @{
|
|
[UInt32] 0 = 'EV_PREBOOT_CERT' # The event field contains certificates such as the Validation Certificates.
|
|
[UInt32] 1 = 'EV_POST_CODE' # The digest field contains the SHA-1 hash of the POST portion of the BIOS. The event field SHOULD NOT contain the actual POST code but MAY contain informative information about the POST code.
|
|
[UInt32] 2 = 'EV_UNUSED' # The event type was never used and is considered reserved.
|
|
[UInt32] 3 = 'EV_NO_ACTION' # The event field contains informative data that was not extended into any PCR. The fields: pcrIndex and digest MUST contain the value 0.
|
|
[UInt32] 4 = 'EV_SEPARATOR' # Delimits actions taken during the Pre-Operating System State and the Operating System Present State
|
|
# This will often be "WBCL" - Windows Boot Configuration Log (Microsoft's name for the TCG log)
|
|
[UInt32] 5 = 'EV_ACTION' # A specific action measured as a string defined in Section 10.4.3.
|
|
[UInt32] 6 = 'EV_EVENT_TAG' # The event field contains the structure defined in Section 10.4.2.1.
|
|
[UInt32] 7 = 'EV_S_CRTM_CONTENTS' # The digest field contains is the SHA-1 hash of the SCRTM. The event field SHOULD NOT contain the actual S-CRTM code but MAY contain informative information about the S-CRTM code.
|
|
[UInt32] 8 = 'EV_S_CRTM_VERSION' # The event field contains the version string of the SCRTM.
|
|
[UInt32] 9 = 'EV_CPU_MICROCODE' # The event field contains a descriptor of the microcode but the digest field contains the actual hash of the microcode patch that was applied.
|
|
[UInt32] 10 = 'EV_PLATFORM_CONFIG_FLAGS' # The format and contents to be defined by the platform manufacturer. Examples of information contained in this event type are the capabilities of the platform?s measurements, whether the Owner has disabled measurements, etc.
|
|
[UInt32] 11 = 'EV_TABLE_OF_DEVICES' # The event field contains the Platform manufacturerprovided Table of Devices or other Platform manufacturer-defined information. The Platform manufacturer defines the content and format of the Table of Devices. The Host Platform Certificate may provide a reference to the meaning of these structures and data. This structure is measured into PCR[1] using the following.
|
|
[UInt32] 12 = 'EV_COMPACT_HASH' # This event is entered using the TCG_CompactHashLogExtendEvent. While it can be used by any function, it is typically used by IPL Code to measure events. The contents of the event field is specified by the caller but is not part of the measurement; rather, it is just informative.
|
|
[UInt32] 13 = 'EV_IPL' # The digest field contains the SHA-1 hash of the IPL Code. The event field SHOULD NOT contain the actual IPL Code but MAY contain informative information about the IPL Code. Note: The digest may not cover the entire area hosting the IPL Image, but only the portion that contains the IPL Code. For example, if the IPL Image is a disk drive MBR, this MUST NOT include the portion of the MBR that contains the disk geometry.
|
|
[UInt32] 14 = 'EV_IPL_PARTITION_DATA' # The data and partition portion of the IPL Image.
|
|
[UInt32] 15 = 'EV_NONHOST_CODE' # The executable component of any Non-host Platform. The contents of the event field are defined by the manufacturer of the Non-host Platform.
|
|
[UInt32] 16 = 'EV-NONHOST_CONFIG' # The parameters associated with a Non-host Platform. The contents of the event field are defined by the manufacturer of the Non-host Platform.
|
|
[UInt32] 17 = 'EV_NONHOST_INFO' # The event is information about the presence of a Non-host Platform. This information could be, but is not required to be, information such as the Non-host Platform manufacturer, model, type, version, etc. The information and formatting is to be determined by the BIOS.
|
|
[UInt32] (2147483648 + 1) = 'EV_EFI_VARIABLE_DRIVER_CONFIG' # EFI variables, either defined in the EFI spec or private, that typically do not change from boot-to-boot and contain system configuration information.
|
|
[UInt32] (2147483648 + 2) = 'EV_EFI_VARIABLE_BOOT' # This event is used to measure boot variables. The event field MUST contain a UEFI_VARIABLE_DATA structure
|
|
[UInt32] (2147483648 + 3) = 'EV_EFI_BOOT_SERVICES_APPLICATION' # EFI application (e.g. EFI OSLoader)
|
|
[UInt32] (2147483648 + 4) = 'EV_EFI_BOOT_SERVICES_DRIVER' # EFI Boot Services Drivers from adapter or loaded by driver in adapter.
|
|
[UInt32] (2147483648 + 5) = 'EV_EFI_RUNTIME_SERVICES_DRIVER' # EFI Runtime drivers from adapter or loaded by driver in adapter.
|
|
[UInt32] (2147483648 + 6) = 'EV_EFI_GPT_EVENT' # GPT Table
|
|
[UInt32] (2147483648 + 7) = 'EV_EFI_ACTION' # Measurement of a specific string value that indicates a specific event occurred during the platform or OS boot process.
|
|
[UInt32] (2147483648 + 8) = 'EV_EFI_PLATFORM_FIRMWARE_BLOB' # The event MUST contain a UEFI_PLATFORM_FIRMWARE_BLOB structure
|
|
[UInt32] (2147483648 + 9) = 'EV_EFI_HANDOFF_TABLES' # Describes the measurement of industry-standard tables and data structure regions.
|
|
[UInt32] (2147483648 + 0x0A) = 'EV_EFI_HCRTM_EVENT' # This event is used to record an event for the digest extended to PCR[0] as part of an H-CRTM event.
|
|
[UInt32] (2147483648 + 0xE0) = 'EV_EFI_VARIABLE_AUTHORITY' # Documented here: https://docs.microsoft.com/en-us/windows-hardware/test/hlk/testref/trusted-execution-environment-efi-protocol
|
|
}
|
|
|
|
$Script:DigestSizeMapping = @{
|
|
'TPM_ALG_SHA1' = 20
|
|
'TPM_ALG_SHA256' = 32
|
|
'TPM_ALG_SHA384' = 48
|
|
'TPM_ALG_SHA512' = 64
|
|
'TPM_ALG_SM3_256' = 32
|
|
}
|
|
|
|
# To-do: expand out the device subtype parsers
|
|
$Script:DevicePathTypeMapping = @{
|
|
[Byte] 1 = 'HARDWARE_DEVICE_PATH' # Hardware Device Path
|
|
[Byte] 2 = 'ACPI_DEVICE_PATH' # ACPI Device Path
|
|
[Byte] 3 = 'MESSAGING_DEVICE_PATH'# Messaging Device Path
|
|
[Byte] 4 = 'MEDIA_DEVICE_PATH' # Media Device Path
|
|
[Byte] 5 = 'BBS_DEVICE_PATH' # BIOS Boot Specification Device Path
|
|
[Byte] 0x7F = 'END_DEVICE_PATH_TYPE'
|
|
}
|
|
|
|
$Script:MediaDeviceSubTypeMapping = @{
|
|
[Byte] 1 = 'MEDIA_HARDDRIVE_DP' # Corresponding struct: HARDDRIVE_DEVICE_PATH
|
|
[Byte] 2 = 'MEDIA_CDROM_DP' # Corresponding struct: CDROM_DEVICE_PATH
|
|
[Byte] 3 = 'MEDIA_VENDOR_DP' # Corresponding struct: ?
|
|
[Byte] 4 = 'MEDIA_FILEPATH_DP' # Corresponding struct: FILEPATH_DEVICE_PATH
|
|
[Byte] 5 = 'MEDIA_PROTOCOL_DP' # Corresponding struct: MEDIA_PROTOCOL_DEVICE_PATH
|
|
[Byte] 6 = 'MEDIA_PIWG_FW_FILE_DP' # Corresponding struct: MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
|
|
[Byte] 7 = 'MEDIA_PIWG_FW_VOL_DP' # Corresponding struct: MEDIA_FW_VOL_DEVICE_PATH
|
|
[Byte] 8 = 'MEDIA_RELATIVE_OFFSET_RANGE_DP' # Corresponding struct: MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH
|
|
[Byte] 9 = 'MEDIA_RAM_DISK_DP' # Corresponding struct: MEDIA_RAM_DISK_DEVICE_PATH
|
|
}
|
|
|
|
$Script:ACPIDeviceSubTypeMapping = @{
|
|
[Byte] 1 = 'ACPI_DP' # Corresponding struct: ACPI_HID_DEVICE_PATH
|
|
[Byte] 2 = 'ACPI_EXTENDED_DP' # Corresponding struct: ACPI_EXTENDED_HID_DEVICE_PATH
|
|
[Byte] 3 = 'ACPI_ADR_DP' # Corresponding struct: ACPI_ADR_DEVICE_PATH
|
|
}
|
|
|
|
$Script:PartitionGUIDMapping = @{
|
|
'00000000-0000-0000-0000-000000000000' = 'PARTITION_ENTRY_UNUSED_GUID'
|
|
'ebd0a0a2-b9e5-4433-87c0-68b6b72699c7' = 'PARTITION_BASIC_DATA_GUID'
|
|
'c12a7328-f81f-11d2-ba4b-00a0c93ec93b' = 'PARTITION_SYSTEM_GUID'
|
|
'e3c9e316-0b5c-4db8-817d-f92df00215ae' = 'PARTITION_MSFT_RESERVED_GUID'
|
|
'5808c8aa-7e8f-42e0-85d2-e1e90434cfb3' = 'PARTITION_LDM_METADATA_GUID'
|
|
'af9b60a0-1431-4f62-bc68-3311714a69ad' = 'PARTITION_LDM_DATA_GUID'
|
|
'de94bba4-06d1-4d40-a16a-bfd50179d6ac' = 'PARTITION_MSFT_RECOVERY_GUID'
|
|
}
|
|
#endregion
|
|
|
|
# Helper function to retrieve SIPA events - i.e. Windows-specific PCR measurements
|
|
# I still have no clue what SIPA refers to. I use it because it's referenced all over wbcl.h.
|
|
# This function should not be exported.
|
|
function Get-SIPAEventData {
|
|
[CmdletBinding()]
|
|
param (
|
|
[Parameter(Mandatory)]
|
|
[Byte[]]
|
|
$SIPAEventBytes
|
|
)
|
|
|
|
# We need to identify container structures and recurse accordingly.
|
|
$ContainerType = 0x00010000
|
|
|
|
$EventMemoryStream = New-Object -TypeName IO.MemoryStream -ArgumentList @(,$SIPAEventBytes)
|
|
$EventBinaryReader = New-Object -TypeName IO.BinaryReader -ArgumentList $EventMemoryStream, ([Text.Encoding]::Unicode)
|
|
|
|
while (($EventBinaryReader.BaseStream.Position) -lt $SIPAEventBytes.Count) {
|
|
$SIPAEventTypeVal = $EventBinaryReader.ReadInt32()
|
|
$SIPAEventType = $SIPAEventMapping[$SIPAEventTypeVal]
|
|
|
|
$SIPAEventSize = $EventBinaryReader.ReadUInt32()
|
|
$EventBytes = $EventBinaryReader.ReadBytes($SIPAEventSize)
|
|
|
|
# All SIPA event types _should_ be defined but just in case one isn't, print it out in hex.
|
|
if (-not $SIPAEventType) { $SIPAEventType = "0x$($SIPAEventTypeVal.ToString('X8'))" }
|
|
|
|
if ((($SIPAEventTypeVal -band 0x000F0000) -eq $ContainerType) -or (($SIPAEventType -eq 'NoAuthority') -or ($SIPAEventType -eq 'AuthorityPubKey'))) {
|
|
switch ($SIPAEventType) {
|
|
'TrustBoundary' {
|
|
$PropertyTemplate = [Ordered] @{
|
|
Information = $null
|
|
PreOSParameters = $null
|
|
OSParameters = $null
|
|
LoadedModules = $null # This appears to be the only one that will have multiple entries
|
|
ELAM = $null
|
|
VBS = $null
|
|
}
|
|
|
|
$InformationTemplate = @{
|
|
Information = $null
|
|
BootCounter = $null
|
|
TransferControl = $null
|
|
ApplicationReturn = $null
|
|
BitlockerUnlock = $null
|
|
EventCounter = $null
|
|
CounterID = $null
|
|
MORBitNotCancelable = $null
|
|
ApplicationSVN = $null
|
|
SVNChainStatus = $null
|
|
MORBitAPIStatus = $null
|
|
}
|
|
|
|
$PreOSTemplate = @{
|
|
BootDebugging = $null
|
|
BootRevocationList = $null
|
|
}
|
|
|
|
$OSTemplate = @{
|
|
OSKernelDebug = $null
|
|
CodeIntegrity = $null
|
|
TestSigning = $null
|
|
DataExecutionPrevention = $null
|
|
SafeMode = $null
|
|
WinPE = $null
|
|
PhysicalAddressExtension = $null
|
|
OSDevice = $null
|
|
SystemRoot = $null
|
|
HypervisorLaunchType = $null
|
|
HypervisorPath = $null
|
|
HypervisorIOMMUPolicy = $null
|
|
HypervisorDebug = $null
|
|
DriverLoadPolicy = $null
|
|
SIPolicy = $null
|
|
HypervisorMMIONXPolicy = $null
|
|
HypervisorMSRFilterPolicy = $null
|
|
VSMLaunchType = $null
|
|
OSRevocationList = $null
|
|
VSMIDKInfo = $null
|
|
FlightSigning = $null
|
|
PagefileEncryptionEnabled = $null
|
|
VSMIDKSInfo = $null
|
|
HibernationDisabled = $null
|
|
DumpsDisabled = $null
|
|
DumpEncryptionEnabled = $null
|
|
DumpEncryptionKeyDigest = $null
|
|
LSAISOConfig = $null
|
|
}
|
|
|
|
$VBSTemplate = @{
|
|
VBSVSMRequired = $null
|
|
VBSSecurebootRequired = $null
|
|
VBSIOMMURequired = $null
|
|
VBSNXRequired = $null
|
|
VBSMSRFilteringRequired = $null
|
|
VBSMandatoryEnforcement = $null
|
|
VBSHVCIPolicy = $null
|
|
VBSMicrosoftBootChainRequired = $null
|
|
}
|
|
|
|
$ContainerEvents = Get-SIPAEventData -SIPAEventBytes $EventBytes
|
|
|
|
$LoadedModuleList = New-Object 'System.Collections.Generic.List[PSObject]'
|
|
$ELAMList = New-Object 'System.Collections.Generic.List[PSObject]'
|
|
|
|
$InformationTemplateSet = $False
|
|
$PreOSTemplateSet = $False
|
|
$OSTemplateSet = $False
|
|
$VBSTemplateSet = $False
|
|
|
|
foreach ($Container in $ContainerEvents) {
|
|
if ($Container.SIPAEventType -eq 'LoadedModuleAggregation') {
|
|
$LoadedModuleList.Add($Container.SIPAEventData)
|
|
} elseif ($Container.SIPAEventType -eq 'ELAMAggregation') {
|
|
$ELAMList.Add($Container.SIPAEventData)
|
|
} else {
|
|
switch ($Container.Category) {
|
|
'Information' {
|
|
$InformationTemplateSet = $True
|
|
$InformationTemplate[$Container.SIPAEventType] = $Container.SIPAEventData
|
|
}
|
|
|
|
'PreOSParameter' {
|
|
$PreOSTemplateSet = $True
|
|
$PreOSTemplate[$Container.SIPAEventType] = $Container.SIPAEventData
|
|
}
|
|
|
|
'OSParameter' {
|
|
$OSTemplateSet = $True
|
|
$OSTemplate[$Container.SIPAEventType] = $Container.SIPAEventData
|
|
}
|
|
|
|
'VBS' {
|
|
$VBSTemplateSet = $True
|
|
$VBSTemplate[$Container.SIPAEventType] = $Container.SIPAEventData
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$InformationObject = $null
|
|
$PreOSParameterObject = $null
|
|
$OSParameterObject = $null
|
|
$VBSObject = $null
|
|
|
|
if ($InformationTemplateSet) { $InformationObject = [PSCustomObject] $InformationTemplate }
|
|
if ($PreOSTemplateSet) { $PreOSParameterObject = [PSCustomObject] $PreOSTemplate }
|
|
if ($OSTemplateSet) { $OSParameterObject = [PSCustomObject] $OSTemplate }
|
|
if ($VBSTemplateSet) { $VBSObject = [PSCustomObject] $VBSTemplate }
|
|
|
|
$PropertyTemplate['Information'] = $InformationObject
|
|
$PropertyTemplate['PreOSParameters'] = $PreOSParameterObject
|
|
$PropertyTemplate['OSParameters'] = $OSParameterObject
|
|
$PropertyTemplate['VBS'] = $VBSObject
|
|
if ($LoadedModuleList.Count) { $PropertyTemplate['LoadedModules'] = $LoadedModuleList }
|
|
if ($ELAMList) { $PropertyTemplate['ELAM'] = $ELAMList }
|
|
|
|
[PSCustomObject] $PropertyTemplate
|
|
}
|
|
|
|
'LoadedModuleAggregation' {
|
|
$PropertyTemplate = [Ordered] @{
|
|
FilePath = $null
|
|
ImageBase = $null
|
|
ImageSize = $null
|
|
HashAlgorithmID = $null
|
|
AuthenticodeHash = $null
|
|
ImageValidated = $null
|
|
AuthorityIssuer = $null
|
|
AuthorityPublisher = $null
|
|
AuthoritySerial = $null
|
|
AuthoritySHA1Thumbprint = $null
|
|
ModuleSVN = $null
|
|
}
|
|
|
|
$ContainerEvents = Get-SIPAEventData -SIPAEventBytes $EventBytes
|
|
|
|
foreach ($Container in $ContainerEvents) {
|
|
$PropertyTemplate[$Container.SIPAEventType] = $Container.SIPAEventData
|
|
}
|
|
|
|
$ContainerObject = [PSCustomObject] $PropertyTemplate
|
|
|
|
[PSCustomObject] @{
|
|
IsContainer = $False
|
|
SIPAEventType = $SIPAEventType
|
|
SIPAEventData = $ContainerObject
|
|
}
|
|
}
|
|
|
|
'ELAMAggregation' {
|
|
$PropertyTemplate = [Ordered] @{
|
|
ELAMKeyname = $null
|
|
ELAMConfiguration = $null
|
|
ELAMPolicy = $null
|
|
ELAMMeasured = $null
|
|
}
|
|
|
|
$ContainerEvents = Get-SIPAEventData -SIPAEventBytes $EventBytes
|
|
|
|
foreach ($Container in $ContainerEvents) {
|
|
$PropertyTemplate[$Container.SIPAEventType] = $Container.SIPAEventData
|
|
}
|
|
|
|
$ContainerObject = [PSCustomObject] $PropertyTemplate
|
|
|
|
[PSCustomObject] @{
|
|
IsContainer = $False
|
|
SIPAEventType = $SIPAEventType
|
|
SIPAEventData = $ContainerObject
|
|
}
|
|
}
|
|
|
|
'TrustpointAggregation' {
|
|
$PropertyTemplate = [Ordered] @{
|
|
AIKID = $null
|
|
AIKPubDigest = $null
|
|
Quote = $null
|
|
QuoteSignature = $null
|
|
}
|
|
|
|
$ContainerEvents = Get-SIPAEventData -SIPAEventBytes $EventBytes
|
|
|
|
foreach ($Container in $ContainerEvents) {
|
|
$PropertyTemplate[$Container.SIPAEventType] = $Container.SIPAEventData
|
|
}
|
|
|
|
$ContainerObject = [PSCustomObject] $PropertyTemplate
|
|
|
|
$ContainerObject
|
|
}
|
|
|
|
'NoAuthority' {
|
|
[PSCustomObject] @{
|
|
NoAuthority = $EventBytes
|
|
}
|
|
}
|
|
|
|
'AuthorityPubKey' {
|
|
[PSCustomObject] @{
|
|
AuthorityPubKey = ($EventBytes | ForEach-Object { $_.ToString('X2') }) -join ':'
|
|
}
|
|
}
|
|
|
|
default {
|
|
# Return raw event data for KSR containers until I have data to actually parse
|
|
# KSRAggregation
|
|
# KSRSignedMeasurementAggregation
|
|
|
|
Write-Warning "Uncategorized SIPA Event Category"
|
|
|
|
[PSCustomObject] @{
|
|
IsContainer = $True
|
|
SIPAEventType = $SIPAEventType
|
|
SIPAEventData = Get-SIPAEventData -SIPAEventBytes $EventBytes
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
# Each SIPA event data structure will differ depending on the type.
|
|
# Many of these data types are not formally defined but can be easily inferred.
|
|
# If the strucutre is not explicitly stated, it is inferred from multiple events.
|
|
switch ($SIPAEventType) {
|
|
'Information' { $EventData = $EventBytes; $Category = 'Information' }
|
|
'BootCounter' { $EventData = [BitConverter]::ToUInt64($EventBytes, 0); $Category = 'Information' }
|
|
'TransferControl' { $EventData = [BitConverter]::ToUInt32($EventBytes, 0); $Category = 'Information' }
|
|
'ApplicationReturn' { $EventData = $EventBytes; $Category = 'Information' }
|
|
'BitlockerUnlock' { $EventData = [BitConverter]::ToUInt32($EventBytes, 0); $Category = 'Information' }
|
|
'EventCounter' { $EventData = [BitConverter]::ToUInt64($EventBytes, 0); $Category = 'Information' }
|
|
'CounterID' { $EventData = [BitConverter]::ToUInt64($EventBytes, 0); $Category = 'Information' }
|
|
'MORBitNotCancelable' { $EventData = [BitConverter]::ToUInt32($EventBytes, 0); $Category = 'Information' }
|
|
'ApplicationSVN' { $EventData = [BitConverter]::ToUInt32($EventBytes, 0); $Category = 'Information' }
|
|
'SVNChainStatus' { $EventData = [BitConverter]::ToUInt32($EventBytes, 0); $Category = 'Information' }
|
|
# MemoryOverwriteRequest - Introduced in the TCG Platform Reset Attack Mitigation Specification
|
|
'MORBitAPIStatus' { $EventData = [BitConverter]::ToUInt32($EventBytes, 0); $Category = 'Information' }
|
|
'BootDebugging' { $EventData = [Bool] $EventBytes[0]; $Category = 'PreOSParameter' }
|
|
|
|
'BootRevocationList' {
|
|
# SIPAEVENT_REVOCATION_LIST_PAYLOAD structure
|
|
|
|
# I haven't spent time to determine how to translate the creation time yet.
|
|
$CreationTime = [BitConverter]::ToUInt64($EventBytes, 0)
|
|
$DigestLength = [BitConverter]::ToUInt32($EventBytes, 8)
|
|
$HashAlgorithm = $DigestAlgorithmMapping[[BitConverter]::ToUInt16($EventBytes, 0x0C)]
|
|
$Digest = [BitConverter]::ToString($EventBytes[0x0E..(0x0E + $DigestLength - 1)]).Replace('-', '')
|
|
|
|
$Category = 'PreOSParameter'
|
|
|
|
$EventData = [PSCustomObject] @{
|
|
CreationTime = $CreationTime
|
|
HashAlgorithm = $HashAlgorithm
|
|
Digest = $Digest
|
|
}
|
|
}
|
|
|
|
'OSKernelDebug' { $EventData = [Bool] $EventBytes[0]; $Category = 'OSParameter' }
|
|
'CodeIntegrity' { $EventData = [Bool] $EventBytes[0]; $Category = 'OSParameter' }
|
|
'TestSigning' { $EventData = [Bool] $EventBytes[0]; $Category = 'OSParameter' }
|
|
'DataExecutionPrevention' { $EventData = [BitConverter]::ToUInt64($EventBytes, 0); $Category = 'OSParameter' }
|
|
'SafeMode' { $EventData = [Bool] $EventBytes[0]; $Category = 'OSParameter' }
|
|
'WinPE' { $EventData = [Bool] $EventBytes[0]; $Category = 'OSParameter' }
|
|
'PhysicalAddressExtension' { $EventData = [BitConverter]::ToUInt64($EventBytes, 0); $Category = 'OSParameter' }
|
|
'OSDevice' { $EventData = $OSDeviceMapping[[BitConverter]::ToInt32($EventBytes, 0)]; $Category = 'OSParameter' }
|
|
'SystemRoot' { $EventData = [Text.Encoding]::Unicode.GetString($EventBytes).TrimEnd(@(0)); $Category = 'OSParameter' }
|
|
'HypervisorLaunchType' { $EventData = [BitConverter]::ToUInt64($EventBytes, 0); $Category = 'OSParameter' }
|
|
'HypervisorPath' { $EventData = [Text.Encoding]::Unicode.GetString($EventBytes).TrimEnd(@(0)); $Category = 'OSParameter' }
|
|
'HypervisorIOMMUPolicy' { $EventData = [BitConverter]::ToUInt64($EventBytes, 0); $Category = 'OSParameter' }
|
|
'HypervisorDebug' { $EventData = [Bool] $EventBytes[0]; $Category = 'OSParameter' }
|
|
'DriverLoadPolicy' { $EventData = [BitConverter]::ToUInt32($EventBytes, 0); $Category = 'OSParameter' }
|
|
|
|
'SIPolicy' {
|
|
# SIPAEVENT_SI_POLICY_PAYLOAD structure
|
|
|
|
$Revision = [Int32][BitConverter]::ToInt16($EventBytes, 0)
|
|
$Build = [Int32][BitConverter]::ToInt16($EventBytes, 2)
|
|
$Minor = [Int32][BitConverter]::ToInt16($EventBytes, 4)
|
|
$Major = [Int32][BitConverter]::ToInt16($EventBytes, 6)
|
|
$PolicyVersion = New-Object -TypeName Version -ArgumentList @($Major, $Minor, $Build, $Revision)
|
|
|
|
$PolicyNameLength = [BitConverter]::ToInt16($EventBytes, 8)
|
|
$HashAlgorithm = $DigestAlgorithmMapping[[BitConverter]::ToUInt16($EventBytes, 0x0A)]
|
|
|
|
$DigestLength = [BitConverter]::ToUInt16($EventBytes, 0x0C)
|
|
$DigestIndex = 0x10 + $PolicyNameLength
|
|
|
|
$PolicyName = [Text.Encoding]::Unicode.GetString($EventBytes[0x10..($DigestIndex - 1)]).TrimEnd(@(0))
|
|
$Digest = [BitConverter]::ToString($EventBytes[($DigestIndex)..($DigestIndex + $DigestLength - 1)]).Replace('-', '')
|
|
|
|
$Category = 'OSParameter'
|
|
|
|
$EventData = [PSCustomObject] @{
|
|
PolicyVersion = $PolicyVersion
|
|
PolicyName = $PolicyName
|
|
HashAlgorithm = $HashAlgorithm
|
|
Digest = $Digest
|
|
}
|
|
}
|
|
|
|
'HypervisorMMIONXPolicy' { $EventData = [BitConverter]::ToUInt64($EventBytes, 0); $Category = 'OSParameter' }
|
|
'HypervisorMSRFilterPolicy' { $EventData = [BitConverter]::ToUInt64($EventBytes, 0); $Category = 'OSParameter' }
|
|
'VSMLaunchType' { $EventData = [BitConverter]::ToUInt64($EventBytes, 0); $Category = 'OSParameter' }
|
|
|
|
'OSRevocationList' {
|
|
# SIPAEVENT_REVOCATION_LIST_PAYLOAD structure
|
|
|
|
# I haven't spent time to determine how to translate the creation time yet.
|
|
$CreationTime = [BitConverter]::ToUInt64($EventBytes, 0)
|
|
$DigestLength = [BitConverter]::ToUInt32($EventBytes, 8)
|
|
$HashAlgorithm = $DigestAlgorithmMapping[[BitConverter]::ToUInt16($EventBytes, 0x0C)]
|
|
$Digest = [BitConverter]::ToString($EventBytes[0x0E..(0x0E + $DigestLength - 1)]).Replace('-', '')
|
|
|
|
$Category = 'OSParameter'
|
|
|
|
$EventData = [PSCustomObject] @{
|
|
CreationTime = $CreationTime
|
|
HashAlgorithm = $HashAlgorithm
|
|
Digest = $Digest
|
|
}
|
|
}
|
|
|
|
'VSMIDKInfo' {
|
|
# SIPAEVENT_VSM_IDK_INFO_PAYLOAD structure
|
|
|
|
# Type: VSM_IDK_ALG_ID (I can't find this defined anywhere. I'm personally not worried about it. IDK what "IDK" is)
|
|
# This should only be 1.
|
|
$KeyAlgID = [BitConverter]::ToUInt32($EventBytes, 0)
|
|
$null = [BitConverter]::ToUInt32($EventBytes, 4) # KeyBitLength
|
|
$PublicExpLengthBytes = [BitConverter]::ToUInt32($EventBytes, 8)
|
|
$ModulusSizeBytes = [BitConverter]::ToUInt32($EventBytes, 0x0C)
|
|
|
|
$ModulusIndex = 0x10 + $PublicExpLengthBytes
|
|
|
|
[Byte[]] $PublicExponent = $EventBytes[0x10..($ModulusIndex - 1)]
|
|
[Byte[]] $Modulus = $EventBytes[($ModulusIndex)..($ModulusIndex + $ModulusSizeBytes - 1)]
|
|
|
|
$Category = 'OSParameter'
|
|
|
|
$EventData = [PSCustomObject] @{
|
|
KeyAlgID = $KeyAlgID
|
|
PublicExponent = ($PublicExponent | ForEach-Object {$_.ToString('X2')}) -join ':'
|
|
Modulus = ($Modulus | ForEach-Object {$_.ToString('X2')}) -join ':'
|
|
}
|
|
}
|
|
|
|
'FlightSigning' { $EventData = [Bool] $EventBytes[0]; $Category = 'OSParameter' }
|
|
'PagefileEncryptionEnabled' { $EventData = [Bool] $EventBytes[0]; $Category = 'OSParameter' }
|
|
|
|
'VSMIDKSInfo' {
|
|
# SIPAEVENT_VSM_IDK_INFO_PAYLOAD structure
|
|
|
|
# Type: VSM_IDK_ALG_ID (I can't find this defined anywhere. I'm personally not worried about it. IDK what "IDK" is)
|
|
# This should only be 1.
|
|
$KeyAlgID = [BitConverter]::ToUInt32($EventBytes, 0)
|
|
$null = [BitConverter]::ToUInt32($EventBytes, 4) # KeyBitLength
|
|
$PublicExpLengthBytes = [BitConverter]::ToUInt32($EventBytes, 8)
|
|
$ModulusSizeBytes = [BitConverter]::ToUInt32($EventBytes, 0x0C)
|
|
|
|
$ModulusIndex = 0x10 + $PublicExpLengthBytes
|
|
|
|
[Byte[]] $PublicExponent = $EventBytes[0x10..($ModulusIndex - 1)]
|
|
[Byte[]] $Modulus = $EventBytes[($ModulusIndex)..($ModulusIndex + $ModulusSizeBytes - 1)]
|
|
|
|
$Category = 'OSParameter'
|
|
|
|
$EventData = [PSCustomObject] @{
|
|
KeyAlgID = $KeyAlgID
|
|
PublicExponent = ($PublicExponent | ForEach-Object {$_.ToString('X2')}) -join ':'
|
|
Modulus = ($Modulus | ForEach-Object {$_.ToString('X2')}) -join ':'
|
|
}
|
|
}
|
|
|
|
'HibernationDisabled' { $EventData = [Bool] $EventBytes[0]; $Category = 'OSParameter' }
|
|
'DumpsDisabled' { $EventData = [Bool] $EventBytes[0]; $Category = 'OSParameter' }
|
|
'DumpEncryptionEnabled' { $EventData = [Bool] $EventBytes[0]; $Category = 'OSParameter' }
|
|
# SHA-256 digest of thefollowing regkey value:
|
|
# CurrentControlSet\Control\CrashControl\EncryptionCertificates\Certificate.1::PublicKey
|
|
'DumpEncryptionKeyDigest' { $EventData = $EventBytes; $Category = 'OSParameter' }
|
|
'LSAISOConfig' { $EventData = [BitConverter]::ToUInt32($EventBytes, 0); $Category = 'OSParameter' }
|
|
'FilePath' { $EventData = [Text.Encoding]::Unicode.GetString($EventBytes).TrimEnd(@(0)); $Category = 'LoadedImage' }
|
|
'SIPAEventData' { $EventData = [BitConverter]::ToUInt64($EventBytes, 0); $Category = 'LoadedImage' }
|
|
'HashAlgorithmID' { $EventData = $HashAlgorithmMapping[[BitConverter]::ToInt32($EventBytes, 0)]; $Category = 'LoadedImage' }
|
|
'AuthenticodeHash' { $EventData = [BitConverter]::ToString($EventBytes).Replace('-', ''); $Category = 'LoadedImage' }
|
|
'AuthorityIssuer' { $EventData = [Text.Encoding]::Unicode.GetString($EventBytes).TrimEnd(@(0)); $Category = 'LoadedImage' }
|
|
'AuthoritySerial' { $EventData = [BitConverter]::ToString($EventBytes).Replace('-', ''); $Category = 'LoadedImage' }
|
|
'ImageBase' { $EventData = [BitConverter]::ToUInt64($EventBytes, 0); $Category = 'LoadedImage' }
|
|
'ImageSize' { $EventData = [BitConverter]::ToUInt64($EventBytes, 0); $Category = 'LoadedImage' }
|
|
'AuthorityPublisher' { $EventData = [Text.Encoding]::Unicode.GetString($EventBytes).TrimEnd(@(0)); $Category = 'LoadedImage' }
|
|
'AuthoritySHA1Thumbprint' { $EventData = [BitConverter]::ToString($EventBytes).Replace('-', ''); $Category = 'LoadedImage' }
|
|
'ImageValidated' { $EventData = [Bool] $EventBytes[0]; $Category = 'LoadedImage' }
|
|
'ModuleSVN' { $EventData = [BitConverter]::ToUInt32($EventBytes, 0); $Category = 'LoadedImage' }
|
|
'AIKID' { $EventData = [Text.Encoding]::Unicode.GetString($EventBytes).TrimEnd(@(0)); $Category = 'Trustpoint' }
|
|
'AIKPubDigest' { $EventData = [BitConverter]::ToString($EventBytes).Replace('-', ''); $Category = 'Trustpoint' }
|
|
'Quote' { $EventData = ($EventBytes | ForEach-Object { $_.ToString('X2') }) -join ':'; $Category = 'Trustpoint' }
|
|
'QuoteSignature' { $EventData = ($EventBytes | ForEach-Object { $_.ToString('X2') }) -join ':'; $Category = 'Trustpoint' }
|
|
'VBSVSMRequired' { $EventData = [Bool] $EventBytes[0]; $Category = 'VBS' }
|
|
'VBSSecurebootRequired' { $EventData = [Bool] $EventBytes[0]; $Category = 'VBS' }
|
|
'VBSIOMMURequired' { $EventData = [Bool] $EventBytes[0]; $Category = 'VBS' }
|
|
'VBSNXRequired' { $EventData = [Bool] $EventBytes[0]; $Category = 'VBS' }
|
|
'VBSMSRFilteringRequired' { $EventData = [Bool] $EventBytes[0]; $Category = 'VBS' }
|
|
'VBSMandatoryEnforcement' { $EventData = $EventBytes; $Category = 'VBS' }
|
|
'VBSHVCIPolicy' { $EventData = $EventBytes; $Category = 'VBS' }
|
|
'VBSMicrosoftBootChainRequired' { $EventData = [Bool] $EventBytes[0]; $Category = 'VBS' }
|
|
'ELAMKeyname' { $EventData = [Text.Encoding]::Unicode.GetString($EventBytes).TrimEnd(@(0)); $Category = 'ELAM' }
|
|
'ELAMMeasured' { $EventData = [BitConverter]::ToString($EventBytes).Replace('-', ''); $Category = 'ELAM' }
|
|
'ELAMConfiguration' { $EventData = $EventBytes; $Category = 'ELAM' }
|
|
'ELAMPolicy' { $EventData = $EventBytes; $Category = 'ELAM' }
|
|
|
|
default {
|
|
$Category = 'Uncategorized'
|
|
$EventData = $EventBytes
|
|
}
|
|
}
|
|
|
|
[PSCustomObject] @{
|
|
Category = $Category
|
|
SIPAEventType = $SIPAEventType
|
|
SIPAEventData = $EventData
|
|
}
|
|
}
|
|
}
|
|
|
|
$EventBinaryReader.Close()
|
|
}
|
|
|
|
function Get-TPMDeviceInfo {
|
|
<#
|
|
.SYNOPSIS
|
|
|
|
Retrieves TPM information.
|
|
|
|
.DESCRIPTION
|
|
|
|
Get-TPMDeviceInfo retrieves limited TPM information.
|
|
|
|
Author: Matthew Graeber (@mattifestation)
|
|
License: BSD 3-Clause
|
|
|
|
.EXAMPLE
|
|
|
|
Get-TPMDeviceInfo
|
|
#>
|
|
|
|
$TPM_DEVICE_INFO_Size = 16
|
|
|
|
$DeviceInfo = New-Object -TypeName TPMBaseServices.TPM_DEVICE_INFO
|
|
$Result = [TPMBaseServices.UnsafeNativeMethods]::Tbsi_GetDeviceInfo($TPM_DEVICE_INFO_Size, [Ref] $DeviceInfo)
|
|
|
|
if ($Result -eq 0) {
|
|
$DeviceInfo
|
|
} else {
|
|
Write-Error "Tbsi_GetDeviceInfo: $($TBSReturnCodes[$Result])"
|
|
}
|
|
}
|
|
|
|
function Get-TCGLogContent {
|
|
<#
|
|
.SYNOPSIS
|
|
|
|
Retrieves the contents of the Trusted Computing Group (TCG) log.
|
|
|
|
.DESCRIPTION
|
|
|
|
Get-TCGLogContent retrieves the contents of the TCG log (referred to as the "Windows Boot Configuration Log" (WBCL) by Microsoft). This log captures the various boot and runtime measurements used for device health attestation.
|
|
|
|
Author: Matthew Graeber (@mattifestation)
|
|
License: BSD 3-Clause
|
|
|
|
.PARAMETER LogType
|
|
|
|
Specifies the type of TCG log to retrieve. The following arguments are supported:
|
|
|
|
* SRTMCurrent (default): The log associated with PCRs 0-15 for the current session (boot or resume).
|
|
* This option retrieves the contents of HKLM\SYSTEM\CurrentControlSet\Control\IntegrityServices\WBCL
|
|
* DRTMCurrent: The log associated with PCRs 17-22 for the current session (boot or resume).
|
|
* This option retrieves the contents of HKLM\SYSTEM\CurrentControlSet\Control\IntegrityServices\WBCLDrtm
|
|
* The presence of DRTM is validated with NtQuerySystemInformation - SYSTEM_BOOT_ENVIRONMENT_INFORMATION.DbgMeasuredLaunch
|
|
* SRTMBoot: The log associated with PCRs 0-15 for the most recent clean boot session.
|
|
* This log is retrieved from the most current MeasuredBoot log from a clean boot state. For example, if the most recent log is C:\Windows\Logs\MeasuredBoot\0000000029-0000000003.log, This option will retrieve C:\Windows\Logs\MeasuredBoot\0000000029-0000000000.log (indicating the first MeasuredBoot log taken from a clean boot state).
|
|
* SRTMResume: The log associated with PCRs 0-15 for the most recent resume from hibernation.
|
|
* This log is retrieved from the most current MeasuredBoot log taken immediately after the clean state boot log. For example, if the clean boot log is C:\Windows\Logs\MeasuredBoot\0000000029-0000000000.log, this options will retrieve C:\Windows\Logs\MeasuredBoot\0000000029-0000000001.log.
|
|
|
|
.EXAMPLE
|
|
|
|
Get-TCGLogContent
|
|
|
|
Retrieves the TCG log bytes associated with PCRs 0-15 for the current session (boot or resume).
|
|
|
|
.EXAMPLE
|
|
|
|
Get-TCGLogContent -LogType SRTMBoot
|
|
|
|
Retrieves the TCG log bytes associated with PCRs 0-15 for the most recent clean boot session.
|
|
|
|
.OUTPUTS
|
|
|
|
System.Byte[]
|
|
|
|
Outputs a byte array consisting of a raw TCG log. Supply the byte array to ConvertTo-TCGEventLog to parse the contents of the log.
|
|
#>
|
|
|
|
[OutputType([Byte[]])]
|
|
[CmdletBinding()]
|
|
param (
|
|
[Parameter(Position = 0)]
|
|
[String]
|
|
[ValidateSet('SRTMCurrent', 'DRTMCurrent', 'SRTMBoot', 'SRTMResume')]
|
|
$LogType = 'SRTMCurrent'
|
|
)
|
|
|
|
switch ($LogType) {
|
|
'SRTMCurrent' { $LogTypeEnumVal = [TPMBaseServices.TBS_TCGLOG]::TBS_TCGLOG_SRTM_CURRENT }
|
|
'DRTMCurrent' { $LogTypeEnumVal = [TPMBaseServices.TBS_TCGLOG]::TBS_TCGLOG_DRTM_CURRENT }
|
|
'SRTMBoot' { $LogTypeEnumVal = [TPMBaseServices.TBS_TCGLOG]::TBS_TCGLOG_SRTM_BOOT }
|
|
'SRTMResume' { $LogTypeEnumVal = [TPMBaseServices.TBS_TCGLOG]::TBS_TCGLOG_SRTM_RESUME }
|
|
}
|
|
|
|
$TCGLogSize = 0
|
|
|
|
# Supply an empty buffer so that the size of the buffer will be returned.
|
|
$Result = [TPMBaseServices.UnsafeNativeMethods]::Tbsi_Get_TCG_Log_Ex($LogTypeEnumVal, [IntPtr]::Zero, [Ref] $TCGLogSize)
|
|
|
|
if ($Result -ne 0) {
|
|
Write-Error "Tbsi_Get_TCG_Log_Ex: $($TBSReturnCodes[$Result])"
|
|
|
|
return
|
|
}
|
|
|
|
if ($TCGLogSize) {
|
|
Write-Verbose "TCG log size: 0x$($TCGLogSize.ToString('X8'))"
|
|
$TCGLogBuffer = [Runtime.InteropServices.Marshal]::AllocHGlobal($TCGLogSize)
|
|
|
|
# Initialize the buffer to zero. AllocHGlobal won't initialize memory nor will Tbsi_Get_TCG_Log_Ex.
|
|
for ($i = 0; $i -lt $TCGLogSize; $i++) {
|
|
[Runtime.InteropServices.Marshal]::WriteByte($TCGLogBuffer, $i, 0)
|
|
}
|
|
|
|
$TCGLogBytes = New-Object -TypeName Byte[]($TCGLogSize)
|
|
|
|
# Read the TCG log buffer.
|
|
$Result = [TPMBaseServices.UnsafeNativeMethods]::Tbsi_Get_TCG_Log_Ex($LogTypeEnumVal, $TCGLogBuffer, [Ref] $TCGLogSize)
|
|
|
|
if ($Result -ne 0) {
|
|
Write-Error "Tbsi_Get_TCG_Log_Ex: $($TBSReturnCodes[$Result])"
|
|
|
|
# Free the unmanaged memory
|
|
[Runtime.InteropServices.Marshal]::FreeHGlobal($TCGLogBuffer)
|
|
|
|
return
|
|
}
|
|
|
|
# Copy the buffer to the byte array
|
|
[Runtime.InteropServices.Marshal]::Copy($TCGLogBuffer, $TCGLogBytes, 0, $TCGLogSize)
|
|
|
|
# Free the unmanaged memory
|
|
[Runtime.InteropServices.Marshal]::FreeHGlobal($TCGLogBuffer)
|
|
}
|
|
|
|
$TCGLogBytes
|
|
}
|
|
|
|
filter ConvertTo-TCGEventLog {
|
|
<#
|
|
.SYNOPSIS
|
|
|
|
Parses a Trusted Computing Group (TCG) log.
|
|
|
|
.DESCRIPTION
|
|
|
|
ConvertTo-TCGEventLog parses one or more TCG logs (referred to as the "Windows Boot Configuration Log" (WBCL) by Microsoft). This log captures the various boot and runtime measurements used for device health attestation. ConvertTo-TCGEventLog will parse the log as a byte array or from one or more log files on disk.
|
|
|
|
Author: Matthew Graeber (@mattifestation)
|
|
License: BSD 3-Clause
|
|
|
|
.PARAMETER LogBytes
|
|
|
|
Specifies an array of bytes consisting of a raw TCG log.
|
|
|
|
.PARAMETER LogPath
|
|
|
|
Specifies the path to one or more TCG log files. On Windows 10 with TPM enabled, these logs are located at %windir%\Logs\MeasuredBoot by default. Optionally, you can specify an alternate TCG log path with HKLM\System\CurrentControlSet\services\TPM\WBCLPath (REG_EXPAND_SZ).
|
|
|
|
.PARAMETER
|
|
|
|
Specifies that any object that return a signature object should return an X509Certificate object. If this switch is not specified, X509Certificate2 objects will be returned. This switch is present in order to reduce the amount of data in JSON output.
|
|
|
|
.EXAMPLE
|
|
|
|
$TCGLogBytes = Get-TCGLogContent -LogType SRTMCurrent
|
|
$TCGLog = ConvertTo-TCGEventLog -LogBytes $TCGLogBytes
|
|
|
|
.EXAMPLE
|
|
|
|
ls C:\Windows\Logs\MeasuredBoot\*.log | ConvertTo-TCGEventLog
|
|
|
|
.EXAMPLE
|
|
|
|
ConvertTo-TCGEventLog -LogPath C:\Windows\Logs\MeasuredBoot\0000000001-0000000000.log
|
|
|
|
.EXAMPLE
|
|
|
|
ConvertTo-TCGEventLog -LogBytes (Get-TCGLogContent -LogType SRTMBoot) -MinimizedX509CertInfo | ConvertTo-Json -Depth 8 | Out-File TCGlog.json
|
|
|
|
Using the -MinimizedX509CertInfo so that JSON output is not as verbose.
|
|
|
|
.INPUTS
|
|
|
|
System.String
|
|
|
|
Accepts one or more TCG log file paths.
|
|
|
|
.OUTPUTS
|
|
|
|
PSCustomObject
|
|
|
|
Outputs a parsed TCG log.
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param (
|
|
[Parameter(Mandatory, ParameterSetName = 'Bytes')]
|
|
[Byte[]]
|
|
$LogBytes,
|
|
|
|
[Parameter(Mandatory, ParameterSetName = 'LogFile', ValueFromPipelineByPropertyName)]
|
|
[String]
|
|
[Alias('FullName')]
|
|
[ValidateNotNullOrEmpty()]
|
|
$LogPath,
|
|
|
|
[Switch]
|
|
$MinimizedX509CertInfo
|
|
)
|
|
|
|
$LogFullPath = $null
|
|
# The header should be at least this long in order to proceed with parsing.
|
|
$MinimumHeaderLength = 65
|
|
|
|
if ($LogBytes) {
|
|
$TCGLogBytes = $LogBytes
|
|
|
|
if ($TCGLogBytes.Count -lt $MinimumHeaderLength) {
|
|
Write-Error "The supplied byte array is not of sufficient size to be a TCG log. It must be at least $MinimumHeaderLength bytes in length. It is likely that the data supplied to ConvertTo-TCGEventLog is not a TCG log."
|
|
return
|
|
}
|
|
} else {
|
|
# -LogPath was specified
|
|
$LogFullPath = (Resolve-Path $LogPath).Path
|
|
$TCGLogBytes = [IO.File]::ReadAllBytes($LogFullPath)
|
|
|
|
if ($TCGLogBytes.Count -lt $MinimumHeaderLength) {
|
|
Write-Error "$LogFullPath is not of sufficient size to be a TCG log. It must be at least $MinimumHeaderLength bytes in length. It is likely that the data supplied to ConvertTo-TCGEventLog is not a TCG log."
|
|
return
|
|
}
|
|
}
|
|
|
|
if ($MinimizedX509CertInfo) {
|
|
$SignatureObjectType = 'Security.Cryptography.X509Certificates.X509Certificate'
|
|
} else {
|
|
$SignatureObjectType = 'Security.Cryptography.X509Certificates.X509Certificate2'
|
|
}
|
|
|
|
try {
|
|
$MemoryStream = New-Object -TypeName IO.MemoryStream -ArgumentList @(,$TCGLogBytes)
|
|
$BinaryReader = New-Object -TypeName IO.BinaryReader -ArgumentList $MemoryStream, ([Text.Encoding]::Unicode)
|
|
} catch {
|
|
throw $_
|
|
return
|
|
}
|
|
|
|
$PCRIndex = $BinaryReader.ReadUInt32()
|
|
|
|
if ($PCRIndex -ne 0) {
|
|
Write-Error "TCG_PCR_EVENT.PCRIndex expected value: 0. Actual value: $PCRIndex. It is likely that the data supplied to ConvertTo-TCGEventLog is not a TCG log."
|
|
$BinaryReader.Close()
|
|
return
|
|
}
|
|
|
|
$EventType = $EventTypeMapping[$BinaryReader.ReadUInt32()]
|
|
|
|
if ($EventType -ne 'EV_NO_ACTION') {
|
|
Write-Error "TCG_PCR_EVENT.EventType expected value: EV_NO_ACTION. Actual value: $EventType. It is likely that the data supplied to ConvertTo-TCGEventLog is not a TCG log."
|
|
$BinaryReader.Close()
|
|
return
|
|
}
|
|
|
|
$Digest = $BinaryReader.ReadBytes(20)
|
|
$DigestString = [BitConverter]::ToString($Digest).Replace('-', '')
|
|
|
|
if ($DigestString -ne '0000000000000000000000000000000000000000') {
|
|
Write-Error "TCG_PCR_EVENT.Digest expected value: 0000000000000000000000000000000000000000. Actual value: $DigestString. It is likely that the data supplied to ConvertTo-TCGEventLog is not a TCG log."
|
|
$BinaryReader.Close()
|
|
return
|
|
}
|
|
|
|
$EventSize = $BinaryReader.ReadUInt32()
|
|
|
|
# Read the TCG_EfiSpecIdEventStruct instance contents
|
|
$Signature = [Text.Encoding]::ASCII.GetString($BinaryReader.ReadBytes(16)).TrimEnd(@(0, 0))
|
|
|
|
if ($Signature -ne 'Spec ID Event03') {
|
|
Write-Error "TCG_PCR_EVENT.Event.Signature expected value: Spec ID Event03. Actual value: $Signature. It is likely that the data supplied to ConvertTo-TCGEventLog is not a TCG log."
|
|
$BinaryReader.Close()
|
|
return
|
|
}
|
|
|
|
# At this point, there is a very reasonable confidence that this is a well-formed TCG log.
|
|
|
|
$PlatformClass = $BinaryReader.ReadUInt32()
|
|
$SpecVersionMinor = $BinaryReader.ReadByte()
|
|
$SpecVersionMajor = $BinaryReader.ReadByte()
|
|
$SpecErrata = $BinaryReader.ReadByte()
|
|
$UintNSize = $BinaryReader.ReadByte()
|
|
$NumberOfAlgorithms = $BinaryReader.ReadUInt32()
|
|
|
|
$DigestSizes = New-Object -TypeName PSObject[]($NumberOfAlgorithms)
|
|
|
|
for ($i = 0; $i -lt $NumberOfAlgorithms; $i++) {
|
|
$DigestSizes[$i] = New-Object -TypeName PSObject -Property @{
|
|
HashAlg = $DigestAlgorithmMapping[$BinaryReader.ReadUInt16()]
|
|
DigestSize = $BinaryReader.ReadUInt16()
|
|
}
|
|
}
|
|
|
|
$VendorInfoSize = $BinaryReader.ReadByte()
|
|
$VendorInfo = $BinaryReader.ReadBytes($vendorInfoSize)
|
|
|
|
# Described here: https://msdn.microsoft.com/en-us/library/windows/desktop/bb530712(v=vs.85).aspx
|
|
$TCG_EfiSpecIdEventStruct = [PSCustomObject] @{
|
|
PSTypeName = 'TCGEfiSpecIdEvent'
|
|
Signature = $Signature
|
|
PlatformClass = $PlatformClass
|
|
SpecVersionMinor = $SpecVersionMinor
|
|
SpecVersionMajor = $SpecVersionMajor
|
|
SpecErrata = $SpecErrata
|
|
UintNSize = $UintNSize
|
|
NumberOfAlgorithms = $NumberOfAlgorithms
|
|
DigestSizes = $DigestSizes
|
|
VendorInfoSize = $VendorInfoSize
|
|
VendorInfo = $VendorInfo
|
|
}
|
|
|
|
$TCGHeader = [PSCustomObject] @{
|
|
PSTypeName = 'TCGPCREvent'
|
|
PCR = $PCRIndex
|
|
EventType = $EventType
|
|
Digest = $DigestString
|
|
Event = $TCG_EfiSpecIdEventStruct
|
|
}
|
|
|
|
# Loop through all the remaining measurements, parsing each TCG_PCR_EVENT2 struct along the way
|
|
$Events = while ($BinaryReader.PeekChar() -ne -1) {
|
|
$PCRIndex = $BinaryReader.ReadInt32()
|
|
|
|
$EventTypeVal = $BinaryReader.ReadUInt32()
|
|
$EventType = $EventTypeMapping[$EventTypeVal]
|
|
if (-not $EventType) { $EventType = $EventTypeVal.ToString('X8') }
|
|
|
|
# Multiple digests can be calculated/stored but in plractice, you will likely only over see one digest.
|
|
$DigestValuesCount = $BinaryReader.ReadUInt32()
|
|
|
|
if ($DigestValuesCount -eq 1) {
|
|
$HashAlg = $DigestAlgorithmMapping[$BinaryReader.ReadUInt16()]
|
|
$DigestSize = $DigestSizeMapping[$HashAlg]
|
|
|
|
$Digests = [BitConverter]::ToString($BinaryReader.ReadBytes($DigestSize)).Replace('-', '')
|
|
} else {
|
|
$Digests = New-Object -TypeName PSObject[]($DigestValuesCount)
|
|
|
|
for ($i = 0; $i -lt $DigestValuesCount; $i++) {
|
|
$HashAlg = $DigestAlgorithmMapping[$BinaryReader.ReadUInt16()]
|
|
$DigestSize = $DigestSizeMapping[$HashAlg]
|
|
|
|
$Digests[$i] = [BitConverter]::ToString($BinaryReader.ReadBytes($DigestSize)).Replace('-', '')
|
|
}
|
|
}
|
|
|
|
|
|
$EventSize = $BinaryReader.ReadUInt32()
|
|
|
|
$Event = $null
|
|
|
|
# Parse specific event types. Event types that are not explicitly parsed will return a byte array of the contents.
|
|
switch ($EventType) {
|
|
'EV_S_CRTM_CONTENTS' {
|
|
$EventBytes = $BinaryReader.ReadBytes($EventSize)
|
|
$Event = [Text.Encoding]::ASCII.GetString($EventBytes).TrimEnd(@(0))
|
|
}
|
|
|
|
'EV_POST_CODE' {
|
|
$EventBytes = $BinaryReader.ReadBytes($EventSize)
|
|
$Event = [Text.Encoding]::ASCII.GetString($EventBytes).TrimEnd(@(0))
|
|
}
|
|
|
|
'EV_EFI_PLATFORM_FIRMWARE_BLOB' {
|
|
$EventBytes = $BinaryReader.ReadBytes($EventSize)
|
|
$BlobBase = [BitConverter]::ToUInt64($EventBytes, 0)
|
|
$BlobLength = [BitConverter]::ToUInt64($EventBytes, 8)
|
|
|
|
# Chipsec can dump this for validation:
|
|
# chipsec_util.py mem read [BlobBase] [BlobLength] firmwareblob.bin
|
|
# What's dumped will likely be a firmware volume. I use UEFITool.exe to extract contents.
|
|
|
|
$Event = [PSCustomObject] @{
|
|
PSTypeName = 'TCGUEFIPlatformFirmwareBlob'
|
|
BlobBase = $BlobBase
|
|
BlobLength = $BlobLength
|
|
}
|
|
}
|
|
|
|
'EV_EVENT_TAG' {
|
|
$EventBytes = $BinaryReader.ReadBytes($EventSize)
|
|
|
|
# These will be Windows-specific data structures
|
|
$Event = Get-SIPAEventData -SIPAEventBytes $EventBytes
|
|
}
|
|
|
|
'EV_NO_ACTION' {
|
|
$EventBytes = $BinaryReader.ReadBytes($EventSize)
|
|
|
|
if ($PCRIndex -eq -1) {
|
|
# Extact TrustPoint information - used for log attestation
|
|
$Event = Get-SIPAEventData -SIPAEventBytes $EventBytes
|
|
} else {
|
|
$Event = $EventBytes
|
|
}
|
|
}
|
|
|
|
'EV_EFI_GPT_EVENT' {
|
|
# This will consist of a UEFI_GPT_DATA structure.
|
|
|
|
# EFI_TABLE_HEADER: Start
|
|
$EventBytes = $BinaryReader.ReadBytes($EventSize)
|
|
|
|
$GPTMemoryStream = New-Object -TypeName IO.MemoryStream -ArgumentList @(,$EventBytes)
|
|
$GPTBinaryReader = New-Object -TypeName IO.BinaryReader -ArgumentList $GPTMemoryStream, ([Text.Encoding]::Unicode)
|
|
|
|
$Signature = [Text.Encoding]::ASCII.GetString($GPTBinaryReader.ReadBytes(8)).TrimEnd(@(0))
|
|
$SpecMinor = [Int32] $GPTBinaryReader.ReadInt16()
|
|
$SpecMajor = [Int32] $GPTBinaryReader.ReadInt16()
|
|
|
|
$Revision = New-Object -TypeName Version -ArgumentList @($SpecMajor, $SpecMinor, 0, 0)
|
|
|
|
$null = $GPTBinaryReader.ReadUInt32() # HeaderSize
|
|
$CRC32 = $GPTBinaryReader.ReadUInt32()
|
|
$null = $GPTBinaryReader.ReadUInt32() # Reserved
|
|
|
|
$TableHeader = [PSCustomObject] @{
|
|
Signature = $Signature
|
|
Revision = $Revision
|
|
CRC32 = $CRC32
|
|
}
|
|
# EFI_TABLE_HEADER: End
|
|
|
|
# EFI_PARTITION_TABLE_HEADER: Start
|
|
$MyLBA = $GPTBinaryReader.ReadUInt64()
|
|
$AlternateLBA = $GPTBinaryReader.ReadUInt64()
|
|
$FirstUsableLBA = $GPTBinaryReader.ReadUInt64()
|
|
$LastUsableLBA = $GPTBinaryReader.ReadUInt64()
|
|
|
|
$DiskGUID = [Guid][Byte[]] $GPTBinaryReader.ReadBytes(16)
|
|
|
|
$PartitionEntryLBA = $GPTBinaryReader.ReadUInt64()
|
|
$NumberOfPartitionEntries = $GPTBinaryReader.ReadUInt32()
|
|
$SizeOfPartitionEntry = $GPTBinaryReader.ReadUInt32()
|
|
$PartitionEntryArrayCRC32 = $GPTBinaryReader.ReadUInt32()
|
|
# EFI_PARTITION_TABLE_HEADER: End
|
|
|
|
$EFIPartitionHeader = [PSCustomObject] @{
|
|
Header = $TableHeader
|
|
MyLBA = $MyLBA
|
|
AlternateLBA = $AlternateLBA
|
|
FirstUsableLBA = $FirstUsableLBA
|
|
LastUsableLBA = $LastUsableLBA
|
|
DiskGUID = $DiskGUID
|
|
PartitionEntryLBA = $PartitionEntryLBA
|
|
NumberOfPartitionEntries = $NumberOfPartitionEntries
|
|
SizeOfPartitionEntry = $SizeOfPartitionEntry
|
|
PartitionEntryArrayCRC32 = $PartitionEntryArrayCRC32
|
|
}
|
|
|
|
$NumberOfPartitions = $GPTBinaryReader.ReadUInt64()
|
|
|
|
$Partitions = New-Object PSObject[]($NumberOfPartitions)
|
|
|
|
for ($i = 0; $i -lt $NumberOfPartitions; $i++) {
|
|
$PartitionTypeGUID = [Guid][Byte[]] $GPTBinaryReader.ReadBytes(16)
|
|
$PartitionTypeName = $PartitionGUIDMapping[$PartitionTypeGUID.Guid]
|
|
$UniquePartitionGUID = [Guid][Byte[]] $GPTBinaryReader.ReadBytes(16)
|
|
$StartingLBA = $GPTBinaryReader.ReadUInt64()
|
|
$EndingLBA = $GPTBinaryReader.ReadUInt64()
|
|
$Attributes = $GPTBinaryReader.ReadUInt64()
|
|
$PartitionName = [Text.Encoding]::Unicode.GetString($GPTBinaryReader.ReadBytes(72)).TrimEnd(@(0))
|
|
|
|
$Partitions[$i] = [PSCustomObject] @{
|
|
PartitionTypeGUID = $PartitionTypeGUID
|
|
PartitionTypeName = $PartitionTypeName
|
|
UniquePartitionGUID = $UniquePartitionGUID
|
|
StartingLBA = $StartingLBA
|
|
EndingLBA = $EndingLBA
|
|
Attributes = $Attributes
|
|
PartitionName = $PartitionName
|
|
}
|
|
}
|
|
|
|
$Event = [PSCustomObject] @{
|
|
EfiPartitionHeader = $EfiPartitionHeader
|
|
NumberOfPartitions = $NumberOfPartitions
|
|
Partitions = $Partitions
|
|
}
|
|
|
|
$GPTBinaryReader.Close()
|
|
}
|
|
|
|
'EV_SEPARATOR' {
|
|
$EventBytes = $BinaryReader.ReadBytes($EventSize)
|
|
|
|
if ($PCRIndex -gt 11) {
|
|
$Event = [Text.Encoding]::ASCII.GetString($EventBytes)
|
|
} else {
|
|
$Event = ($EventBytes | ForEach-Object {$_.ToString('X2')}) -join ':'
|
|
}
|
|
}
|
|
|
|
'EV_EFI_VARIABLE_AUTHORITY' {
|
|
$VariableName = [Guid] $BinaryReader.ReadBytes(16)
|
|
$UnicodeNameLength = $BinaryReader.ReadUInt64()
|
|
$VariableDataLength = $BinaryReader.ReadUInt64()
|
|
$UnicodeName = [Text.Encoding]::Unicode.GetString($BinaryReader.ReadBytes($UnicodeNameLength * 2)).TrimEnd(@(0))
|
|
|
|
[Byte[]] $SignatureDataBytes = $BinaryReader.ReadBytes($VariableDataLength)
|
|
|
|
if (@('PK', 'KEK', 'db', 'dbx') -contains $UnicodeName) {
|
|
# A EFI_SIGNATURE_DATA instance
|
|
# "The EFI_VARIABLE_DATA.VariableData value shall be the EFI_SIGNATURE_DATA value from
|
|
# the EFI_SIGNATURE_LIST that contained the authority that was used to validate the image
|
|
# and the EFI_VARIABLE_DATA.VariableName shall be set to EFI_IMAGE_SECURITY_DATABASE_GUID.
|
|
# The EFI_VARIABLE_DATA.UnicodeName shall be set to the value of EFI_IMAGE_SECURITY_DATABASE."
|
|
$SignatureOwner = [Guid][Byte[]] $SignatureDataBytes[0..15]
|
|
$SignatureBytes = $SignatureDataBytes[16..($SignatureDataBytes.Count - 1)]
|
|
|
|
$SignatureData = New-Object -TypeName $SignatureObjectType -ArgumentList (@(,$SignatureBytes))
|
|
|
|
$VariableData = [PSCustomObject] @{
|
|
SignatureOwner = $SignatureOwner
|
|
SignatureData = $SignatureData
|
|
}
|
|
} else {
|
|
# Just return a byte array for unknown/new UEFI variables
|
|
$VariableData = $SignatureDataBytes
|
|
}
|
|
|
|
$Event = [PSCustomObject] @{
|
|
PSTypeName = 'TCGUEFIVariable'
|
|
VariableGUID = $VariableName
|
|
VariableName = $UnicodeName
|
|
VariableData = $VariableData
|
|
}
|
|
}
|
|
|
|
'EV_EFI_VARIABLE_DRIVER_CONFIG' {
|
|
$EventBytes = $BinaryReader.ReadBytes($EventSize)
|
|
|
|
$VarMemoryStream = New-Object -TypeName IO.MemoryStream -ArgumentList @(,$EventBytes)
|
|
$VarBinaryReader = New-Object -TypeName IO.BinaryReader -ArgumentList $VarMemoryStream, ([Text.Encoding]::Unicode)
|
|
|
|
$VariableName = [Guid] $VarBinaryReader.ReadBytes(16)
|
|
|
|
# To-do: These lengths are dependant upon the platform architecture. Currently, I'm only considering 64-bit platforms
|
|
$UnicodeNameLength = $VarBinaryReader.ReadUInt64()
|
|
$VariableDataLength = $VarBinaryReader.ReadUInt64()
|
|
$UnicodeName = [Text.Encoding]::Unicode.GetString($VarBinaryReader.ReadBytes($UnicodeNameLength * 2)).TrimEnd(@(0))
|
|
|
|
if (@('PK', 'KEK', 'db', 'dbx') -contains $UnicodeName) {
|
|
# Parse out the EFI_SIGNATURE_LIST structs
|
|
|
|
$SignatureTypeMapping = @{
|
|
'C1C41626-504C-4092-ACA9-41F936934328' = 'EFI_CERT_SHA256_GUID' # Most often used for dbx
|
|
'A5C059A1-94E4-4AA7-87B5-AB155C2BF072' = 'EFI_CERT_X509_GUID' # Most often used for db
|
|
}
|
|
|
|
while ($VarBinaryReader.PeekChar() -ne -1) {
|
|
$SignatureType = $SignatureTypeMapping[([Guid][Byte[]] $VarBinaryReader.ReadBytes(16)).Guid]
|
|
$SignatureListSize = $VarBinaryReader.ReadUInt32()
|
|
$SignatureHeaderSize = $VarBinaryReader.ReadUInt32()
|
|
$SignatureSize = $VarBinaryReader.ReadUInt32()
|
|
|
|
$null = $VarBinaryReader.ReadBytes($SignatureHeaderSize) # SignatureHeader
|
|
|
|
# 0x1C is the size of the EFI_SIGNATURE_LIST header
|
|
$SignatureCount = ($SignatureListSize - 0x1C) / $SignatureSize
|
|
|
|
$Signature = 1..$SignatureCount | ForEach-Object {
|
|
$SignatureDataBytes = $VarBinaryReader.ReadBytes($SignatureSize)
|
|
|
|
$SignatureOwner = [Guid][Byte[]] $SignatureDataBytes[0..15]
|
|
|
|
switch ($SignatureType) {
|
|
'EFI_CERT_SHA256_GUID' {
|
|
$SignatureData = ([Byte[]] $SignatureDataBytes[0x10..0x2F] | ForEach-Object { $_.ToString('X2') }) -join ''
|
|
}
|
|
|
|
'EFI_CERT_X509_GUID' {
|
|
$SignatureData = New-Object $SignatureObjectType -ArgumentList @(,([Byte[]] $SignatureDataBytes[16..($SignatureDataBytes.Count - 1)]))
|
|
}
|
|
}
|
|
|
|
[PSCustomObject] @{
|
|
PSTypeName = 'EFI.SignatureData'
|
|
SignatureOwner = $SignatureOwner
|
|
SignatureData = $SignatureData
|
|
}
|
|
}
|
|
|
|
$VariableData = [PSCustomObject] @{
|
|
SignatureType = $SignatureType
|
|
Signature = $Signature
|
|
}
|
|
}
|
|
} else {
|
|
$VariableData = $VarBinaryReader.ReadBytes($VariableDataLength)
|
|
}
|
|
|
|
$VarBinaryReader.Close()
|
|
|
|
$Event = [PSCustomObject] @{
|
|
PSTypeName = 'TCGUEFIVariable'
|
|
VariableGUID = $VariableName
|
|
VariableName = $UnicodeName
|
|
VariableData = $VariableData
|
|
}
|
|
}
|
|
|
|
'EV_EFI_BOOT_SERVICES_APPLICATION' {
|
|
$EventBytes = $BinaryReader.ReadBytes($EventSize)
|
|
|
|
$ImageLocationInMemory = [BitConverter]::ToUInt64($EventBytes, 0)
|
|
$ImageLengthInMemory = [BitConverter]::ToUInt64($EventBytes, 8)
|
|
$ImageLinkTimeAddress = [BitConverter]::ToUInt64($EventBytes, 16)
|
|
$LengthOfDevicePath = [BitConverter]::ToUInt64($EventBytes, 24)
|
|
|
|
$DevicePathBytes = $EventBytes[32..(32 + $LengthOfDevicePath - 1)]
|
|
|
|
$FilePathList = $null
|
|
|
|
# Parse all the file list entries
|
|
if ($DevicePathBytes.Count) {
|
|
$MoreToParse = $True
|
|
$FilePathEntryIndex = 0
|
|
|
|
$FilePathList = while ($MoreToParse) {
|
|
# Parse the EFI_DEVICE_PATH_PROTOCOL struct.
|
|
|
|
$DevicePathType = $DevicePathTypeMapping[$DevicePathBytes[$FilePathEntryIndex]]
|
|
$Length = [BitConverter]::ToUInt16($DevicePathBytes, $FilePathEntryIndex + 2)
|
|
[Byte[]] $DataBytes = $DevicePathBytes[($FilePathEntryIndex + 4)..($FilePathEntryIndex + $Length - 1)]
|
|
|
|
switch ($DevicePathType) {
|
|
'ACPI_DEVICE_PATH' {
|
|
$DeviceSubType = $ACPIDeviceSubTypeMapping[$DevicePathBytes[$FilePathEntryIndex + 1]]
|
|
|
|
switch ($DeviceSubType) {
|
|
'ACPI_DP' {
|
|
$HID = [BitConverter]::ToUInt32($DevicePathBytes, $FilePathEntryIndex + 4 + 0)
|
|
$UID = [BitConverter]::ToUInt32($DevicePathBytes, $FilePathEntryIndex + 4 + 4)
|
|
|
|
$DeviceInfo = [PSCustomObject] @{
|
|
HID = $HID # Device's PnP hardware ID stored in a numeric 32-bit
|
|
# compressed EISA-type ID. This value must match the
|
|
# corresponding _HID in the ACPI name space.
|
|
UID = $UID # Unique ID that is required by ACPI if two devices have the
|
|
# same _HID. This value must also match the corresponding
|
|
# _UID/_HID pair in the ACPI name space.
|
|
}
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
DeviceInfo = $DeviceInfo
|
|
}
|
|
}
|
|
|
|
'ACPI_EXTENDED_DP' {
|
|
$HID = [BitConverter]::ToUInt32($DevicePathBytes, $FilePathEntryIndex + 4 + 0)
|
|
$UID = [BitConverter]::ToUInt32($DevicePathBytes, $FilePathEntryIndex + 4 + 4)
|
|
$CID = [BitConverter]::ToUInt32($DevicePathBytes, $FilePathEntryIndex + 4 + 8)
|
|
|
|
$DeviceInfo = [PSCustomObject] @{
|
|
HID = $HID
|
|
UID = $UID
|
|
CID = $CID # Device's compatible PnP hardware ID stored in a numeric
|
|
# 32-bit compressed EISA-type ID.
|
|
}
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
DeviceInfo = $DeviceInfo
|
|
}
|
|
}
|
|
|
|
'ACPI_ADR_DP' {
|
|
$ADR = [BitConverter]::ToUInt32($DevicePathBytes, $FilePathEntryIndex + 4 + 0)
|
|
|
|
$DeviceInfo = [PSCustomObject] @{
|
|
ADR = $ADR # For video output devices the value of this
|
|
# field comes from Table B-2 of the ACPI 3.0 specification.
|
|
}
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
DeviceInfo = $DeviceInfo
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
'MEDIA_DEVICE_PATH' {
|
|
$DeviceSubType = $MediaDeviceSubTypeMapping[$DevicePathBytes[$FilePathEntryIndex + 1]]
|
|
|
|
switch ($DeviceSubType) {
|
|
'MEDIA_HARDDRIVE_DP' {
|
|
$PartitionNumber = [BitConverter]::ToUInt32($DevicePathBytes, $FilePathEntryIndex + 4 + 0)
|
|
$PartitionStart = [BitConverter]::ToUInt64($DevicePathBytes, $FilePathEntryIndex + 4 + 4)
|
|
$PartitionSize = [BitConverter]::ToUInt64($DevicePathBytes, $FilePathEntryIndex + 4 + 4 + 8)
|
|
|
|
$SignatureIndex = $FilePathEntryIndex + 4 + 4 + 8 + 8
|
|
[Byte[]] $SignatureBytes = $DevicePathBytes[$SignatureIndex..($SignatureIndex + 16 - 1)]
|
|
$MBRType = @{ [Byte] 1 = 'MBR_TYPE_PCAT'; [Byte] 2 = 'MBR_TYPE_EFI_PARTITION_TABLE_HEADER' }[$DevicePathBytes[$SignatureIndex + 16]]
|
|
$SignatureType = @{ [Byte] 0 = 'NO_DISK_SIGNATURE'; [Byte] 1 = 'SIGNATURE_TYPE_MBR'; [Byte] 2 = 'SIGNATURE_TYPE_GUID' }[$DevicePathBytes[$SignatureIndex + 16 + 1]]
|
|
|
|
$DeviceInfo = [PSCustomObject] @{
|
|
PartitionNumber = $PartitionNumber
|
|
PartitionStart = $PartitionStart
|
|
PartitionSize = $PartitionSize
|
|
Signature = ($SignatureBytes | ForEach-Object {$_.ToString('X2')}) -join ':'
|
|
MBRType = $MBRType
|
|
SignatureType = $SignatureType
|
|
}
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
DeviceInfo = $DeviceInfo
|
|
}
|
|
}
|
|
|
|
|
|
'MEDIA_FILEPATH_DP' {
|
|
$PathName = [Text.Encoding]::Unicode.GetString($DataBytes).TrimEnd(@(0))
|
|
$DeviceInfo = [PSCustomObject] @{ PathName = $PathName }
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
DeviceInfo = $DeviceInfo
|
|
}
|
|
}
|
|
|
|
'MEDIA_PIWG_FW_VOL_DP' {
|
|
$DeviceInfo = [PSCustomObject] @{ FvName = [Guid] $DataBytes }
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
DeviceInfo = $DeviceInfo
|
|
}
|
|
}
|
|
|
|
'MEDIA_PIWG_FW_FILE_DP' {
|
|
$DeviceInfo = [PSCustomObject] @{ FvFileName = [Guid] $DataBytes }
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
DeviceInfo = $DeviceInfo
|
|
}
|
|
}
|
|
|
|
default {
|
|
$DeviceSubType = $DevicePathBytes[$FilePathEntryIndex + 1].ToString('X2')
|
|
$DeviceInfo = [PSCustomObject] @{ RawDeviceBytes = $DataBytes }
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
DeviceInfo = $DeviceInfo
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
'END_DEVICE_PATH_TYPE' { }
|
|
|
|
default {
|
|
# Until other subtypes are added, just supply the bytes.
|
|
$DeviceSubType = $DevicePathBytes[$FilePathEntryIndex + 1].ToString('X2')
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
Length = $Length
|
|
Data = ($DataBytes | ForEach-Object {$_.ToString('X2')}) -join ':'
|
|
}
|
|
}
|
|
}
|
|
|
|
$FilePathEntryIndex = $FilePathEntryIndex + $Length
|
|
$MoreToParse = $null -ne $DevicePathBytes[$FilePathEntryIndex]
|
|
}
|
|
}
|
|
|
|
$Event = [PSCustomObject] @{
|
|
ImageLocationInMemory = $ImageLocationInMemory
|
|
ImageLengthInMemory = $ImageLengthInMemory
|
|
ImageLinkTimeAddress = $ImageLinkTimeAddress
|
|
DevicePath = $FilePathList
|
|
}
|
|
}
|
|
|
|
'EV_EFI_ACTION' {
|
|
$EventBytes = $BinaryReader.ReadBytes($EventSize)
|
|
$Event = [Text.Encoding]::ASCII.GetString($EventBytes).TrimEnd(@(0))
|
|
}
|
|
|
|
'EV_EFI_VARIABLE_BOOT' {
|
|
$VariableName = [Guid] $BinaryReader.ReadBytes(16)
|
|
|
|
$UnicodeNameLength = $BinaryReader.ReadUInt64()
|
|
$VariableDataLength = $BinaryReader.ReadUInt64()
|
|
$UnicodeName = [Text.Encoding]::Unicode.GetString($BinaryReader.ReadBytes($UnicodeNameLength * 2)).TrimEnd(@(0))
|
|
|
|
if ($UnicodeName -eq 'BootOrder') {
|
|
$VariableData = 1..($VariableDataLength / 2) | ForEach-Object { $BinaryReader.ReadUInt16().ToString('X4') }
|
|
} elseif ($UnicodeName -match '^Boot[0-9A-F]{4}$') {
|
|
$VariableDataBytes = $BinaryReader.ReadBytes($VariableDataLength)
|
|
|
|
$Attributes = [BitConverter]::ToUInt32($VariableDataBytes, 0)
|
|
$FilePathListLength = [BitConverter]::ToUInt16($VariableDataBytes, 4)
|
|
|
|
$Index = 6
|
|
|
|
$DescriptionChars = do {
|
|
$CharVal = [BitConverter]::ToUInt16($VariableDataBytes, $index)
|
|
[Char] $CharVal
|
|
|
|
$Index += 2
|
|
} while ($CharVal -ne 0)
|
|
|
|
[String] $Description = $DescriptionChars -join ''
|
|
|
|
$FilePathListEndIndex = $Index + $FilePathListLength - 1
|
|
# This will be of type: EFI_DEVICE_PATH_PROTOCOL
|
|
[Byte[]] $FilePathListBytes = $VariableDataBytes[$Index..$FilePathListEndIndex]
|
|
$FilePathList = $null
|
|
|
|
# Parse all the file list entries
|
|
if ($FilePathListBytes.Count) {
|
|
$MoreToParse = $True
|
|
$FilePathEntryIndex = 0
|
|
|
|
$FilePathList = while ($MoreToParse) {
|
|
# Parse the EFI_DEVICE_PATH_PROTOCOL struct.
|
|
|
|
$DevicePathType = $DevicePathTypeMapping[$FilePathListBytes[$FilePathEntryIndex]]
|
|
$Length = [BitConverter]::ToUInt16($FilePathListBytes, $FilePathEntryIndex + 2)
|
|
[Byte[]] $DataBytes = $FilePathListBytes[($FilePathEntryIndex + 4)..($FilePathEntryIndex + $Length - 1)]
|
|
|
|
switch ($DevicePathType) {
|
|
'MEDIA_DEVICE_PATH' {
|
|
$DeviceSubType = $MediaDeviceSubTypeMapping[$FilePathListBytes[$FilePathEntryIndex + 1]]
|
|
|
|
switch ($DeviceSubType) {
|
|
'MEDIA_HARDDRIVE_DP' {
|
|
$PartitionNumber = [BitConverter]::ToUInt32($FilePathListBytes, $FilePathEntryIndex + 4 + 0)
|
|
$PartitionStart = [BitConverter]::ToUInt64($FilePathListBytes, $FilePathEntryIndex + 4 + 4)
|
|
$PartitionSize = [BitConverter]::ToUInt64($FilePathListBytes, $FilePathEntryIndex + 4 + 4 + 8)
|
|
|
|
$SignatureIndex = $FilePathEntryIndex + 4 + 4 + 8 + 8
|
|
[Byte[]] $SignatureBytes = $FilePathListBytes[$SignatureIndex..($SignatureIndex + 16 - 1)]
|
|
$MBRType = @{ [Byte] 1 = 'MBR_TYPE_PCAT'; [Byte] 2 = 'MBR_TYPE_EFI_PARTITION_TABLE_HEADER' }[$FilePathListBytes[$SignatureIndex + 16]]
|
|
$SignatureType = @{ [Byte] 0 = 'NO_DISK_SIGNATURE'; [Byte] 1 = 'SIGNATURE_TYPE_MBR'; [Byte] 2 = 'SIGNATURE_TYPE_GUID' }[$FilePathListBytes[$SignatureIndex + 16 + 1]]
|
|
|
|
$DeviceInfo = [PSCustomObject] @{
|
|
PartitionNumber = $PartitionNumber
|
|
PartitionStart = $PartitionStart
|
|
PartitionSize = $PartitionSize
|
|
Signature = ($SignatureBytes | ForEach-Object {$_.ToString('X2')}) -join ':'
|
|
MBRType = $MBRType
|
|
SignatureType = $SignatureType
|
|
}
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
DeviceInfo = $DeviceInfo
|
|
}
|
|
}
|
|
|
|
|
|
'MEDIA_FILEPATH_DP' {
|
|
$PathName = [Text.Encoding]::Unicode.GetString($DataBytes).TrimEnd(@(0))
|
|
$DeviceInfo = [PSCustomObject] @{ PathName = $PathName }
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
DeviceInfo = $DeviceInfo
|
|
}
|
|
}
|
|
|
|
'MEDIA_PIWG_FW_VOL_DP' {
|
|
$DeviceInfo = [PSCustomObject] @{ FvName = [Guid] $DataBytes }
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
DeviceInfo = $DeviceInfo
|
|
}
|
|
}
|
|
|
|
'MEDIA_PIWG_FW_FILE_DP' {
|
|
$DeviceInfo = [PSCustomObject] @{ FvFileName = [Guid] $DataBytes }
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
DeviceInfo = $DeviceInfo
|
|
}
|
|
}
|
|
|
|
default {
|
|
$DeviceSubType = $FilePathListBytes[$FilePathEntryIndex + 1].ToString('X2')
|
|
$DeviceInfo = [PSCustomObject] @{ RawDeviceBytes = $DataBytes }
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
DeviceInfo = $DeviceInfo
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
'END_DEVICE_PATH_TYPE' { }
|
|
|
|
default {
|
|
# Until other subtypes are added, just supply the bytes.
|
|
$DeviceSubType = $FilePathListBytes[$FilePathEntryIndex + 1].ToString('X2')
|
|
|
|
[PSCustomObject] @{
|
|
Type = $DevicePathType
|
|
SubType = $DeviceSubType
|
|
Length = $Length
|
|
Data = ($DataBytes | ForEach-Object {$_.ToString('X2')}) -join ':'
|
|
}
|
|
}
|
|
}
|
|
|
|
$FilePathEntryIndex = $FilePathEntryIndex + $Length
|
|
$MoreToParse = $null -ne $FilePathListBytes[$FilePathEntryIndex]
|
|
}
|
|
}
|
|
|
|
$OptionalData = $null
|
|
|
|
# The remaining bytes in the load option descriptor are a binary data buffer that is passed to the loaded image.
|
|
# If the field is zero bytes long, a NULL pointer is passed to the loaded image. The number of bytes in OptionalData
|
|
# can be computed by subtracting the starting offset of OptionalData from total size in bytes of the EFI_LOAD_OPTION.
|
|
if (($VariableDataBytes.Count - ($FilePathListEndIndex + 1)) -gt 0) { $OptionalData = $VariableDataBytes[($FilePathListEndIndex + 1)..($VariableDataBytes.Count - 1)] }
|
|
|
|
if ($OptionalData) { $OptionalData = ($OptionalData | ForEach-Object {$_.ToString('X2')}) -join ':' }
|
|
|
|
$VariableData = [PSCustomObject] @{
|
|
Attributes = $Attributes
|
|
FilePathListLength = $FilePathListLength
|
|
Description = $Description.TrimEnd(@(0))
|
|
FilePathList = $FilePathList
|
|
OptionalData = $OptionalData
|
|
}
|
|
} else {
|
|
$VariableData = $BinaryReader.ReadBytes($VariableDataLength)
|
|
}
|
|
|
|
$Event = [PSCustomObject] @{
|
|
PSTypeName = 'TCGUEFIVariable'
|
|
VariableGUID = $VariableName
|
|
VariableName = $UnicodeName
|
|
VariableData = $VariableData
|
|
}
|
|
}
|
|
|
|
default {
|
|
$Event = ($BinaryReader.ReadBytes($EventSize) | ForEach-Object {$_.ToString('X2')}) -join ':'
|
|
}
|
|
}
|
|
|
|
[Ordered] @{
|
|
PCR = $PCRIndex
|
|
EventType = $EventType
|
|
Digest = $Digests
|
|
Event = $Event
|
|
}
|
|
}
|
|
|
|
$BinaryReader.Close()
|
|
|
|
$PCRTemplate = [Ordered] @{
|
|
PCR0 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR1 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR2 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR3 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR4 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR5 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR6 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR7 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR8 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR9 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR10 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR11 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR12 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR13 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR14 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR15 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR16 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCR23 = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
PCRMinusOne = (New-Object 'System.Collections.Generic.List[PSObject]')
|
|
}
|
|
|
|
foreach ($PCRMeasurement in $Events) {
|
|
if ($PCRMeasurement['PCR'] -eq -1) {
|
|
$PCRMeasurement.Remove('PCR')
|
|
$PCRTemplate['PCRMinusOne'].Add(([PSCustomObject] $PCRMeasurement))
|
|
} else {
|
|
$PCRNum = $PCRMeasurement['PCR']
|
|
$PCRMeasurement.Remove('PCR')
|
|
$PCRTemplate["PCR$($PCRNum)"].Add(([PSCustomObject] $PCRMeasurement))
|
|
}
|
|
}
|
|
|
|
foreach ($Key in $PCRTemplate.GetEnumerator().Name) {
|
|
if ($PCRTemplate[$Key].Count -eq 0) { $PCRTemplate[$Key] = $null }
|
|
if ($PCRTemplate[$Key].Count -eq 1) { $PCRTemplate[$Key] = $PCRTemplate[$Key][0] }
|
|
}
|
|
|
|
$TCGEventLog = [PSCustomObject] @{
|
|
PSTypeName = 'TCGLog'
|
|
LogPath = $LogFullPath
|
|
Header = $TCGHeader
|
|
Events = ([PSCustomObject] $PCRTemplate)
|
|
}
|
|
|
|
$TCGEventLog
|
|
}
|
|
|
|
Export-ModuleMember -Function Get-TCGLogContent, ConvertTo-TCGEventLog, Get-TPMDeviceInfo
|