Thursday, October 18, 2012

Christmas Comes Early: HFS/HFS+ Mounting

Note This is my first attempt at using asciidoc to create a more legible document for the reader. My thanks go out to Dr. Michael Cohen at Google for pointing out the formatting tool.

The Ghost of HFS Past

It is no great revelation that Apple favors the HFS/HFS+ file systems. But, when I started my adventures in Linux-based forensics, my chief forensics tool, The Sleuthkit, did not support HFS file systems. The solution was to mount the file systems read-only and examine the allocated files with standard Linux tools and applications. Even when The Sleuthkit added HFS support, it was still useful to mount the partition, especially when it came to examining media files.

Note

Microsoft Windows

Windows users have been doing pretty much the same using tools like HFSExplorer.

The process in Linux was pretty straight forward:

  1. Image the device to be examined.

  2. Read the partition table to identify the byte-offset to the HFS partition in the image.

  3. Use the mount command with the byte-offset to mount the partition.

For example

# mmls macbookpro320.dd -a
GUID Partition Table (EFI)
Offset Sector: 0
Units are in 512-byte sectors

     Slot    Start        End          Length       Description
04:  00      0000000040   0000409639   0000409600   EFI system partition
05:  01      0000409640   0624880263   0624470624   Customer

# mount -o ro,loop,offset=$((409640*512)) macbookpro320.dd /mnt/analysis

The mount command attaches file systems on storage devices to the GNU Linux file tree. Conversely, the umount (not ‘unmount’ as you might expect) command detaches the device file system from the GNU Linux file system. The mount command above worked with the macbookpro320.dd disk image because of the loop option.

Loop Device

In Unix-like operating systems, a loop device, vnd (vnode disk), or lofi (loopback file interface) is a pseudo-device that makes a file accessible as a block device.

http://en.wikipedia.org/wiki/Loop_device
— Wikipedia


The Ghost of HFS Present

But, somewhere around the 2.6.34 Linux kernel, the mount command stopped working with HFS loop devices in the manner demonstrated above. The mount command can still be used to mount a partition addressed block device, but not addressed by image by offset like the illustration above.

By Partition Block Device File (verbose mode for illustration)

# blkid
/dev/sdd1: LABEL="EFI" UUID="2860-11F4" TYPE="vfat"
/dev/sdd2: UUID="f2477645-5489-3419-b477-d504574057e3" LABEL="Macintosh 
HD" TYPE="hfsplus"

# mount -o ro -v /dev/sdd2 /mnt/analysis/
mount: you didn't specify a filesystem type for /dev/sdd2
       I will try type hfsplus
/dev/sdd2 on /mnt/analysis type hfsplus (ro)

# umount -v /mnt/analysis/
/dev/sdd2 has been unmounted

As you can see, the mount command works as expected when the partition is addressed by the special block device file. But, when the partition is addressed by byte-offset from the raw device or disk image, it fails:

By Byte-Offset (block device shown)

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

     Slot    Start        End          Length       Description
04:  00      0000000040   0000409639   0000409600   EFI system partition
05:  01      0000409640   0624880263   0624470624   Customer

# mount -o ro,offset=$((409640*512)) /dev/sdd /mnt/analysis
mount: wrong fs type, bad option, bad superblock on /dev/loop2,
       missing codepage or helper program, or other error
       In some cases useful info is found in syslog - try
       dmesg | tail  or so
Note This bug only applies to HFS formatted partitions. Other common file systems—FAT, NFTS, EXT2/3/4—do not seem to be affected.

The Ghost of HFS Future

The work around for storage devices is obvious: point mount at the partition’s block device file. But in forensics, we work with disk images to avoid making changes to the original storage medium. How do we address HFS partitions in disk images if we can’t address them by offset?

Enter kpartx. The kpartx command reads partition tables and maps partitions to device files. It works on devices and disk images. This means we can map HFS partitions in a disk image to a special block device file and mount those partitions by addressing that block device file as if it were part of an attached device!

kpartx

# kpartx
usage : kpartx [-a|-d|-l] [-f] [-v] wholedisk
    -a add partition devmappings
    -r devmappings will be readonly
    -d del partition devmappings
    -u update partition devmappings
    -l list partitions devmappings that would be added by -a
    -p set device name-partition number delimiter
    -g force GUID partition table (GPT)
    -f force devmap create
    -v verbose
    -s sync mode. Don't return until the partitions are created

To demonstrate its use, we will use a raw (dd) image from a MacBook Pro. Other disk image formats will work too, so long as they can be exposed to GNU Linux as raw devices (think xmount).

Image Information

# img_stat macbookpro320.dd
IMAGE FILE INFORMATION
 --------------------------------------------
Image Type: raw

Size in bytes: 320072933376

We can read the partitions in the disk image with kpartx.

kpartx: Detected Partitions

# kpartx -l macbookpro320.dd
loop1p1 : 0 409600 /dev/loop1 40
loop1p2 : 0 624470624 /dev/loop1 409640

# kpartx -lg macbookpro320.dd
loop1p1 : 0 409600 /dev/loop1 40
loop1p2 : 0 624470624 /dev/loop1 409640
Note

The GUID Partition Table

kpartx has a option to force a GUID partition table, which the MacBook uses, but as demonstrated, it wasn’t necessary in this case.

All that remains to do is to map the partitions so that we can mount them. We can use the -r option to create read-only devices.

kpartx: Mapping Partitions

# kpartx -av macbookpro320.dd
add map loop1p1 (254:0): 0 409600 linear /dev/loop1 40
add map loop1p2 (254:1): 0 624470624 linear /dev/loop1 409640

Now, mounting is as simple as pointing at the new block device files, which are found in the /dev/mapper directory.

Mounting special HFS block devices

# mount -o ro -v /dev/mapper/loop1p2 /mnt/analysis
mount: you didn't specify a filesystem type for /dev/mapper/loop1p2
       I will try type hfsplus
/dev/mapper/loop1p2 on /mnt/analysis type hfsplus (ro)

# mount
...
/dev/mapper/loop1p2 on /mnt/analysis type hfsplus (ro,relatime,umask=22,
uid=0,gid=0,nls=utf8)

After you have completed your analysis, unmount the partition and remove the special block devices.

Cleaning up

# umount -v /mnt/analysis/
/dev/mapper/loop1p2 has been unmounted

# kpartx -dv macbookpro320.dd
del devmap : loop1p2
del devmap : loop1p1
loop deleted : /dev/loop1
Note

Accessing Unallocated File System Space

Unallocated space in HFS partitions is addressable through The Sleuthkit with the blkls tool.

Now, go forth and conquer!