Thursday, March 11, 2010

How to mount a VirtualBox .VDI image under OS X

Updated (02/19/2015): This procedure is confirmed to work with Oracle's VirtualBox 4.3.22 r98236 running on Mac OS X Yosemite (10.10.2).  I tested it with Oracle's Solaris 11 (2) on a statically-sized .vdi and though there were no filesystems it could read, the same procedure works now as it did then.

Introduction:  While tinkering with Sun's VirtualBox 3.1.4 on Apple OS X Snow Leopard (10.6.2 as of this writing), I found the necessity to be able to mount VirtualBox's virtual disk image files so I could work on them from within the host. This includes partitioning, formatting, data transfer and general maintenance -- all much simpler to do within the host, especially if the guest isn't actually running yet. This method is a re-post of collective information I found online, I will post attributions to the original authors once I can find their sites again.

:  This method only works on flat, statically-sized
.vdi images.  Though possible to mount dynamically-sized images, it is beyond the scope of this post.

Methodology: To mount the image, we need to find where the VirtualBox .vdi header stops and the raw disk image begins.  This is discerned by reading a little-endian, 4-byte, 32-bit integer at byte offset 0x158 (hex) or 344 (dec) from the .vdi image file.  Once we have this value, we will divide it by the number of bytes per sector, 0x200 (hex) or 512 (dec), and use Apple OS X's included hdid utility to attach the virtual device using a subset of the image file (please see the man 8 hdid, --section, parameter).  Once mounted, all standard utilities can be used against the disk image, including but not limited to any cli-based command and even the gui Disk Utility (Applications -> Utilities -> Disk Utility).

Implementation:  Let's start by getting that little-endian, 4-byte, 32-bit integer at offset 0x158 in the .vdi file.  It so happens that I will be working on sl.vdi today, I'll leave it as an exercise to the reader to figure out what I've done, but let's just say that Leopard is NOT necessary to install Snow Leopard within VirtualBox.  That's another discussion for another day, but tanolinkranfx's guide is a total rubbish workaround and I've little respect for teaching/preaching any such methodologies.  I won't link to that site for less than obvious reasons.

Change directories and have a look to see what image files we will be working with:
[steph@d830: ~]$ cd ~/Library/VirtualBox/HardDisks/
[steph@d830: HardDisks]$ ls -lh sl.vdi
-rw------- 1 steph staff 10G 11 Mar 14:25 sl.vdi

Use the hexdump (man 1 hexdump) utility included with Apple's OS X to retrieve the value where the raw disk image begins:
[steph@d830: HardDisks]$ hexdump -C -s 0x158 -n 4 sl.vdi
00000158  00 a2 00 00                                       |....|

Excellent, our raw disk begins at offset 0x2a00.  We will now perform a quick calculation to determine how many sectors to section the image file using the bc (man 1 bc) utility included with Apple's OS X.

Note: Sun has stated that, for performance reasons, it will always offset the image evenly on 512-byte sectors:
[steph@d830: HardDisks]$ echo "obase=16; ibase=16; 0A200 / 200" | bc

Now that we have the number of sectors to offset (0x51), we will use hdid to attach the virtual device:

Caveat:  OS X's hdid utility can't understand the .vdi extension; though this is frustrating, it's not a big deal.  We'll create a symlink to a .img file and work on the symlink instead.
[steph@d830: HardDisks]$ ln -s sl.vdi sl.img
[steph@d830: HardDisks]$ ls -lh sl.*
lrwxr-xr-x  1 steph  staff     6B 11 Mar 14:57 sl.img -> sl.vdi
-rw-------  1 steph  staff    10G 11 Mar 14:25 sl.vdi

And now to use the hdid utility to attach the image, note the number of sectors taken from the second step, 0x51, and subsection the file using that value.

Caveat:  Your image may vary, do not use this value without verification!
[steph@d830: HardDisks]$ hdid -section 0x51 sl.img
/dev/disk3           GUID_partition_scheme           
/dev/disk3s1         EFI                             
/dev/disk3s2         Apple_HFS                       /Volumes/VBOX SL

Note that the virtual disk is now located at /dev/disk3, and has two partitions (/dev/disk3s1, and /dev/disk3s2).  This particular virtual image utilizes a GUID partitioning scheme, with an EFI partition at the root of the drive, and an Apple HFS Plus partition consuming the remainder.  Also note that it was auto-mounted under /Volumes/VBOX SL.  You can now work on any given partition, or the disk itself, using standard utilities included with OS X.

You can also use the -nomount flag with the hdid utility to prevent OS X from auto-mounting the partition, or even use the -shadow flag so that changes made to the partition are made to another external file so that you can preserve the image's integrity.  Naturally, you could also mount the partitions as read-only if you so desire.  I highly recommend reading the included manual page (man 8 hdid), as it will include far more information than I can explain in a simple post.

Final Caveat:  Please do not use this on a production image until you are quite familiar with what you're doing.  It will only take a very small miscalculation or misunderstanding for you to entirely wreck the data stored within the image file.  If you're unsure, use the --shadow option within hdid, or copy the file to the /tmp directory and work on it there.  You've been sufficiently warned!


  1. I wrote this shell script to do this for me...
    It even creates a link to a temporary name ending in img to fool hdid...
    I named it mountvdi and I use it like this...
    mountvdi path/to/vdi/file.vdi


    trap "rm -f $TEMP 2>/dev/null" 1 2 3 11 15
    offset=`hexdump -s 0x158 -n 4 "$1" | head -1 | awk '{print $5 $4 $3 $2}'`
    offset512=`echo "obase=16; ibase=16; $offset / 200" | bc`
    ln "$1" "$TEMP"
    echo hdid -section "0x$offset512" \"$TEMP\"
    hdid -section "0x$offset512" "$TEMP"
    rm -f "$TEMP"

  2. Barry Nelson, can you please explain in more detail precisely how to use your script to mount a VirtualBox .vdi file? I have created the script in BBEdit and saved it with both the .sh and .command extension, but I am not sure how to use it to ope my .vdi file. Thank you very much.

    1. BTW, I am running El Capitan final, if that is any help to you in your instructions. Thank you.

  3. This comment has been removed by the author.