Mac DFIR - HFS+ Volume Header


Understanding the HFS+ file system is an important step to analyzing Mac systems. It tracks all of the metadata associated with files and folders on a system among things.

Suggested Reading

NOTE: Any discussions about Mac systems will assume you are running 10.11.x That's all I have for testing on my Surface Pro 4 :)

HFS+ Structure

The core files (aka – “special files”) that make up the HFS+ filesystem according to TN1150 are listed below. This blog post will cover the Volume Header. I will cover the others in order as they are listed here in subsequest blog posts.

  • Volume Header
  • Catalog File
  • Extents Overflow File
  • Attributes File
  • Allocation File
  • Startup File

Table 1 – Special File Reservation C struct depicts the C struct code for the 16 reserved Catalog Node IDs (CNID/inode) for HFS+ special files per the TN1150

Table 1 – Special File Reservation C struct

enum {  
    kHFSRootParentID           = 1,
    kHFSRootFolderID           = 2,
    kHFSExtentsFileID          = 3,
    kHFSCatalogFileID          = 4,
    kHFSBadBlockFileID         = 5,
    kHFSAllocationFileID       = 6,
    kHFSStartupFileID          = 7,
    kHFSAttributesFileID       = 8,
    kHFSRepairCatalogFileID    = 14,
    kHFSBogusExtentFileID      = 15,
    kHFSFirstUserCatalogNodeID = 16

Volume Header

Every HFS+ volume must have a volume header. The volume header is important to the overall filesystem because it provides the analyst with volume creation, modification, and checked dates. It specifics the block size, the locations of our 16 special files, boot files (boot.efi), bootable folder (CoreServices), number of files and folders on the volume and also lets us know if journaling is enabled among other details.

There are two volume headers. The volume header and the alternate volume header. The volume header is located at offset 0x400h, which is 1024 bytes from the start of the volume. The alternate volume header is located 1024 bytes before the end of the volume. Both are 512 bytes in size and are at fixed locations.

Extract Volume Header

In this example I show you how you can extract the volume header for analysis.

In our case I extract 4096 bytes, which is our first block. This will contain all of our volume header information that we can use during analysis.

In order to do the extraction, I used the following. If you prefer you can also open the entire disk with your hex editor. For size/portability reasons I will be using dd to extract the first 4096 bytes.

First we will look at the mapping of our disk.

Table 2 - mmls disk layout

sudo mmls /dev/rdisk1  

We can see here that item 05 (HFSDemo) is what we want.

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   0030703575   0030293936   HFSDemo  
006:  -------   0030703576   0030965759   0000262184   Unallocated  

Table 3 - dd block 1 - header volume

sudo dd if=/dev/disk1 of=volheader bs=4096 count=1  

After running dd we now have our 4096 byte dump, which will contain our volume header.

1+0 records in  
1+0 records out  
4096 bytes transferred in 0.000940 secs (4357055 bytes/sec)  

Analyze Volume Header

Now that we have the volume header extracted we can move to offset: 0x400h with our hex editor (010 Hex Editor), which is sector 2 (0, 1) as depicted in Figure 1 – HFS+ Offset – 0400h (1,024 bytes). On a Mac, you can easily skip to an offset in 010 by using the Command + L keys. You could have also skipped these bytes using dd as well.

Figure 1 - HFS+ Offset - 0x400h (1,024 bytes)


To make things easier to see and separate out I created a Synalyze It! template for parsing the HFS+ volume header. The results of the grammar file can be seen in Figure 2 – HFS+ Synalyze It! Volume Header Grammar.

You can download the Synalyze It grammar file on my GitHub.

Figure 2 - HFS+ Synalyze It! Volume Header Grammar


NOTE: The volume header creation date is stored in local time, not GMT.  

Table 3 – HFS+ Volume Header Output

Here is the parsed hex from Figure 2 above using the Synalyze It! Pro Grammar file I created.

Now that we have "manually" parsed the volume header using a hex editor let’s go over some of the more useful information that we were able to uncover.

Volume Header Analysis Results

  • HFS+ filesystem
    • H+
    • Version 4 = HFS+
  • A journaled filesystem - Journaling is enabled
  • Creation Date (Local time) - 2016-07-23 11:08:47
  • Modify Date(UTC) - 2016-07-23 18:09:36
  • Backup Date (UTC) - 00 00 00 00
  • Checked Date (UTC) - 2016-07-23 18:08:47
  • File count – 66
  • Folder count – 19
  • Volume UUID - 37a4e9fdeafc14ea
  • Block size is 4096
  • Total Blocks – 3,786,742
  • Free Blocks - 3,777,448
  • Drive size = Total Blocks * Block Size (4096), which is 15,510,495,232 bytes, or 15 GB
  • Location and Size of Special files (Extent, Catalog, Attributes, and Startup) via the Fork Data Structures.

To make converting the hex times easier I went ahead and wrote a simple Python method below to convert our times and print them out in a human readable format.

Table 4 - Python Datetime Conversion

>>> print mactimeConvert(0xD3B900BF)
2016-07-23 11:08:47  
>>> print mactimeConvert(0xD3B96360)
2016-07-23 18:09:36  
>>> print mactimeConvert(0xD3B9632F)
2016-07-23 18:08:47  

The Easy Way

Now that we parsed the volume header the “hard” way, it is time to go over an easier method using one of my favorite tools.

This is accomplished via Sleuth Kit’s fsstat command.

fsstat displays details of a file system. The “f” set of tools within Sleuth Kit are file system specific (fls, fsstat, ffind, etc.) You could also use the native Mac tool, hdiutil (hdiutil fsid /dev/).

You can see within Table 5 – fsstat - Sleuth Kit, fsstat provides us with all of the information we were able to obtain via hex analysis and then some.

It also provides us this information within a faction of a second vs. the time required for manual analysis/parsing like we did above.

Table 5 - fsstat - Sleuth Kit

You can run it via:

sudo fsstat /dev/rdisk2s2  

And here are the results of using The Sleuth Kit's fsstat command.

File System Type: HFS+  
File System Version: HFS+

Volume Name: HFSDemo  
Volume Identifier: 37a4e9fdeafc14ea

Last Mounted By: Mac OS X, Journaled  
Volume Unmounted Properly  
Mount Count: 203

Creation Date:         2016-07-23 11:08:47 (PDT)  
Last Written Date:     2016-07-23 11:09:36 (PDT)  
Last Backup Date:      0000-00-00 00:00:00 (UTC)  
Last Checked Date:     2016-07-23 11:08:47 (PDT)

Journal Info Block: 117

Range: 2 - 108  
Bootable Folder ID: 0  
Startup App ID: 0  
Startup Open Folder ID: 0  
Mac OS 8/9 Blessed System Folder ID: 0  
Mac OS X Blessed System Folder ID: 0  
Number of files: 66  
Number of folders: 19

Block Range: 0 - 3786741  
Allocation Block Size: 4096  
Number of Free Blocks: 3777448  


Keep in mind tools are not always 100% accurate.
I have personally written tools that parsed artifacts incorrectly. I do this all the time. Do not blindly rely on them for your analysis. Learn how to do things manually, then go about writing your own tools, or verifying other people's tools.