Monday, June 29, 2015

On the Forensic Trail - Guid Partition Table (GPT)

[This is the 3rd in a multi-part series titled "On the Forensic Trail".  My goal with this series is to introduce my PowerShell Forensics module called PowerForensics, and the forensic artifacts that it parses.  This post covers the Guid Partition Table (GPT), an alternative hard disk partitioning scheme to the Master Boot Record, and how to use PowerForensics to inspect it.]

For help with downloading/installing PowerForensics please visit the Installing PowerForensics article.

As United Extensible Firmware Interface (UEFI) begins to replace legacy BIOS firmware interfaces, we will see the rise of the Guid Partition Table (GPT) as a replacement for the Master Boot Record.  The UEFI Specification requires that all compliant firmware supports the GPT partitioning scheme, so GPT will begin to become more common as UEFI is implemented by vendors.  That being said, the GPT partitioning scheme is not unique to UEFI, as it is also supported by many modern BIOS systems.

This post explores the Guid Partition Table data structure, and focuses on how PowerForensics can be used with it.

Advantages of GPT
The GUID Partition Table provides a number of advantages over the legacy Master Boot Record disk layout.  Three of the main advantages of the GPT disk layout are listed below:

1)  Logical Block Addresses (LBAs) are 64 bits (rather than 32 bits) increasing the maximum partition size from 2 TiB to 8 ZiB. 
2)  GPT supports many partitions (rather than just four primary partitions). 
3)  Provides both a primary and backup partition table for redundancy.  Two GPT Header structures are stored on the device: the primary and the backup. The primary GPT Header must be located in LBA 1 (i.e., the second logical block), and the backup GPT Header must be located in the last LBA of the device. 

GPT Data Structure
Protective MBR
When a disk is formatted with a GPT disk layout, a Protective MBR is located at Logical Block Address (LBA) 0.  The Protective MBR is used to provide compatibility with legacy tools that do not understand the GPT format.  The Protective MBR is functionally equivalent to a normal or "Legacy" MBR, but only has one partition.  The first/only partition will be of type 0xEE (EFI_GPT_DISK) and reserves the entire disk starting at LBA 1 for the formal Guid Partition Table structure.  

It is worth noting that the MBR Boot Code (the first 440 bytes) is not executed by UEFI Firmware. 

    In the example below, the Get-MBR cmdlet is used to display the MBR Partition Table of a GPT formatted disk.  The output shows that there is one EFI_GPT_DISK partition that starts at LBA 1 (the sector immediately following the Protective MBR) and ends at LBA 4294967295 (or 0xFFFFFFFF which represents the entire disk).

    Guid Partition Table
    The formal Guid Partition Table begins at LBA 1 where the GPT Header is found.

    GPT Header
    The GPT Header describes the logical layout of the disk as a whole.  The location of the GPT Header  is described by the MyLBA value and should always be 1, while the AlternateLBA value points to the backup GPT and will always be the last sector on disk.  It contains the DiskGUID, which is used to uniquely identify the disk, and CRC32 values which are used by firmware to detect corruption of the GPT itself.  If the GPT is corrupted, the original GPT will be replaced with the backup GPT.  The FirstUsableLBA and LastUsableLBA values define the portion of the disk that is not reserved by the GPT and therefore can be used by the partitions.  Lastly, the header provides us with details about the Partition Array itself.  The PartitionEntryLBA value points to the start of the array, and its overall size can be derived from the NumberOfPartitionEntries and SizeOfPartitionEntry value.

    Partition Array
    The GPT Header points to the Partition Array via the PartitionEntryLBA value.  The size and number of partitions are defined in the GPT Header (The number of partitions value may not correspond with the number of actual partitions, but rather the space reserved for partition entries).  

    Each partition contains two GUIDs, one representing the type of partition (see this table to interpret) and the second is used to uniquely identify the partition.  The StartingLBA and EndingLBA values to describe the location and size of the partition.  Lastly, 64 bits are reserved for attribute flags, and 72 bytes are reserved for a null terminated name string.

    PowerForensics Cmdlets
    PowerForensics currently has three cmdlets that deal specifically with the GPT (Get-GPT, Get-BootSector, and Get-PartitionTable).  This portion of the post will explain the cmdlets and go through a few example use cases.

    Get-GPT is a cmdlet that parses the GUID Partition Table data structure contained within the first few sector of the device specified.  Get-GPT requires the use of the -Path parameter which takes the Win32 Device Namespace (ex. \\.\PHYSICALDRIVE1) for the device from which the GPT should be parsed.

    In this example, Get-GPT is executed against \\.\PHYSICALDRIVE1 and returns a GuidPartitionTable object.
    If Get-GPT is run against a disk formatted with a Master Boot Record, it will throw an error prompting you to use Get-MBR instead.
    InvokeIR.PowerForensics.GuidPartitionTable Object
    Get-GPT outputs an InvokeIR.PowerForensics.GuidPartitionTable object.  This object contains 11 readonly properties (property descriptions provided by the UEFI Specification):

    1)  Revision -  The revision number for this header.
    2)  HeaderSize - Size in bytes of the GPT Header. Must be greater than or equal to 92 and must be less than or equal to the logical block size.
    3)  MyLBA - The LBA that contains this data structure.
    4)  AlternateLBA -  LBA address of the alternate (backup) GPT Header. 
    5)  FirstUsableLBA - The first usable logical block that may be used by a partition described by a GUID Partition Entry.
    6)  LastUsableLBA - The last usable logical block that may be used by a partition described by a GUID Partition Entry.
    7)  DiskGUID - GUID that can be used to uniquely identify the disk.
    8)  PartitionEntryLBA - The starting LBA of the GUID Partition Array.
    9)  NumberOfPartitionEntries - The number of Partition Entries in the GUID Partition Array.
    10)  SizeOfPartitionEntry - The size, in bytes, of each the GUID Partition Entry structures in the GUID Partition Array.
    11)  PartitionTable - An array of InvokeIR.PowerForensics.GuidPartitionEntry objects.

    The Get-BootSector cmdlet provides an alternative to the Get-MBR and Get-GPT cmdlets.  Get-BootSector reviews the hard drive's first sector and determines if the disk is formatted using the Master Boot Record or Guid Partition Table partitioning scheme.  Once the partitioning scheme is determined, Get-BootSector acts just as Get-MBR or Get-GPT would respectively.

    NOTE: Since making Get-BootSector, I rarely use the Get-MBR or Get-GPT cmdlets, but have kept them in the module in case anyone finds a reason for them.

    Here Get-BootSector running against a disk formatted using the GPT partitioning scheme.  The cmdlet returns an InvokeIR.PowerForensics.GuidPartitionTable object.
    When Get-BootSector targets an MBR formatted disk it returns an InvokeIR.PowerForensics.MasterBootRecord object.
    Like Get-BootSector, Get-PartitionTable determines the type of boot sector (Master Boot Record or Guid PartitionTable) and returns the correct partition object (InvokeIR.PowerForensics.PartitionEntry or InvokeIR.PowerForensics.GuidPartitionTableEntry). 
    As a reminder, this is an example of Get-PartitionTable being run against an MBR formatted disk and returning an PartitionEntry object.
    In this example, Get-PartitionTable is run against a GPT formatted hard drive disk (\\.\PHYSICALDISK1).  The cmdlet returns an array of GuidPartitionTableEntry Objects.

    InvokeIR.PowerForensics.GuidPartitionTableEntry Object
    When Get-PartitionTable is run against a GPT formatted disk, the cmdlet outputs an InvokeIR.PowerForensics.GuidPartitionTableEntry object.  The GuidPartitionTableEntry object is made up of 6 readonly properties (property descriptions provided by the UEFI Specification):

    1)  PartitionTypeGUID - Unique ID that defines the purpose and type of this Partition. A value of zero defines that this partition entry is not being used.
    2)  UniquePartitionGUID -  GUID that is unique for every partition entry.
    3)  StartingLBA - Starting LBA of the partition defined by this entry.
    4)  EndingLBA - Ending LBA of the partition defined by this entry.
    5)  Attributes - Flag value representing the partition's attributes.
    6)  PartitionName - Null-terminated string containing a human-readable name of the partition. 


    - Invoke-IR - By Jared Atkinson -