The libvmdk library allows you to access the VMware Virtual Disk (VMDK) format. This post covers how to use the tools from the libvmdk library to manage VMDK files via Terminal on macOS.

I frequently use VMDK files in the Mac Forensics training courses I teach (together with my dear friend and colleague F.C.). These files are a convenient way to share with students disk images specifically created with virtual machines for homeworks, CTF challenges, etc. The images are designed to be mounted on macOS systems for further investigation by students.

From my experience, the tools from libvmdk, such as vmdkmount, are effective for handling VMDK files through the command line, though their installation and use on macOS can be tricky. This post explains how to build and use the libvmdk tools on macOS from releases, with a focus on resolving common issues when using the vmdkmount tool.

The instructions have been tested on a M2 MacBook Pro running macOS Sonoma 14.5 with macFUSE 4.8.0 and libvmdk-alpha-20240510.tar.gz. However, they are adaptable for other recent macOS versions and libvmdk releases.

Building a libvmdk release on macOS

Download the latest release from libvmdk releases, which at the time of this post is libvmdk-alpha-20240510.

Please verify online that the version of libvmdk you’re downloading is still available. If not, you’ll need to replace the URL above.

One strong dependency which must be installed prior to configuring libvmdk is macFUSE. It can be installed via Homebrew:

% brew install macfuse

Since macFUSE requires a kernel extension to function, you’ll need to enable it System Settings > Privacy & Security after installation.

Once libvmdk is downloaded and macFUSE is installed, extract the archive with tar xvf libvmdk-alpha-20240510.tar.gz, navigate to the extracted folder libvmdk-20240510, and run ./configure to configure the package.

Previously, I encountered no issues with libvmdk-20221124, but with libvmdk-20240510, the configuration process fails to detect macFUSE. Below is part of the output when running ./configure:

libvmdk configured without fuse

This happens even though macFUSE is installed in your system, with the related package available at /usr/local/lib/pkgconfig/fuse.pc. This .pc file contains the following information:

prefix=/usr/local
  2 exec_prefix=${prefix}
  3 libdir=${exec_prefix}/lib
  4 includedir=${prefix}/include
  5 
  6 Name: fuse
  7 Description: Filesystem in Userspace
  8 Version: 2.9.9
  9 Libs: -L${libdir} -lfuse -pthread
 10 Libs.private:  -liconv -framework CoreFoundation -framework DiskArbitration
 11 Cflags: -I${includedir}/fuse -D_FILE_OFFSET_BITS=64

The .pc file is used by pkg-config to retrieve the metadata for compiling and linking a program to a library. The configuration of libvmdk relies on pkg-config but cannot locate fuse.pc. To resolve this, add the package path as follows:

% export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/ && ./configure

The PKG_CONFIG_PATH environment variable specifies additional paths where pkg-config will search for its .pc files. Running ./configure again with the path of the folder containing fuse.pc enables FUSE support for libvmdk:

libvmdk configured without fuse

With the FUSE support enabled, you can compile the package with make and install it using make install. Specifically, the new programs available on your system will be:

  • vmdkinfo: Provides information about a VMDK image file.
  • vmdkmount: Mounts a VMDK image file.

Let’s explore how to use vmdkmount on a Mac more efficiently.

Using vmdkmount to Mount a VMDK

The vmdkmount command-line tool works as follows:

vmdkmount [ -X extended_options ] image mount_point

where extended_options are options (if any) passed to the subsystem, image is the VMDK image file, and mount_point is the desired mount location.

On a Mac, vmdkmount sometimes requires additional attention. For instance, if you want to mount a VMDK renamed to nash.vmdk, located at /Volumes/nash/nash.vmdk, using /tmp/mp as the mount point, you might try the following:

vmdkmount source image error

However, the tool fails to open the source image because vmdkmount does not support renaming for stream optimized images (see the open issue 34 on the GitHub repository of libvmdk).

The workaround is to either rename the image back to its original name (which can be determined using vmdkinfo) or navigate to the folder containing nash.vmdk and mount the image from there:

vmdkinfo output

Additionally, when running vmdkmount on macOS, it appears that macFUSE requires a volume icon, which you’ll need to specify during the mount process (see the closed issue 117 on the GitHub repository of libvmdk):

vmdkmount iconpath_error

To address this, pass the volume icon (volicon=/path/to/volume_icon) via the extended options (-X) of vmdkmount:

vmdkmount volicon option

Consequently, when you want to mount a renamed VMDK on a Mac, you need to execute the following commands:

cd /path/to/parent_of_vmdk
% vmdkmount -X volicon=/Library/Filesystems/macfuse.fs/Contents/Resources/Volume.icns image.vmdk /path/to/MountPoint

Mounting VMDK from Any Directory on macOS

As shown, mounting VMDK images on macOS can be tricky. It is more convenient to create an alias which can be used to run vmdkmount to mount an image from any directory and without providing extended options.

Since creating an alias with arguments can be problematic, you can create a function that accepts the path to the image and the path to the mount point as arguments. This function handles issues like renaming stream optimized images and the icon path error. The vmdkmount2 function below serves this purpose:

# Alias for vmdkmount working from any directory.
vmdkmount2() {
  local vmdk_path="$(dirname $1)"
  local vmdk_file="$(basename $1)"
  local mount_point="$2"
  local cur_dir="$PWD"
  cd "${vmdk_path}"
  mkdir -p "${mount_point}"
  vmdkmount -X volicon=/Library/Filesystems/macfuse.fs/Contents/Resources/Volume.icns "${vmdk_file}" "${mount_point}"
  cd "${cur_dir}"
}

To define the vmdkmount2 function in your environment for login shells, you can append this function (for example, within a file named as vmdkmount2.sh) to .zprofile:

% cat vmdkmount2.sh >> ~/.zprofile

Once you have defined vmdkmount2, you can easily mount a VMDK image on Mac as follows:

% vmdkmount2 /path/to/image.vmdk /path/to/MountPoint

vmdkmount2

Once the VMDK is mounted on your Mac, you can attach the virtual disk to the system using hdiutil attach with the option -imagekey diskimage-class=CRawDiskImage:

hdiutil attach vmdk

The output of hdiutil shows that new volumes from the VMDK are now available. These volumes can be mounted, for example, with diskutil, allowing you to interact with them as needed.

I find the libvmdk tools, vmdkmount and vmdkinfo, to be invaluable when working with VMDK images on macOS. I have created a GitHub gist containing the vmdkmount2 function. You can use this to quickly update your .zprofile and have this helper function readily available.