10: GPTs; the FAT filesystem

Announcement

Hadi was out of town briefly earlier this week. He's catching up now on the regrade requests. Please be patient, I promise we'll get to things eventually.

We're hoping to have the midterm graded by next class.

GPTs

Modern PCs and Macs use the GUID Partition Table (GPT) standard on fixed hard disks. The GPT is a more sophisticated system that parallels the MBR in many ways but fixes many of its problems.

A GPT-formatted disk is laid out as follows:

GUID partition table

(Image copyright © 2007 Wikimedia Commons and used under Attribution-ShareAlike 2.5 Generic (CC BY-SA 2.5).)

Note that the GPT is duplicated at the start and end of disk, and supposed to be kept in sync. This is a backup to mitigate data corruption.

Also note that there's a "protective MBR". What's that about? If you put a GPT-formatted disk into a MBR-only computer, it contains dummy values (a single maximum size partition of type 0xEE) so that the disk shows up as formatted. Hey, what were those bytes on my Mac's "MBR"? Remember, the first partition starts at 0x1BE:

hexdump -Cv -n 512 disk-image.dd 
00000000  33 c0 8e d0 bc 00 7c 8e  c0 8e d8 be 00 7c bf 00  |3.....|......|..|
00000010  06 b9 00 02 fc f3 a4 50  68 1c 06 cb fb b9 04 00  |.......Ph.......|
00000020  bd be 07 80 7e 00 00 7c  0b 0f 85 0e 01 83 c5 10  |....~..|........|
00000030  e2 f1 cd 18 88 56 00 55  c6 46 11 05 c6 46 10 00  |.....V.U.F...F..|
00000040  b4 41 bb aa 55 cd 13 5d  72 0f 81 fb 55 aa 75 09  |.A..U..]r...U.u.|
00000050  f7 c1 01 00 74 03 fe 46  10 66 60 80 7e 10 00 74  |....t..F.f`.~..t|
00000060  26 66 68 00 00 00 00 66  ff 76 08 68 00 00 68 00  |&fh....f.v.h..h.|
00000070  7c 68 01 00 68 10 00 b4  42 8a 56 00 8b f4 cd 13  ||h..h...B.V.....|
00000080  9f 83 c4 10 9e eb 14 b8  01 02 bb 00 7c 8a 56 00  |............|.V.|
00000090  8a 76 01 8a 4e 02 8a 6e  03 cd 13 66 61 73 1c fe  |.v..N..n...fas..|
000000a0  4e 11 75 0c 80 7e 00 80  0f 84 8a 00 b2 80 eb 84  |N.u..~..........|
000000b0  55 32 e4 8a 56 00 cd 13  5d eb 9e 81 3e fe 7d 55  |U2..V...]...>.}U|
000000c0  aa 75 6e ff 76 00 e8 8d  00 75 17 fa b0 d1 e6 64  |.un.v....u.....d|
000000d0  e8 83 00 b0 df e6 60 e8  7c 00 b0 ff e6 64 e8 75  |......`.|....d.u|
000000e0  00 fb b8 00 bb cd 1a 66  23 c0 75 3b 66 81 fb 54  |.......f#.u;f..T|
000000f0  43 50 41 75 32 81 f9 02  01 72 2c 66 68 07 bb 00  |CPAu2....r,fh...|
00000100  00 66 68 00 02 00 00 66  68 08 00 00 00 66 53 66  |.fh....fh....fSf|
00000110  53 66 55 66 68 00 00 00  00 66 68 00 7c 00 00 66  |SfUfh....fh.|..f|
00000120  61 68 00 00 07 cd 1a 5a  32 f6 ea 00 7c 00 00 cd  |ah.....Z2...|...|
00000130  18 a0 b7 07 eb 08 a0 b6  07 eb 03 a0 b5 07 32 e4  |..............2.|
00000140  05 00 07 8b f0 ac 3c 00  74 09 bb 07 00 b4 0e cd  |......<.t.......|
00000150  10 eb f2 f4 eb fd 2b c9  e4 64 eb 00 24 02 e0 f8  |......+..d..$...|
00000160  24 02 c3 49 6e 76 61 6c  69 64 20 70 61 72 74 69  |$..Invalid parti|
00000170  74 69 6f 6e 20 74 61 62  6c 65 00 45 72 72 6f 72  |tion table.Error|
00000180  20 6c 6f 61 64 69 6e 67  20 6f 70 65 72 61 74 69  | loading operati|
00000190  6e 67 20 73 79 73 74 65  6d 00 4d 69 73 73 69 6e  |ng system.Missin|
000001a0  67 20 6f 70 65 72 61 74  69 6e 67 20 73 79 73 74  |g operating syst|
000001b0  65 6d 00 00 00 63 7b 9a  7d 6e 00 00 00 00 00 fe  |em...c{.}n......|
000001c0  ff ff ee fe ff ff 01 00  00 00 a3 70 3d 3a 00 00  |...........p=:..|
000001d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|

00 fe ff ff *ee* fe ff ff 01 00 00 00 a3 70 3d 3a

ee! Well, there you go then.

Where's the actual GPT data? It starts in a header in the next sector.

https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_table_header_.28LBA_1.29

dd if=disk-image.dd bs=512 count=1 skip=1 | hexdump -Cv
1+0 records in
1+0 records out
512 bytes transferred in 0.000016 secs (31580642 bytes/sec)
00000000  45 46 49 20 50 41 52 54  00 00 01 00 5c 00 00 00  |EFI PART....\...|
00000010  7f 95 63 62 00 00 00 00  01 00 00 00 00 00 00 00  |..cb............|
00000020  a3 70 3d 3a 00 00 00 00  22 00 00 00 00 00 00 00  |.p=:....".......|
00000030  82 70 3d 3a 00 00 00 00  a8 4d 00 00 93 38 00 00  |.p=:.....M...8..|
00000040  3d 11 00 00 f3 62 00 00  02 00 00 00 00 00 00 00  |=....b..........|
00000050  80 00 00 00 80 00 00 00  81 d5 7a 4e 00 00 00 00  |..........zN....|
00000060  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000070  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000080  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000100  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000110  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000120  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000130  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000140  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000150  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000160  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000170  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000180  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000190  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000200

Note, for example, we have the right header (EFI PART), and that the partition entries (partition table) offset is located at byte 0x48 and is equal to 2 (that is, it's at the next sector on the disk). There's also a 4-byte value for the number of entries and the size of each entry at 0x50 and 0x54 (very much like the IFD). In this image, there are 128 entries (little endian: 08 00 00 00) each 128 bytes long (which is typical).

Let's pull out the next sector to see the first few entries:

dd if=disk-image.dd bs=512 count=1 skip=2 | hexdump -Cv
1+0 records in
1+0 records out
512 bytes transferred in 0.000478 secs (1071599 bytes/sec)
00000000  28 73 2a c1 1f f8 d2 11  ba 4b 00 a0 c9 3e c9 3b  |(s*......K...>.;|
00000010  e3 22 00 00 4b 2b 00 00  1e 43 00 00 72 0b 00 00  |."..K+...C..r...|
00000020  28 00 00 00 00 00 00 00  27 40 06 00 00 00 00 00  |(.......'@......|
00000030  00 00 00 00 00 00 00 00  45 00 46 00 49 00 20 00  |........E.F.I. .|
00000040  73 00 79 00 73 00 74 00  65 00 6d 00 20 00 70 00  |s.y.s.t.e.m. .p.|
00000050  61 00 72 00 74 00 69 00  74 00 69 00 6f 00 6e 00  |a.r.t.i.t.i.o.n.|
00000060  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000070  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000080  72 6f 74 53 67 61 aa 11  aa 11 00 30 65 43 ec ac  |rotSga.....0eC..|
00000090  41 5a 00 00 e1 30 00 00  8a 74 00 00 df 60 00 00  |AZ...0...t...`..|
000000a0  28 40 06 00 00 00 00 00  7f 9a e1 22 00 00 00 00  |(@........."....|
000000b0  00 00 00 00 00 00 00 00  49 00 72 00 6f 00 6e 00  |........I.r.o.n.|
000000c0  00 00 6d 00 65 00 72 00  00 00 00 00 00 00 00 00  |..m.e.r.........|
000000d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000100  74 6f 6f 42 00 00 aa 11  aa 11 00 30 65 43 ec ac  |tooB.......0eC..|
00000110  40 0b 46 a0 6e 7e 24 42  91 02 75 57 32 ab c9 dd  |@.F.n~$B..uW2...|
00000120  80 9a e1 22 00 00 00 00  9f f9 f4 22 00 00 00 00  |..."......."....|
00000130  00 00 00 00 00 00 02 00  52 00 65 00 63 00 6f 00  |........R.e.c.o.|
00000140  76 00 65 00 72 00 79 00  20 00 48 00 44 00 00 00  |v.e.r.y. .H.D...|
00000150  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000160  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000170  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000180  00 53 46 48 00 00 aa 11  aa 11 00 30 65 43 ec ac  |.SFH.......0eC..|
00000190  c0 34 9b 30 09 0b fb 41  95 02 8b 95 10 1f 4e 41  |.4.0...A......NA|
000001a0  00 00 f5 22 00 00 00 00  7f 70 39 3a 00 00 00 00  |...".....p9:....|
000001b0  00 00 00 00 00 00 00 00  41 00 70 00 70 00 6c 00  |........A.p.p.l.|
000001c0  65 00 5f 00 48 00 46 00  53 00 5f 00 55 00 6e 00  |e._.H.F.S._.U.n.|
000001d0  74 00 69 00 74 00 6c 00  65 00 64 00 5f 00 32 00  |t.i.t.l.e.d._.2.|
000001e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000200

Entries look like: https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_entries

Let's look at the first few:

00000000  28 73 2a c1 1f f8 d2 11  ba 4b 00 a0 c9 3e c9 3b  |(s*......K...>.;|
00000010  e3 22 00 00 4b 2b 00 00  1e 43 00 00 72 0b 00 00  |."..K+...C..r...|
00000020  28 00 00 00 00 00 00 00  27 40 06 00 00 00 00 00  |(.......'@......|
00000030  00 00 00 00 00 00 00 00  45 00 46 00 49 00 20 00  |........E.F.I. .|
00000040  73 00 79 00 73 00 74 00  65 00 6d 00 20 00 70 00  |s.y.s.t.e.m. .p.|
00000050  61 00 72 00 74 00 69 00  74 00 69 00 6f 00 6e 00  |a.r.t.i.t.i.o.n.|
00000060  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000070  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

Each entry starts with a 16-byte partition type GUID. This one's is: 28 73 2a c1 1f f8 d2 11 ba 4b 00 a0 c9 3e c9 3b. Hmm, it doesn't seem to be in the list at https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs. What might it be? Turns out it's: an EFI System Partition (spoiler: the name is stored as UTF-16LE text!). https://en.wikipedia.org/wiki/EFI_system_partition. Bootable drives in UEFI systems put the bootloader and associated utilities on this partition, which is FAT-lie (though actually standardized as part of UEFI, so not exactly FAT). Different OSes put different stuff here; it's a standardized, extensible way to get more than the 446 bytes the MBR provided for a full-featured boot loader (and whatever else your OS provider wants to give you).

At 0x10, the next 16 bytes are a unique-to-this-partition-on-this-computer GUID.

At 0x20, there are 8 bytes (LE) telling you the first LBA of this partition, then 8 bytes telling you the last (inclusive).

struct.unpack('<QQ', bytes.fromhex('28 00 00 00 00 00 00 00  27 40 06 00 00 00 00 00'))
# => (40, 409639)

Again, does that match what mmls told us?

mmls /dev/rdisk0
GUID Partition Table (EFI)
Offset Sector: 0
Units are in 512-byte sectors

      Slot      Start        End          Length       Description
000:  Meta      0000000000   0000000000   0000000001   Safety Table
001:  -------   0000000000   0000000039   0000000040   Unallocated
002:  Meta      0000000001   0000000001   0000000001   GPT Header
003:  Meta      0000000002   0000000033   0000000032   Partition Table
004:  000       0000000040   0000409639   0000409600   EFI system partition
005:  001       0000409640   0585210495   0584800856   Iron
006:  002       0585210496   0586480031   0001269536   Recovery HD
007:  -------   0586480032   0586481663   0000001632   Unallocated
008:  003       0586481664   0976842879   0390361216   Apple_HFS_Untitled_2
009:  -------   0976842880   0977105059   0000262180   Unallocated

Yup, exactly right. Then 8 bytes of "attribute flags," with only the first three bits being universally defined so far, and the last 16 defined by each partition type. Finally at 0x38 the partition name, in 72 bytes of UTF-16LE encoded text.

The next one looks like:

00000080  72 6f 74 53 67 61 aa 11  aa 11 00 30 65 43 ec ac  |rotSga.....0eC..|
00000090  41 5a 00 00 e1 30 00 00  8a 74 00 00 df 60 00 00  |AZ...0...t...`..|
000000a0  28 40 06 00 00 00 00 00  7f 9a e1 22 00 00 00 00  |(@........."....|
000000b0  00 00 00 00 00 00 00 00  49 00 72 00 6f 00 6e 00  |........I.r.o.n.|
000000c0  00 00 6d 00 65 00 72 00  00 00 00 00 00 00 00 00  |..m.e.r.........|
000000d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

This is an Apple partition, and you can see it's named "Iron", which is my Mac's primary partition's name.

If we kept going, you'd see that unused entries are zeroed out (that is, they consist entirely of bytes set to the value 00).

So you get the idea here, anyway. GPTs are a fairly straightforward binary data structure to store hard disk partition information. They're slightly more complex than MBRs, but they don't require the contortions of MBRs (which is a legacy format originally designed for computers and disks over 30 years ago!).

So that's it for lecture content on volumes and partitions, though you will probably want to Read the Book, supplemented with more recent web resources, for the fine details of MBRs and GPTs.

Filesystems

Filesystems are provided by operating systems to programs (and ultimately, to users). They provide a mechanism to store data in a structured way, usually organized around "files" and "directories".

The filesystem doesn't worry about the internal structure of files (like the JPEGs we've dealt with); it treats them as blobs of bytes to be stored and retrieved when requested.

The filesystem instead manages the files that are stored and the space in which they are stored. Minimally, a file system must be able to store, retrieve, and remove data from a partition corresponding to a particular file. To do so, it must keep track of:

  • free and allocated space within the partition that it is responsible for;
  • the location of each file within the partition
  • the user-visible name of each file (the filename)
  • the user-visible location of each file (the path to the file)

Carrier refers to these items as essential and therefore "more trustworthy" in some sense than nonessential items. The reasoning here is that the above must be correct, or the filesystem isn't fulfilling its basic purpose.

Filesystems might also track many other items of metadata including:

  • creation, modification, or last-accessed time
  • ownership information
  • permissions (readable, writeable, executable, by who?)

Carrier provides a broad overview of the analysis techniques you might use at an abstract level in Chapter 8; we're going to jump right into the details of the FAT filesystem and see them as we go along.

FAT

The File Allocation Table (FAT) filesystem is simple (maybe too simple, in some ways) and extraordinarily widespread. While to doesn't see much use on new computers, it was the domininant filesystem on PCs from the early 80s through the late 90s / early 00s.

Being simple and nearly ubiquitious, virtually every OS (not just Microsoft's) had and have full support for it.

It lives on as the filesystem on virtually every USB thumb drive and SD-card (either FAT16, FAT32, or "exFAT"), and as a variant in the EFI System partition on every bootable GPT volume.

There are several variants you might encounter: FAT16, FAT32, and exFAT, with the latter two more common now (as FAT16 cannot support partitions larger than 2GB, and even "small" USB thumbdrives are generally larger than this nowadays).

FAT allocates storage in units called "clusters"; a cluster is the minimum allocable unit on a FAT filesystem. Clusters are a number of sectors; the number must be a power of two.

FAT layout

FAT manages files, directories, and free space using two data structures:

  • The directory entry, which contains the file (or directory) name, size, starting address, and other metadata; and
  • The file allocation table, which has two functions. First, it tracks the allocation status of clusters (that is, is part of a file stored at a given cluster?). Second, if a file is split across more than one cluster, it lets you find the clusters after the first (the first's address being stored in the directory entry).

At a high level, FAT filesystems have three parts:

  • the reserved area, which stores essential data the describes the remainder of the filesystem,
  • the FAT area, where one or more (typically two) copies of the FAT structures are stored, and
  • the data area, where directory entries and file data are stored.

Let's look at each of these in turn.

Reserved area

Let's do these on the reserved area of my USB key. Remember, we can use mmls to view the partition map, or parse the MBR (or GPT) ourselves.

mmls /dev/rdisk2
Password:
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors

      Slot      Start        End          Length       Description
000:  Meta      0000000000   0000000000   0000000001   Primary Table (#0)
001:  -------   0000000000   0000000031   0000000032   Unallocated
002:  000:000   0000000032   0003913727   0003913696   DOS FAT16 (0x06)

So the FAT partition begins on sector 32 of the drive. Let's extract it and view it:

dd if=/dev/rdisk2 bs=512 skip=32 count=1 | hexdump -Cv
1+0 records in
1+0 records out
512 bytes transferred in 0.001643 secs (311591 bytes/sec)
00000000  eb 3c 90 4d 53 44 4f 53  35 2e 30 00 02 40 01 00  |.<.MSDOS5.0..@..|
00000010  02 00 02 00 00 f8 ef 00  3f 00 ff 00 20 00 00 00  |........?... ...|
00000020  e0 b7 3b 00 00 00 29 02  97 72 68 4d 41 52 43 27  |..;...)..rhMARC'|
00000030  53 20 55 53 42 20 46 41  54 31 36 20 20 20 33 c9  |S USB FAT16   3.|
00000040  8e d1 bc f0 7b 8e d9 b8  00 20 8e c0 fc bd 00 7c  |....{.... .....||
00000050  38 4e 24 7d 24 8b c1 99  e8 3c 01 72 1c 83 eb 3a  |8N$}$....<.r...:|
00000060  66 a1 1c 7c 26 66 3b 07  26 8a 57 fc 75 06 80 ca  |f..|&f;.&.W.u...|
00000070  02 88 56 02 80 c3 10 73  eb 33 c9 8a 46 10 98 f7  |..V....s.3..F...|
00000080  66 16 03 46 1c 13 56 1e  03 46 0e 13 d1 8b 76 11  |f..F..V..F....v.|
00000090  60 89 46 fc 89 56 fe b8  20 00 f7 e6 8b 5e 0b 03  |`.F..V.. ....^..|
000000a0  c3 48 f7 f3 01 46 fc 11  4e fe 61 bf 00 00 e8 e6  |.H...F..N.a.....|
000000b0  00 72 39 26 38 2d 74 17  60 b1 0b be a1 7d f3 a6  |.r9&8-t.`....}..|
000000c0  61 74 32 4e 74 09 83 c7  20 3b fb 72 e6 eb dc a0  |at2Nt... ;.r....|
000000d0  fb 7d b4 7d 8b f0 ac 98  40 74 0c 48 74 13 b4 0e  |.}.}....@t.Ht...|
000000e0  bb 07 00 cd 10 eb ef a0  fd 7d eb e6 a0 fc 7d eb  |.........}....}.|
000000f0  e1 cd 16 cd 19 26 8b 55  1a 52 b0 01 bb 00 00 e8  |.....&.U.R......|
00000100  3b 00 72 e8 5b 8a 56 24  be 0b 7c 8b fc c7 46 f0  |;.r.[.V$..|...F.|
00000110  3d 7d c7 46 f4 29 7d 8c  d9 89 4e f2 89 4e f6 c6  |=}.F.)}...N..N..|
00000120  06 96 7d cb ea 03 00 00  20 0f b6 c8 66 8b 46 f8  |..}..... ...f.F.|
00000130  66 03 46 1c 66 8b d0 66  c1 ea 10 eb 5e 0f b6 c8  |f.F.f..f....^...|
00000140  4a 4a 8a 46 0d 32 e4 f7  e2 03 46 fc 13 56 fe eb  |JJ.F.2....F..V..|
00000150  4a 52 50 06 53 6a 01 6a  10 91 8b 46 18 96 92 33  |JRP.Sj.j...F...3|
00000160  d2 f7 f6 91 f7 f6 42 87  ca f7 76 1a 8a f2 8a e8  |......B...v.....|
00000170  c0 cc 02 0a cc b8 01 02  80 7e 02 0e 75 04 b4 42  |.........~..u..B|
00000180  8b f4 8a 56 24 cd 13 61  61 72 0b 40 75 01 42 03  |...V$..aar.@u.B.|
00000190  5e 0b 49 75 06 f8 c3 41  bb 00 00 60 66 6a 00 eb  |^.Iu...A...`fj..|
000001a0  b0 4e 54 4c 44 52 20 20  20 20 20 20 0d 0a 4e 54  |.NTLDR      ..NT|
000001b0  4c 44 52 20 69 73 20 6d  69 73 73 69 6e 67 ff 0d  |LDR is missing..|
000001c0  0a 44 69 73 6b 20 65 72  72 6f 72 ff 0d 0a 50 72  |.Disk error...Pr|
000001d0  65 73 73 20 61 6e 79 20  6b 65 79 20 74 6f 20 72  |ess any key to r|
000001e0  65 73 74 61 72 74 0d 0a  00 00 00 00 00 00 00 00  |estart..........|
000001f0  00 00 00 00 00 00 00 00  00 00 00 ac bf cc 55 aa  |..............U.|
00000200

Note that like in the MBR, multibyte values in the FAT boot sector are little-endian.

0x0, 3 bytes: The reserved area starts with machine code that (in older bootable FAT partitions) tells the CPU how far ahead to JMP to the next part of the boot loader.

0x3, 8 bytes: Then 8 bytes of ASCII-coded OEM. "MSDOS5.0"

0xB, 2 bytes: bytes per sector "00 02" -> 512

0xD, 1 byte: sectors per cluster "40" -> 64 (so a cluster is 64 * 512 = 32KB on this USB key)

0xE, 2 bytes: size of the reserved area, in sectors "01 00" -> 1

0x10, 1 byte: # FATs "02"

0x11 2 bytes: (0 in FAT32) (in FAT16: max # files in root directory) "00 02" -> 512

0x13 2 bytes: # sectors; if doesn't fit in 2 bytes, should be zero "00 00 "

0x15 1 byte: media type (0xf8 fixed disk, 0xf0 removable) "f8"

0x16 2 bytes: (in FAT32: 0) (in FAT16: size in sectors of the FAT) "ef 00" -> 239

0x18 2 bytes: sectors per track "3f 00"

0x1A 2 bytes: # heads "ff 00"

0x1C 4 bytes: # sectors before start of partition (from beginning of disk, or extended partition) "20 00 00 00" -> 32

0x20 4 bytes: # sectors in file system (will be zero if bytes at 0x13 are non-zero, and vice versa) "e0 b7 3b 00" -> 3913696

0x24 1 byte: BIOS INT13h drive number (see https://en.wikipedia.org/wiki/INT_13H; not used these days)

0x25 1 byte: not used

0x26 1 byte: signature for validity of next entries; 0x29 if valid.

0x27 4 bytes: volume (partition) serial number

0x2b 11 bytes: volume (partition) label, ASCII

0x36 8 bytes: FS type label in ASCII -- usually "FAT16"

0x3e--0x1FE: unused by FAT; sometimes contains boot code (it might be what's jumped to by the JMP instructions)

0x1FE (2 bytes): signature value (55 AA)

This boot sector is the only thing in its reserved area; the reserved area in FAT32 might contain a few more things (including a FSINFO structure) but we'll skip those details here.

We can use fsstat to view this information via Sleuthkit. We have to tell it where the filesystem if we access the volume directly, as it doesn't do partition table parsing itself:

fsstat -o 32  /dev/rdisk2

FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: FAT16

OEM Name: MSDOS5.0
Volume ID: 0x68729702
Volume Label (Boot Sector): MARC'S USB 
Volume Label (Root Directory):
File System Type Label: FAT16   

Sectors before file system: 32

File System Layout (in sectors)
Total Range: 0 - 3913695
* Reserved: 0 - 0
** Boot Sector: 0
* FAT 0: 1 - 239
* FAT 1: 240 - 478
* Data Area: 479 - 3913695
** Root Directory: 479 - 510
** Cluster Area: 511 - 3913662
** Non-clustered: 3913663 - 3913695

METADATA INFORMATION
--------------------------------------------
Range: 2 - 62611478
Root Directory: 2

CONTENT INFORMATION
--------------------------------------------
Sector Size: 512
Cluster Size: 32768
Total Cluster Range: 2 - 61144

FAT CONTENTS (in sectors)
--------------------------------------------
511-574 (64) -> EOF
...more output...

Immediately following the reserved area (whose size is described above) comes the FATs themselves, with no header or footer.

File Allocation Tables

The FATs come next. In our example, there are 2 of them, each 239 sectors long. In FAT16, they are a sequence of 16-bit entries, one per cluster in the data area.

Entries corresponding to unallocated clusters store the value zero.

Entries corresponding to file/directories that are the last (including only) cluster allocated to the file contain any value greater than or equal to 0xFFF8 (again, little endian).

Entries containing 0xFFF7 indicate a bad sector (modern hard drives usually handle this, though it might matter if someone was attempting to hide data).

Other values tell you the next cluster of a file (or directory), given the current cluster.

Weirdly, the address of the first cluster in the data area is 2. And so the first two entries of the FAT don't correspond to clusters; they are usually used store a copy of the media type, and the "dirty status" --- whether the disk was ejected properly and/or the OS was shut down before poweroff.

Let's look at the start of our FAT:

sudo dd if=/dev/rdisk2 bs=512 skip=33 count=1 | hexdump -Cv
1+0 records in
1+0 records out
512 bytes transferred in 0.000679 secs (754032 bytes/sec)
00000000  f8 ff ff 7f ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000010  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000020  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000030  ff ff ff ff ff ff ff ff  1d 00 ff ff 1f 00 ff ff  |................|
00000040  ff ff ff ff ff ff 00 00  ff ff 00 00 00 00 28 00  |..............(.|
00000050  29 00 2a 00 ff ff 2c 00  2d 00 2e 00 ff ff 30 00  |).*...,.-.....0.|
00000060  ff ff 00 00 ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000070  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff 43 00  |..............C.|
00000080  00 00 ff ff 00 00 ff ff  ff ff ff ff ff ff 00 00  |................|
00000090  ff ff ff ff ff ff ff ff  ff ff ff ff 00 00 ff ff  |................|
000000a0  ff ff ff ff 00 00 ff ff  00 00 ff ff ff ff ff ff  |................|
000000b0  ff ff ff ff ff ff 5c 00  64 00 5e 00 7c 00 00 00  |......\.d.^.|...|
000000c0  ff ff 62 00 ff ff ff ff  ff ff 00 00 00 00 00 00  |..b.............|
000000d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000e0  00 00 00 00 00 00 ff ff  00 00 00 00 00 00 00 00  |................|
000000f0  00 00 00 00 7b 00 ff ff  ff ff 00 00 00 00 00 00  |....{...........|
00000100  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000110  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000120  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000130  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000140  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000150  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000160  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000170  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000180  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000190  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000200

fsstat shows us some of this too, but note all TSK tools use sectors instead of clusters, so the offsets differ.

fsstat -o 32  /dev/rdisk2
FAT CONTENTS (in sectors)
--------------------------------------------
511-574 (64) -> EOF
575-638 (64) -> EOF
639-702 (64) -> EOF
703-766 (64) -> EOF
767-830 (64) -> EOF
831-894 (64) -> EOF
895-958 (64) -> EOF
959-1022 (64) -> EOF
1023-1086 (64) -> EOF
1087-1150 (64) -> EOF
1151-1214 (64) -> EOF
1215-1278 (64) -> EOF
1279-1342 (64) -> EOF
1343-1406 (64) -> EOF
1407-1470 (64) -> EOF
1471-1534 (64) -> EOF
1535-1598 (64) -> EOF
1599-1662 (64) -> EOF
1663-1726 (64) -> EOF
1727-1790 (64) -> EOF
1791-1854 (64) -> EOF
1855-1918 (64) -> EOF
1919-1982 (64) -> EOF
1983-2046 (64) -> EOF
2047-2110 (64) -> EOF
2111-2174 (64) -> EOF
2175-2302 (128) -> EOF
2303-2430 (128) -> EOF
2431-2494 (64) -> EOF
2495-2558 (64) -> EOF
2559-2622 (64) -> EOF
2687-2750 (64) -> EOF
2879-3134 (256) -> EOF
3135-3390 (256) -> EOF
3391-3518 (128) -> EOF
3583-3646 (64) -> EOF
3647-3710 (64) -> EOF
3711-3774 (64) -> EOF
3775-3838 (64) -> EOF
3839-3902 (64) -> EOF
3903-3966 (64) -> EOF
3967-4030 (64) -> EOF
4031-4094 (64) -> EOF
4095-4158 (64) -> EOF
4159-4222 (64) -> EOF
4223-4286 (64) -> EOF
4287-4350 (64) -> EOF
4351-4414 (64) -> EOF
4415-4478 (64) -> 4671
4543-4606 (64) -> EOF
4671-4734 (64) -> EOF
4735-4798 (64) -> EOF
4799-4862 (64) -> EOF
4863-4926 (64) -> EOF
4991-5054 (64) -> EOF
5055-5118 (64) -> EOF
5119-5182 (64) -> EOF
5183-5246 (64) -> EOF
5247-5310 (64) -> EOF
5311-5374 (64) -> EOF
5439-5502 (64) -> EOF
5503-5566 (64) -> EOF
5567-5630 (64) -> EOF
5695-5758 (64) -> EOF
5823-5886 (64) -> EOF
5887-5950 (64) -> EOF
5951-6014 (64) -> EOF
6015-6078 (64) -> EOF
6079-6142 (64) -> EOF
6143-6206 (64) -> EOF
6207-6334 (128) -> 6783
6335-6462 (128) -> 8319
6527-6590 (64) -> EOF
6591-6718 (128) -> EOF
6719-6782 (64) -> EOF
6783-6846 (64) -> EOF
7743-7806 (64) -> EOF
8191-8318 (128) -> EOF
8319-8382 (64) -> EOF