November 05, 2015Networking for Systems Engineers
Calculating CRC32 for GPT Volumes.
Today while having to manually calculate the CRC for the GPT header and the GPT partition table, I was unable to find how to perform such actions manually (by hand literally…).
GPT Volume Structure (Wikipedia Link(link is external))
From the image we can see, we can tell we have:
- 512 Bytes worth of emptiness (Protective MBR, ending in 55AA).
- 512 Bytes worth of the GPT Header.
- 92 bytes is the actual header the rest is unused.
- 128 Bytes that represent each partition.
(The previous copied at the end of the drive backwards).
|0 (0x00)||8 bytes||Signature (“EFI PART”, 45h 46h 49h 20h 50h 41h 52h 54h or 0x5452415020494645ULL[a](link is external) on little-endian(link is external) machines)|
|8 (0x08)||4 bytes||Revision (for GPT version 1.0 (through at least UEFI version 2.3.1), the value is 00h 00h 01h 00h)|
|12 (0x0C)||4 bytes||Header size in little endian (in bytes, usually 5Ch 00h 00h 00h or 92 bytes)|
|16 (0x10)||4 bytes||CRC32(link is external)/zlib of header (offset +0 up to header size) in little endian, with this field zeroed during calculation|
|20 (0x14)||4 bytes||Reserved; must be zero|
|24 (0x18)||8 bytes||Current LBA (location of this header copy)|
|32 (0x20)||8 bytes||Backup LBA (location of the other header copy)|
|40 (0x28)||8 bytes||First usable LBA for partitions (primary partition table last LBA + 1)|
|48 (0x30)||8 bytes||Last usable LBA (secondary partition table first LBA – 1)|
|56 (0x38)||16 bytes||Disk GUID (also referred as UUID(link is external) on UNIXes)|
|72 (0x48)||8 bytes||Starting LBA of array of partition entries (always 2 in primary copy)|
|80 (0x50)||4 bytes||Number of partition entries in array|
|84 (0x54)||4 bytes||Size of a single partition entry (usually 80h or 128)|
|88 (0x58)||4 bytes||CRC32/zlib of partition array in little endian|
|92 (0x5C)||*||Reserved; must be zeroes for the rest of the block (420 bytes for a sector size of 512 bytes; but can be more with larger sector sizes)|
From Wikipedia, we can see the great table above that represents all the contents of the GPT header, for this, let’s check what the structure of a partition entry is so we can move on with a good base.
|0 (0x00)||16 bytes||Partition type GUID|
|16 (0x10)||16 bytes||Unique partition GUID|
|32 (0x20)||8 bytes||First LBA (little endian(link is external))|
|40 (0x28)||8 bytes||Last LBA (inclusive, usually odd)|
|48 (0x30)||8 bytes||Attribute flags (e.g. bit 60 denotes read-only)|
|56 (0x38)||72 bytes||Partition name (36 UTF-16(link is external)LE code units)|
Just for completeness
|0||Platform required (required by the computer to function properly, OEM partition for example, disk partitioning(link is external) utilities must preserve the partition as is)|
|1||EFI firmware should ignore the content of the partition and not try to read from it|
|2||Legacy BIOS bootable (equivalent to active flag (typically bit 7 set) at offset +0h(link is external) in partition entries of the MBR partition table(link is external))(link is external)|
|3–47||Reserved for future use|
|48–63||Defined and used by the individual partition type|
|61||Shadow copy (of another partition)|
|63||No drive letter (i.e. do not automount)|
How do I make sure I get a valid GPT Partition Table?
First, make sure you are familiar with dd (data destroyer haha) is an excellent tool, and you should be familiar with it if you’re going to be playing with data on a hard drive hands-on.
Quick recap: seek, skip, bs, count, conv, if, of, should all be known to you by hand, blindfolded.
- seek: skip BLOCKS obs-sized blocks at start of output file.
- skip: skip BLOCKS obs-sized blocks at start of input file.
- count: copy only BLOCKS input blocks.
- conv: convert the file as per the comma-separated symbol list.
- bs: read and write BYTES at a time.
- if: input file.
- of: output file.
- conv=notrunc: I’m mentioning this one specifically since its 100% required to AVOID blowing up your data all at once successfully.
You will need a crc32 application to perform the calculation on dd generated binaries also because we’re going to have to write that data by hand to the files. And also, I’d recommend looking into an excuse to edit those files manually.
Remember that MANY times you’ll have to know that data on the hard drive is written backward as we usually write it in natural language. For example, if our CRC result were to be the following hex (F7E58D1F we would separate in bytes so F7 E5 8D 1F, then we’d write it as follows: 1F 8D E5 F7 in the hex editor in the appropriate places, so yeah, REMEMBER not a mirror but byte-backward, so if you do F1D85E7F you did it wrong!).
So let’s take, for example, a dump of the GPT Header and Partition table, so that’d be: 16896 bytes or 33 sectors, which would be dividing the number of bytes by 512.
Using OKTETA in Linux, you can find a quick way to calculate the checksum of a highlighted part of the dump, as the next screenshot shows.