09: Acquisition, Volumes, MBRs

DRAFT

Announcements

Facepalm.

SFS https://infosec.cs.umass.edu/content/umass-amherst-scholarship-service-program

Introduction

In previous lectures, we dealt with problems of parsing and carving individual files or portions of files. Now, we’ll turn our attention to one of the major tasks of digital forensics: disk drive imaging (“acquisition”) and analysis of the data so acquired.

So what does it mean to “image” a drive? It means we make a bit-for-bit copy of the raw data stored on that drive and save it as a file on another computer. This is usually referred to as a “raw image” of the drive.

We’ll restrict our attention to the use of OS-level acquisition tools, though there are (in older machines) tools that access drives through the BIOS, and there are hardware-based acquisition tools as well. Carrier provides an (older) summary; the Forensics Wiki is more up to date.

Drives on computers

Depending upon your OS, you might have graphical tools and/or command-line tools built into the system to view drives on your computer. For example, on OS X I can use “Disk Utility” to examine the drives that are mountable on a system (demo w/ laptop and USB drive). But it doesn’t show me everything; “System Information” shows a more comprehensive view. (Note “BSD Name:”, more on this in a bit.)

On a Linux system, there are various ways to see what drives are available. mount shows which drives (partitions, actually) are mounted. (OS X supports this command too.) During boot, the kernel shows a list of hardware as it’s detected. You can use dmesg to view this log after-the-fact. (Demo on virtual machine and/or elnux.)

PCs generally often have some sort of “boot menu” that lets you see what drives are attached, too, using the BIOS (or these days, UEFI running on built-in firmware that runs on the computer’s motherboard) but I can’t demo that on my Mac.

And of course, we can turn to the sleuthkit to interrogate a drive, like my Mac’s HD, and a USB:

sudo 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

sudo mmls /dev/rdisk2
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)

(More on /dev/rdisk[n] in a moment)

You can think of hard disk drives (old-style spinning metal or newer SSDs) as a giant array of bytes. This obviously isn’t the most useful view all the time (where did I put my program? At byte 3D7A149F?) but it is the most fundamental way to view the drive.

Unix-like OSes (including OS X) expose disk drives as a file, stored in a special location. Most devices that can be exposed as files are in the /dev directory, and disks are no exception.

For example, on OS X, the raw bytes of my disk drives are accessible /dev/rdisk* (and the block-buffered bytes at /dev/disk* – these are the “BSD Names”). Linux has similar devices at /dev/sda*. You can directly access these if you like. Here’s the first 512 bytes of my Mac’s hard disk:

sudo hexdump -Cv -n 512 /dev/rdisk0

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.|
00000200

and of my virtual machine’s hard disk:

00000000  eb 63 90 10 8e d0 bc 00  b0 b8 00 00 8e d8 8e c0  |.c..............|
00000010  fb be 00 7c bf 00 06 b9  00 02 f3 a4 ea 21 06 00  |...|.........!..|
00000020  00 be be 07 38 04 75 0b  83 c6 10 81 fe fe 07 75  |....8.u........u|
00000030  f3 eb 16 b4 02 b0 01 bb  00 7c b2 80 8a 74 01 8b  |.........|...t..|
00000040  4c 02 cd 13 ea 00 7c 00  00 eb fe 00 00 00 00 00  |L.....|.........|
00000050  00 00 00 00 00 00 00 00  00 00 00 80 01 00 00 00  |................|
00000060  00 00 00 00 ff fa 90 90  f6 c2 80 74 05 f6 c2 70  |...........t...p|
00000070  74 02 b2 80 ea 79 7c 00  00 31 c0 8e d8 8e d0 bc  |t....y|..1......|
00000080  00 20 fb a0 64 7c 3c ff  74 02 88 c2 52 bb 17 04  |. ..d|<.t...R...|
00000090  f6 07 03 74 06 be 88 7d  e8 17 01 be 05 7c b4 41  |...t...}.....|.A|
000000a0  bb aa 55 cd 13 5a 52 72  3d 81 fb 55 aa 75 37 83  |..U..ZRr=..U.u7.|
000000b0  e1 01 74 32 31 c0 89 44  04 40 88 44 ff 89 44 02  |..t21..D.@.D..D.|
000000c0  c7 04 10 00 66 8b 1e 5c  7c 66 89 5c 08 66 8b 1e  |....f..\|f.\.f..|
000000d0  60 7c 66 89 5c 0c c7 44  06 00 70 b4 42 cd 13 72  |`|f.\..D..p.B..r|
000000e0  05 bb 00 70 eb 76 b4 08  cd 13 73 0d 5a 84 d2 0f  |...p.v....s.Z...|
000000f0  83 d0 00 be 93 7d e9 82  00 66 0f b6 c6 88 64 ff  |.....}...f....d.|
00000100  40 66 89 44 04 0f b6 d1  c1 e2 02 88 e8 88 f4 40  |@f.D...........@|
00000110  89 44 08 0f b6 c2 c0 e8  02 66 89 04 66 a1 60 7c  |.D.......f..f.`||
00000120  66 09 c0 75 4e 66 a1 5c  7c 66 31 d2 66 f7 34 88  |f..uNf.\|f1.f.4.|
00000130  d1 31 d2 66 f7 74 04 3b  44 08 7d 37 fe c1 88 c5  |.1.f.t.;D.}7....|
00000140  30 c0 c1 e8 02 08 c1 88  d0 5a 88 c6 bb 00 70 8e  |0........Z....p.|
00000150  c3 31 db b8 01 02 cd 13  72 1e 8c c3 60 1e b9 00  |.1......r...`...|
00000160  01 8e db 31 f6 bf 00 80  8e c6 fc f3 a5 1f 61 ff  |...1..........a.|
00000170  26 5a 7c be 8e 7d eb 03  be 9d 7d e8 34 00 be a2  |&Z|..}....}.4...|
00000180  7d e8 2e 00 cd 18 eb fe  47 52 55 42 20 00 47 65  |}.......GRUB .Ge|
00000190  6f 6d 00 48 61 72 64 20  44 69 73 6b 00 52 65 61  |om.Hard Disk.Rea|
000001a0  64 00 20 45 72 72 6f 72  0d 0a 00 bb 01 00 b4 0e  |d. Error........|
000001b0  cd 10 ac 3c 00 75 f4 c3  de 9c 09 00 00 00 80 20  |...<.u......... |
000001c0  21 00 83 a9 23 65 00 08  00 00 df f7 ff 04 00 00  |!...#e..........|
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.|
00000200

and of a USB key:

00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
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  60 9d b9 ec 00 00 00 00  |........`.......|
000001c0  21 00 06 2a ea ca 20 00  00 00 e0 b7 3b 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 55 aa  |..............U.|
00000200

There are some similarities: you can see some sort of error message (presumably displayed if this disk cannot boot) on the bootable drives and you’ll notice the end of the 512 bytes are zero-padded, but end with the values 55 aa. Not a coincidence!

Imaging a drive

I kinda already let the horse outta the barn, above: you can directly read these “files” and you’ll get the bytes from the disk. Of course, we don’t usually do it with hexdump. Instead, there are various utilities that can do it for you. The simplest such is dd, which just copies bytes block-by-block (default: 512 bytes at a time) from an input (default: standard in) to an output (default: standard out).

The basic invocation looks like this:

dd if=/dev/rdisk0 of=/Users/liberato/disk-image.dd bs=512

Though that won’t work: I can’t image an entire drive into a file inside a filesystem on the drive, for obvious (I hope) reasons. Usually, you need another drive to capture the data to. For demonstration purposes, I’ll limit the count of blocks here so that (a) data fits and (b) it doesn’t take all day.

dd if=/dev/rdisk0 of=/Users/liberato/disk-image.dd bs=512 count=10

Output:

10+0 records in
10+0 records out
5120 bytes transferred in 0.001093 secs (4683716 bytes/sec)

10 full records + 0 partial records in and out.

I can also compute a hash of the file and/or the drive:

shasum /dev/rdisk0   # note that this will take a looong time

Again, I can read just some of the drive for demonstration purposes:

dd if=/dev/rdisk0 bs=512 count=10 | shasum
10+0 records in
10+0 records out
5120 bytes transferred in 0.003004 secs (1704352 bytes/sec)
4556ea34b55f51eb35b9338e47b07e6710378f98  -

And check the bytes I saved:

shasum /Users/liberato/disk-image.dd
4556ea34b55f51eb35b9338e47b07e6710378f98  disk-image.dd

There are a couple other details to consider. First, what if the drive has errors? The simplest thing to do is replace the sectors you cannot read with just 0s in the image. You must pass two options to the conv argument of dd to make this happen:

dd if=/dev/rdisk0 of=/Users/liberato/disk-image.dd bs=512 count=10 conv=noerror,sync

noerror means to not stop on error, and sync pads erroneous read with NUL (zero) bytes. See man dd for more details.

(Data recovery of corrupted hardware is beyond the scope of this course.)

Finally, a note expounded upon more in the text. In this day and age, forensic exams that are conducted on-site are conducted according to a protocol.

Machines that are off are brought back to a lab, and the drive is imaged. But notably, we don’t (usually) boot the OS on the machine; instead we boot from a known-good OS (like, say a Linux LiveCD) and use it to run the imaging operation. We might also interpose a hardware and/or software “write blocker” to prevent making changes to the drive being imaged. This overall process is called a “dead acquisition.”

In contrast, a “live acquisition” is performed on a running machine. Usually, we might dump memory of an active machine or do other memory forensics (a topic we may touch upon later in the semester), then decide whether to attempt a live acquisition or to shut the machine down to prevent further changes. Lots of factors to consider here, including:

  • techincal sophistication of the user
  • presence of disk encryption
  • rootkits
  • etc.

that go beyond the scope of this lecture.

Interpreting the data: Disk volumes

So now we know how to get some or all of the raw data from a disk. What does it mean?

To answer this question, we’re going to first introduce some terminology and sketch some abstract examples of how disks are organized. Then we’ll dive into some specifics.

“Volumes” are organized by “volume systems”, assembled from one or more disks, usually but not always 1:1. A volume is a collection of addressable “sectors” (sometimes also: “blocks”) which are the smallest unit of addressing that most disk controllers support (older disks: 512 bytes; newer disks can be larger (4KB or Advanced Format) but have backward-compatibility translation layers(!!)) that appear continuous to the OS.

Volumes are usually divided into one or more “partitions”. A partition names a particular collection of consecutive sectors in a volume. For example, my Mac’s HD has two user-visible partitions (show in Disk Utility), as well as two that are not visible through the GUI (show in System Report):

EFI:
  Capacity: 209.7 MB (209,715,200 bytes)
  BSD Name: disk0s1
  Content:  EFI
  Volume UUID:  BDC1974F-6B8C-3DAE-9DB2-3AA3C17BF506
disk0s2:
  Capacity: 299.42 GB (299,418,038,272 bytes)
  BSD Name: disk0s2
  Content:  Apple_CoreStorage
Recovery HD:
  Capacity: 650 MB (650,002,432 bytes)
  BSD Name: disk0s3
  Content:  Apple_Boot
  Volume UUID:  42320CA6-833A-3699-AAC3-64080DD45FF8
Cobalt:
  Capacity: 199.86 GB (199,864,942,592 bytes)
  Available:    198.94 GB (198,938,521,600 bytes)
  Writable: Yes
  File System:  Journaled HFS+
  BSD Name: disk0s4
  Mount Point:  /Volumes/Cobalt
  Content:  Apple_HFS
  Volume UUID:  42E09BD5-9547-36E4-9879-4BB9C01484EB

And here’s a partition on the USB key:

MARC'S USB:
  Capacity: 2 GB (2,003,812,352 bytes)
  Available:    2 GB (2,001,010,688 bytes)
  Writable: Yes
  File System:  MS-DOS FAT16
  BSD Name: disk2s1
  Mount Point:  /Volumes/MARC'S USB
  Content:  DOS_FAT_16
  Volume UUID:  8117D4F3-4CD8-38D5-8B94-75D720C736A5

Different operating systems and devices use different methods of partitioning drives and labeling them, though most modern consumer PC hardware and OSes (Windows, Mac, Linux) these days are converging on two standards: the newer Unified Extensible Firmware Interface’s GUID Partition Table, and legacy support for Master Boot Records (notably, on basically every USB thumb drive and SD storage card in existence, as well as older PCs). There are other formats, but understanding these two will give you the basis to understand others if you need to.

If you want to carve out individual partitions, you can use mmls to find their offsets, then dd to read/write them (note you can pass a skip or iseek parameter to dd). But usually you would just operate on the entire image; most toolsets (TSK included) have other, volume-aware tools to deal with individual partitions, as we showed in our demo in Lecture 2.

The Master Boot Record

The older “master boot record” (MBR) style of partitioning (sometimes called “DOS” style, as it’s the OS that popularized this format) has no formal standard, though it’s well documented in many places since it’s so ubiquitious.

In its simplest form, a MBR contains three things:

  • boot code (literally: it’s executable code that the BIOS will load then execute)
  • a partition table
  • a signature

Note that modern MBRs on HDDs and SSDs don’t contain bootcode – the firmware handles this now, and the bootcode area is used for other information instead. We’ll talk more about this when we get to UEFI. (See https://en.wikipedia.org/wiki/Master_boot_record#Sector_layout.) And USBs don’t usually contain bootcode either.

The signature value we’ve seen already: The last two bytes of a sector containing a MBR are 55 AA; this is another “magic number” not unlike the SOI/EOI tags in a JPEG file. Seeing it is not a guarantee of a valid MBR, but not seeing it means it’s definitely not an MBR.

A disk with three partitions has an MBR then three partitions, and the MBR has entries for each of the three partitions: (on board). These entries are stored in the partition table.

Each of the (at most four) entries contains the following (https://en.wikipedia.org/wiki/Master_boot_record#PTE):

  • status/flags (1 byte)
  • starting CHS address (3 bytes)
  • type (1 byte)
  • ending CHS address (3 bytes)
  • starting LBA sector (4 bytes)
  • number of sectors (4 bytes)

CHS is a legacy system (when disk locations where referred to by Cylinder / Head / Sector, see https://en.wikipedia.org/wiki/Cylinder-head-sector if you’re curious) and basically irrelevant these days. These values are often hardcoded to various marker values that indicate that LBA address should be used instead, e.g., (1023, 254, 63) or (1023, 255, 63).

The type is a value you look up in a table (e.g., https://en.wikipedia.org/wiki/Partition_type) though different OSes and tools might name different types slightly differently due to the lack of a standard here.

The LBA sector is an offset from the start of the disk, in terms of 512-byte sectors, to the start of the partition, and the number of sectors tells you how bit that partition is. Easy-peasy.

Or is it? What if you want more than four partitions on a disk?

MBR and extended partitions

Instead of a nice neat table, you end up with a hybrid. (Up to) the first three partitions are treated as normal and given entries in the MBR. The last partition in the MBR is turned into a “Primary Extended Partition,” which is further subdivided into what looks like a linked-list of “Secondary Extended Partitions.”

Each of these extended partitions starts with an “Extended Boot Record” which is just a simplified version of the MBR, containing two entries:

  • The first entry is the data partition as you’d expect: it points to the data partition (offset from this EBR) and contains the length of this partition, in sectors.
  • The second entry is the address of the next EBR relative to the start of the primary extended partition; it’s length includes all sectors in that span up to the end of that partition, not just filled ones (as some sectors can be unallocated for various reasons).

Extended partitions are a PITA but are becoming more rare as GPTs are becoming standard. (And MBRs on USB keys and the like typically have just a single partition, so generally no extended partition nonsense occurs there.)

Let’s pull up the MBR documentation on Wikipedia https://en.wikipedia.org/wiki/Master_boot_record#Sector_layout (see also Carrier for a good alternative presentation) and the MBR of my USB key, and see what we can see:

00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
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  60 9d b9 ec 00 00 00 00  |........`.......|
000001c0  21 00 06 2a ea ca 20 00  00 00 e0 b7 3b 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 55 aa  |..............U.|
00000200

Very important: All multi-byte fields are little endian in the MBR!

Let’s look at just the partition table, starting at 0x1BE:

00 00 21 00 06 2a ea ca 20 00 00 00 e0 b7 3b 00

And now let’s parse it:

https://en.wikipedia.org/wiki/Master_boot_record#PTE

  • 00: status (not bootable)
  • 00 21 00: CHS start (ignore)
  • 06: type 0x06 is FAT-16 https://en.wikipedia.org/wiki/Partition_type
  • 2a ea ca: CHS end (ignore)
  • 20 00 00 00: LBA start, in this case 32 sectors from the start of the disk
  • e0 b7 3b 00: number of sectors in partition (not its LBA end!) To convert in Python, use: struct.unpack('<I', bytes.fromhex('e0 b7 3b 00'))[0], in this case 3913696

Does this match mmls?

mmls /dev/rdisk2
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)

Look at that! We can parse MBRs!

A note about partitions and slack

There’s nothing in the MBR that implies all sectors will be part of a partition. Space that’s not allocated is not accessible under OSes. One could imagine deleting a partition entry in an MBR to “hide” it from examination, and putting it back in when you wanted to access the data.