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.
Microsoft Windows Windows users have been doing pretty much the same using tools like HFSExplorer. |
The process in Linux was pretty straight forward:
-
Image the device to be examined.
-
Read the partition table to identify the byte-offset to the HFS partition in the image.
-
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 |
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 |
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 |
Accessing Unallocated File System Space Unallocated space in HFS partitions is addressable through The Sleuthkit with the blkls tool. |
Now, go forth and conquer!
Thank you John, really useful.
ReplyDeleteHave you tried to force (modprobe) losetup with the max_part param set (I used 63 in the past, too many)? I acted this way when facing images coming from raid system: the md daemon needed a single losetup command (sorry for this last raw statement).
No, I've not had the need to do that, but thanks for the tip!
Delete