An Examination of
The
Microsoft® Windows 7, 8 and 10
GPT 'Protective' MBR
and EFI
Partitions
(with a comment on Linux and Apple� Mac OS GPT drives)
Web Presentation and Text are
Copyright©2013, 2017, 2021 by Daniel B. Sedory
NOT to be reproduced in any form without Permission of the Author !
Here we examine the structure created by the Windows 7 (64-bit) "Logical Disk Manager" when GPT partitioning is chosen. The major reason for the invention of the GPT ("GUID Partition Table") was the limitation of the MBR Partition Table to a maximum partition size of 4,294,967,295 sectors (about 2.2 TB). However, the minimum capacity for a GPT partitioned drive is far less than 2 TB. In fact, we created our first GPT partitioned disk drive (in a virtual computer) with a capacity of only 2 GiB (after wiping every byte of the drive with the hex value 0x22, so we could know for sure if any sectors were zero-filled by the OS):
NOTE: Although the Windows 7, 8 or 10 Logical Disk Manager does not distinguish between disks partitioned as MBR or GPT in its main view (both disk types are simply listed as "Basic"), they do clearly indicate such disks in the Volume TAB of the Properties of a disk. Typical example from a Windows 10 Laptop:
The way geeks and Sys Admins used to determine if a disk was GPT partitioned was to use the List Disk command of the "DISKPART" tool in a Command Prompt... Today they use the same tool, but normally under Windows PowerShell. Simply enter the commands shown in GREEN below. If any attached disk has been GPT partitioned, an asterisk (*) will appear under the "Gpt" column; as shown in YELLOW for Disk 0 below (or in using the BLUE screen of PowerShell):
Microsoft Windows [Version 6.1.7601] Copyright (c) 2009 Microsoft Corporation. All rights reserved. C:\Windows\system32>diskpart Microsoft DiskPart version 6.1.7601 Copyright (C) 1999-2008 Microsoft Corporation. On computer: MyPC DISKPART> list disk Disk ### Status Size Free Dyn Gpt -------- ------------- ------- ------- --- --- Disk 0 Online 2047 MB 1920 KB * Disk 1 Online 24 GB 0 B DISKPART> exit Leaving DiskPart... | |||||
Of course, using a disk editor, such as the free HxD or the free demo version of WinHex (or, the more recent, Active@ Disk Editor; TestDisk also understands GPT drives) is the best way to examine the actual contents of your disk drive(s) and see all the details presented below. The Active@ Disk Editor has the best presentation of the data found in these sectors, but we have not found its disk editing tools as easy to use as those in HxD; we use either the 'templates' in WinHex or the Active@DiskEditor to find the precise location of what we wish to copy and then use HxD to do so.
When a disk is initialized as GPT by Windows 7 (8 or 10), the first sector (Absolute Sector 0) still contains the same boot code as a Windows 7/8/10 MBR initialized disk drive, but with this exception: The NT Disk Signature is set to zero ("00 00 00 00" as shown in Figure 1 below). Note, however, that connecting such a drive to a Windows XP (and perhaps others) PC, will result in an NT Disk Signature being assigned to the drive. The partition table contains only a single "GPT Protective" entry which in all cases is set to the maximum 32-bit limitation (even though a drive may have far less than a 2.2 TB capacity). The "GPT Protective MBR Sector" has exactly the same contents for all GPT disk drives created by the Windows 7, 8 or 10 OS. But, note: This does not follow the UEFI Specification, which states that the "SizeInLBA" should be "set to the size of the disk minus one" if it's not too large to be represented.[1] (GPT drives partitioned under various Linux and Apple® Mac OS systems do follow the UEFI Specification in this regard.)
Figure 2 shows how to interpret this 16-byte Partition Table entry in Figure 1: The first byte ("00") at offset 1BEh means not bootable (but this is only to ensure a legacy BIOS or OS will not attempt to boot from this drive; EFI/UEFI BIOS do not use this byte!), the next three bytes ("00 02 00") indicate the partition starts at CHS (0,0,2) or Absolute Sector 1 (this is where the GPT Header is located). The Partition Type byte at offset 1C2h ("EE") indicates this is a GPT partitioned disk. The next three bytes hold the CHS Ending values which were only used if the partition didn't end beyond 16,450,560 sectors (or about 8.4 GB). Otherwise, it was agreed to fill these bytes with "FE FF FF" (CHS values 1023, 254 and 63, for a total of: 1024 cylinders, 255 heads and 63 sectors); see our note on the MS-DOS Head Count Error for the reason all BIOS companies standardized the head count at 255 instead of 256. But here we have an 'FF' in every byte: FF FF FF". Though used only to ensure no legacy utility or OS will find any unpartitioned space on the disk, by always filling this field with 0xFFFFFF, the Windows 7 (or 8) OS is not following the UEFI Specification which states the EndingCHS should be "set to the CHS address of the last logical block on the disk" unless it's too large to be represented.[2] The next 4 bytes in the first GREEN box ("01 00 00 00") indicate the number of sectors which precede the partition (sometimes called "Relative Sectors"); so, one sector: The MBR. And the last 4 bytes ("FF FF FF FF") indicate a partition size of 4,294,967,295 sectors. As we mentioned above, Windows 7 always fills this field with 0xFFFFFFFF, even though the UEFI Specification states this should be "set to the size of the disk minus one" for drives under 2.2 TB.[3]
The GPT Header immediately follows the MBR, so it's in Absolute or LBA Sector 1; the second Sector on the drive. Figure 3 shows a Disk Editor View (or 'Hex Dump') of an example GPT Header of only its 92 bytes of data:
The GPT Header data is found only in the first 92 bytes of this zero-padded sector. |
---|
Absolute (LBA) Sector 1 (Cylinder 0, Head 0, Sector 2)
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F (Offsets in Hex)
------ -----------------------------------------------
0000 45 46 49 20 50 41 52 54 00 00 01 00 5C 00 00 00 EFI PART....\...
0010 C8 03 40 5B 00 00 00 00 01 00 00 00 00 00 00 00 ..@[............
0020 EF FF 3F 00 00 00 00 00 22 00 00 00 00 00 00 00 ..?.....".......
0030 CE FF 3F 00 00 00 00 00 5E 86 90 EF D0 30 03 46 ..?.....^....0.F
0040 99 3D 54 6E B0 E7 1B 0D 02 00 00 00 00 00 00 00 .=Tn............
0050 80 00 00 00 80 00 00 00 1E C5 0F B7 ............
-----------------------------------------------
0 1 2 3 4 5 6 7 8 9 A B C D E F |
The GPT Header always begins with the 8-byte EFI "Signature" string: "45 46 49 20 50 41 52 54" (ASCII: "EFI PART"); declared in the UEFI Specification as the 64-bit Hex constant: "0x5452415020494645". The following table explains every byte in this Header:
Specifications for the GPT Header Sector | ||
---|---|---|
Offset (Hex) | Length (bytes) | Contents |
000 | 8 | Signature: Identifies this as an EFI-compatible GPT Header; must contain the ASCII string: "EFI PART" |
008 | 4 | Revision: Revision number for this header. This revision is not related to the UEFI Specification version. The current GPT Header version is still 1.00 (as of June 2021), so 0x00010000 (or "00 00 01 00") is the correct value. |
00C | 4 | HeaderSize: Size in bytes; usually 92 (5Ch), the field being filled with: "5C 00 00 00". The UEFI Spec now states this "must be greater than or equal to 92 and must be less than or equal to the logical block size."[4]. |
010 | 4 | HeaderCRC32: CRC32 of the GPT Header, with this field zeroed during calculation. ( In our example above, this is "C8 03 40 5B". See below: Calculating the CRC32 Checksums.) |
014 | 4 | Reserved; must be set to zero ("00 00 00 00"). |
018 | 8 | MyLBA: LBA location of this GPT Header. (Most often 0x0000000000000001.) |
020 | 8 | AlternateLBA: LBA address of the alternate GPT Header (i.e., the location of the backup copy of this header). Note: That EFI Header will have its own 'MyLBA' location and also its own CRC32 checksum, and in fact, will point to where this EFI Header is located in its 'AlternateLBA' field. [ In our example above, the "EF FF 3F 00 00 00 00 00" points to Sector 4194287.] |
028 | 8 | FirstUsableLBA: First usable LBA Sector for any partition; equal to: 1 + the last LBA Sector of the Primary GUID Partition Table. Most often Sector 34 (0x0000000000000022), which is "22 00 00 00 00 00 00 00" in our example above. |
030 | 8 | LastUsableLBA: Last usable LBA Sector for any partitions; equal to: The first LBA Sector of the Secondary Partition Table - 1. In our example above, this is Sector 4194254 ("CE FF 3F 00 00 00 00 00"). |
038 | 16 | DiskGUID: Disk GUID (Globally Unique IDentifier; also referred as UUID, UniversallyUID, on UNIXes) for this physical disk drive. In our example above this is the whole 16 byte string of "5E 86 90 EF D0 30 03 46 99 3D 54 6E B0 E7 1B 0D" (or 0x0d1be7b06e543d99460330d0ef90865e). |
048 | 8 | PartitionEntryLBA: Starting LBA of the array of GUID Partition entries; most often Sector 2 for the Primary Partition. ("02 00 00 00 00 00 00 00" in our example above.) |
050 | 4 | NumberOfPartitionEntries: Number of Partition Entries in the GUID Partition Entry array. Most often 0x00000080 (which is 128). |
054 | 4 | SizeOfPartitionEntry: Size, in bytes, of each GUID Partition Entry. This field should be set to a value of: 128 x 2n where n is an integer greater than or equal to zero (thus, although this is usually set to 128, it may also be 256, 512, etc.)[5]. 0x00000080 (80 hex) = 128. |
058 | 4 | PartitionEntryArrayCRC32: CRC32 of the GUID Partition Array. ("Starts at PartitionEntryLBA and is computed over a byte length of NumberOfPartitionEntries * SizeOfPartitionEntry.") In our example above, this is "1E C5 0F B7" (or 0xb70fc51e). |
05C | (BlockSize - 92) | Reserved; the remainder of the block is reserved by UEFI and must be padded with zero bytes. |
The CRC32 checksum for the example GPT Header in Figure 3 (hex offsets 00 through 5B or 0x5C = 92 bytes; with offsets 10 - 13 zeroed out) is: 0x5b4003c8 ("C8 03 40 5B" being the on disk little-endian representation of this hexadecimal number). This can be verified by using HxD's "Analysis" -> "Checksums..." tool as follows: Temporarily change the bytes at hex offsets 10 - 13 to zero bytes (shown in RED in Figure 4 below), select all 92 bytes (as indicated by the BLUE highlighting), then choose to perform a "CRC-32" checksum (not 'Checksum-32') operation on the selected bytes:
Figure 4. | Figure 5. | |
Figure 6. |
This sample VHD file (in a 524 KB Zip; MD5 = 0F51223DE96281F9F9133B19E4B5F715) is roughly the smallest size VHD drive (about 128 MB) one can create using Windows 10 Disk Management. Apart from the GPT Header and GUID Partition Array, it also contains a 16 MB "MS Reserved" partition required when using Microsoft Windows to create a GPT VHD (which is full of nothing by zero bytes, since this disk is not bootable) and three PNG files in a volume labeled "Mini_GPT_Drive" (the 3 pictures show data about this VHD Disk in FTK Imager, and the exact values of its GPT Header and Partition Entries in two colorful table displays).
Taking a quick look at its GPT Header Sector (the 2nd sector in the file), we find:
The GPT Header data for the SEDGPT.vhd file: |
---|
Absolute (LBA) Sector 1 (Cylinder 0, Head 0, Sector 2)
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F (Offsets in Hex)
------ -----------------------------------------------
0000 45 46 49 20 50 41 52 54 00 00 01 00 5C 00 00 00 EFI PART....\...
0010 85 7C CD 4B 00 00 00 00 01 00 00 00 00 00 00 00 .|.K............
0020 FF FF 03 00 00 00 00 00 22 00 00 00 00 00 00 00 ........".......
0030 DE FF 03 00 00 00 00 00 15 56 25 BB 7A 32 E3 4E .........V%.z2.N
0040 94 24 31 C7 6B 8A 90 79 02 00 00 00 00 00 00 00 .$1.k..y........
0050 80 00 00 00 80 00 00 00 92 EB D9 FE ........�...
0 1 2 3 4 5 6 7 8 9 A B C D E F |
In the figure above, only those values which often change have been color highlighted: The CRC32 for the GPT Header ("85 7C CD 4B" in this case), the location of the backup copy of this Header ("FF FF 03" which is: 0x3FFFF or Sector 262,143; that Backup Headers AlternateLBA pointing to Sector 1), the LastUsableLBA is Sector 262,110 (0x3FFDE; "DE FF 03"), the DiskGUID of: "15 56 25 BB 7A 32 E3 4E 94 24 31 C7 6B 8A 90 79" and the CRC32 of its following GUID Partition Array ("92 EB D9 FE" in this case).
The GPT Header is (usually) followed immediately by the GUID Partition Table Array and its entries, so it's in Absolute or LBA Sector 2 and following; the third Sector on the drive. Each Partition Entry is comprised of exactly 128 bytes; which allows for 4 entries per sector, and 128 entries total in 32 sectors. Figure 8 shows a Disk Editor View (or 'Hex Dump') of our Sample VHD disks partitions (there are only two):
The GUID Partition Table Array; found immediately after the GPT Header. |
---|
Absolute (LBA) Sector 2 (Cylinder 0, Head 0, Sector 3) Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F (Offsets in Hex) ------ ----------------------------------------------- 0400 16 E3 C9 E3 5C 0B B8 4D 81 7D F9 2D F0 02 15 AE ....\..M.}.-.... 0410 99 12 1A 3D AB 13 B9 45 B5 87 DF 9B DB 08 67 AE .......E......g. 0420 22 00 00 00 00 00 00 00 FF 7F 00 00 00 00 00 00 "............... 0430 00 00 00 00 00 00 00 00 4D 00 69 00 63 00 72 00 ........M.i.c.r. 0440 6F 00 73 00 6F 00 66 00 74 00 20 00 72 00 65 00 o.s.o.f.t. .r.e. 0450 73 00 65 00 72 00 76 00 65 00 64 00 20 00 70 00 s.e.r.v.e.d. .p. 0460 61 00 72 00 74 00 69 00 74 00 69 00 6F 00 6E 00 a.r.t.i.t.i.o.n. 0470 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0480 A2 A0 D0 EB E5 B9 33 44 87 C0 68 B6 B7 26 99 C7 ��....3D..h.�&.. 0490 68 85 20 C3 30 BB 13 4D 82 DF 24 2B 56 C7 25 6F h. .0..M�.$+V.%o 04A0 00 80 00 00 00 00 00 00 FF EF 03 00 00 00 00 00 ................ 04B0 00 00 00 00 00 00 00 00 42 00 61 00 73 00 69 00 ........B.a.s.i. 04C0 63 00 20 00 64 00 61 00 74 00 61 00 20 00 70 00 c. .d.a.t.a. .p. 04D0 61 00 72 00 74 00 69 00 74 00 69 00 6F 00 6E 00 a.r.t.i.t.i.o.n. 04E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ----------------------------------------------- 0 1 2 3 4 5 6 7 8 9 A B C D E F |
As you can see in the figure above, most of the bytes are taken up by the partitions technical description. These are not volume labels, but rather a set Partition TYPE with a unique GUID.[7] Thus, whenever the GUID E3C9E316-0B5C-4DB8-817D-F92DF00215AE ("16 E3 C9 E3 5C 0B B8 4D 81 7D F9 2D F0 02 15 AE" in the figure above) appears on a GPT disk, it always refers to an MSR (or Microsoft Reserved) Partition. Likewise, the GUID EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 ("A2 A0 D0 EB E5 B9 33 44 87 C0 68 B6 B7 26 99 C7" in the second entry) is normally associated with a Microsoft "Basic Data Partition" For more on these unique GUIDs, see: GUID Partition Table (at Wikipedia).
Specifications for a GPT Partition Table Array Entry (128-Bytes) | ||
---|---|---|
Offset (Hex) | Length (bytes) | Contents |
000 | 16 | 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." This is similar to the "Partition Type" byte in the older MBR Sector; which had a maximum of only 255 types available (one Hex byte). But now every file system should have its own unique ID. |
010 | 16 | UniquePartitionGUID: A "GUID that is unique for every partition entry. Every partition ever created will have a unique GUID. This GUID must be assigned when the GPT Partition Entry is created." (Note: This is completely independent of say an NTFS Volumes 8-byte Serial Number.) |
020 | 8 | StartingLBA: "Starting LBA [First Sector] of the partition defined by this entry." For our Sample VHD file, the Data Partition begins at "00 80" (0x8000) or Sector 32,768. |
028 | 8 | EndingLBA: "Ending LBA [Last Sector] of the partition defined by this entry." The Data Partition of our Sample VHD file ends with Sector 258,047, or: "FF EF 03" (0x3EFFF). This includes the NTFS Volumes Backup Boot Sector and any Volume Slack Space. |
030 | 8 | Attributes Reserved (normally all zero bytes); "all bits reserved by UEFI." |
038 | 72 | PartitionName: "Null-terminated [zero-byte] string containing a human-readable name of the partition." The name may be no more than 71 bytes plus the required zero byte at the end, and all the bytes after the name should be zero-byte padded. |
After the above, the UEFI Specification has "(SizeOfPartitionEntry - 128)" for any entries that may exceed 128 bytes: "The rest of the GPT Partition Entry, if any, is reserved by UEFI and must be zero [bytes]." But: As in our example above, and for all the entries we've encountered, they have always been only 128 bytes long. Have you seen a disk drive with entries larger than 128 bytes?
1[Return to
Text] Reference and full quote: Unified Extensible Firmware Interface Specification, Version 2.7, May 2017, which states in Chapter 5, GUID Partition
Table (GPT) Disk Layout, Section 5.2.3, Protective MBR, Table 16. Protective MBR Partition Record protecting the entire disk, SizeInLBA,
on page 129: "Set to the size of the disk minus one. Set to 0xFFFFFFFF if the size of the disk is too large to be represented in this
field." Since Microsoft uses the same entry for drives smaller than 2.2 TB as it does for those over 2.2 TB, they are not following the UEFI
Specification for SizeInLBA.
You can download the latest UEFI Specification here.
2[Return to Text] Reference and full quote: Unified Extensible Firmware Interface Specification, Version 2.7, May 2017, which states in Chapter 5, GUID Partition Table (GPT) Disk Layout, Section 5.2.3, Protective MBR, Table 16. Protective MBR Partition Record protecting the entire disk, 5, EndingCHS, on page 129: "Set to the CHS address of the last logical block on the disk. Set to 0xFFFFFF if it is not possible to represent the value in this field." Since Microsoft uses the same exact CHS values for drives smaller than 2.2 TB as it does for those over 2.2 TB, they are not following the UEFI Specification for the EndingCHS values.
3[Return to Text] See Footnote # 1.
4[Return to Text] See any recent version. At some point prior to at least Version 2.6, UEFI decided to change the Spec by adding the words "or equal to". (But when we first examined the Spec, specifically, Version 2.3.1, Errata C, June 27, 2012, it stated on page 104, in Table 16: "The HeaderSize must be greater than 92." And after contacting the UEFI organization, they assured us the Specification did in fact mean a value larger than 92 bytes should be used; when the logical block size was 512 bytes). Yet, every GPT partitioned drive we examined, whether it was partitioned by a Microsoft Windows 7 or 8 OS, a Linux utility such as GParted or even an Apple Mac OSX machine, had exactly 92 bytes ("5C 00 00 00") in this field. Presumably, this is why one program even states, incorrectly, of the Header Size field: "should be 92" (according to WinHex in a demo version downloaded on 3 JAN 2013; and still does so in 2021 in its "GUID Partition Table.tpl" file).
5[Return to Text] In addition, the official UEFI Specification concerning SizeOfPartitionEntry, still contains: "NOTE: Previous versions of this specification allowed any multiple of 8." (Unified Extensible Firmware Interface Specification, Version 2.9, March 2021, page 135, Table 17. GPT Header).
6[Return to Text] The format of VHD files created by Microsoft utilities is specified on their website here. Their VHD files always include at least one more sector beyond the actual contents of a disk drive which has the name "connectix" in it; heres the beginning of the last sector of our 128 MB sample file:
Offset 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F (Hex) 08000000 63 6F 6E 65 63 74 69 78 00 00 00 02 00 01 00 00 conectix........ 08000010 FF FF FF FF FF FF FF FF 28 6B 97 7F 77 69 6E 20 ........(k�.win 08000020 00 0A 00 00 57 69 32 6B 00 00 00 00 08 00 00 00 ....Wi2k........ 08000030 00 00 00 00 08 00 00 00 03 C3 10 11 00 00 00 02 ................ 08000040 FF FF E8 04 6E 93 CB 76 18 1E 76 4D 83 AD 55 33 ....n..v..vM..U3 08000050 D2 50 CA 4D 00 00 00 00 00 00 00 00 00 00 00 00 .P.M............ |
7[Return to Text] When discussing a particular GUID (Globally Unique Identifier; or, UUID), its normally written as parts separated by dashes in a text or enclosed in brackets ("{GUID}") when displayed in a Windows Registry Editor. However, the first three (3) parts; which are numerical values, are always converted to "little-endian" when stored on a disk for operating systems using that storage method. The remainder of the GUID appears in the same byte order, because those parts are arrays ; not numbers (similar to how "EFI PART" at the beginning of the GPT Header and the Partition Type names appear in readable, left-to-right, ASCII format).
Created: December 9, 2012 (09.12.2012).
Updated: December 10, 2012 (10.12.2012); December 27, 2012 (27.12.2012); January 7, 2013 (07.01.2013);
31 JAN 2017 (31.01.2017); 12 JUN 2021 (12.06.2021).
Last Update: July 5, 2021 (05.07.2021); added 128MB .VHD file for downloading.
You can write to me using this: contact
page (opens in a new window).
MBR and Boot Records Index
The Starman's Realm Index Page