mtt.sh – Mounting Linux Images

Commercial forensic tools often struggle with accessing Linux disk images. To be fair, Linux disk images are often an unholy tangle of Linux software RAID, the Linux logical volume manager, and various different file system types that need to be reconstructed into their original layout. Then add virtual disks that may have been grown incrementally by simply adding new segments as needed. It can be a puzzle putting everything back together.

When working with teams on Linux investigations, I’m often called on to deal with the difficult Linux images. But I wanted to give my teammates a self-service option for mounting these images. Developing a tool that would handle automagically mounting as many different Linux image scenarios as possible has become a passion project for me. The result is “mtt.sh“, a script that can do this:

# mtt.sh -d /mnt/test disk1.E01 disk2.E01
Making /mnt/test, hope that is OK
# ls /mnt/test/files
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr

This image has two disks in a RAID1 configuration with a Linux LVM volume group that contains both EXT4 and XFS file systems which also happen to be “dirty” (incomplete transactions in the file system journals). mtt.sh handled mounting the image in a forensically sound manner without breaking a sweat. Add the “-E” option and mtt.sh will export E01s of each logical volume after mounting so that forensic tools can parse things more easily.

Interested yet? Let’s get into it!

Getting Started

mtt.sh relies on several other tools: qemu-img for VMDKs, ewfmount for E01s, and xmount for some shenanigans I’ve documented elsewhere. So before we get started, we should install those dependencies:

apt install qemu-utils ewf-tools xmount

Note that mtt.sh will run without these dependencies as long as we don’t care about VMDKs, E01s, or shenanigans.

mtt.sh is part of my “Digital Forensic Investigative Scripts” project on Github:

git clone https://github.com/halpomeranz/dfis.git
cp dfis/mtt.sh /usr/local/bin/mtt.sh

Running “mtt.sh --help” gives a summary of the various options:

Usage: mtt.sh [-D] [-W | -V/A newname ] [-E [-S chunksize]] [-d mountpoint] images
       mtt.sh [-D] -U mountpoint

    -D          Output debugging details

    -d dir      Specify mounting point (default is "mount")
    -E          Export E01s of partitions from image
    -S size     Specify the max segment size for E01 exports (in bytes)

    -W          Mount image with writable cache file
    -V newname  Change volume group name before mounting
    -A newname  Change VG name and all UUIDs before mounting

    -U dir      Unmount everything on dir

Currently mtt.sh handles images in VMDK, E01, and raw format. For E01 images, just specify the first chunk with the “.E01” extension and ewfmount will figure out the rest, assuming all the chunks are in the same directory.

Mounting and Unmounting

The typical usage is to specify a target directory for the mount (“-d“) and one or more image files. Add the “-D” flag (“debugging”) and mtt.sh shows what it’s doing:

# mtt.sh -D -d /mnt/test disk1.E01 disk2.E01
+++++ Image(s): disk1.E01 disk2.E01
+++++ Dir: /mnt/test
+++++ Xmount=0 / MakeWritable=0
+++++ ChangeUUIDs=0 / NewVGname=
+++++ Exports: 0
+++++ Debug: 1
+++++ (cd "/images/lab09"; ewfmount "disk1.E01" "/mnt/test/img/file0")
+++++ RAID device: /dev/md/localhost:boot
+++++ RAID device: /dev/md/localhost:pv00
+++++ (cd "/images/lab09"; ewfmount "disk2.E01" "/mnt/test/img/file1")
+++++ RAID device: /dev/md/localhost:pv00
+++++ RAID device: /dev/md/localhost:boot
+++++ /dev/md/localhost:pv00: volume group "grp1"
+++++ fs_type[/dev/grp1/home] set to "xfs"
+++++ fs_type[/dev/grp1/root] set to "xfs"
+++++ /dev/grp1/root is root device
+++++ fs_type[/dev/md/localhost:boot] set to "ext4"
+++++ mount_device(/dev/grp1/root, /mnt/test/files, xfs)
+++++ mount -o ro,noexec,norecovery /dev/grp1/root "/mnt/test/files"
+++++ mount_device(UUID=fbd719a9-9a94-491d-a5aa-c16aa407a23e, /mnt/test/files/boot, ext4)
+++++ mount -o ro,noexec,noload -t ext4 UUID=fbd719a9-9a94-491d-a5aa-c16aa407a23e "/mnt/test/files/boot"
+++++ mount_device(/dev/mapper/grp1-home, /mnt/test/files/home, xfs)
+++++ mount -o ro,noexec,norecovery /dev/mapper/grp1-home "/mnt/test/files/home"

In addition, mtt.sh creates a text file called MOUNTING in the target directory. This file contains the exact commands that were used to mount the image:

# cat /mnt/test/MOUNTING
mkdir -p "/mnt/test/files"
mkdir -p "/mnt/test/img/file0"
(cd "/images/lab09"; ewfmount "disk1.E01" "/mnt/test/img/file0")

losetup -rfP "/mnt/test/img/file0/ewf1"

mkdir -p "/mnt/test/img/file1"
(cd "/images/lab09"; ewfmount "disk2.E01" "/mnt/test/img/file1")

losetup -rfP "/mnt/test/img/file1/ewf1"

sleep 1
vgchange -a y grp1

mount -o ro,noexec,norecovery /dev/grp1/root "/mnt/test/files"
mount -o ro,noexec,noload -t ext4 UUID=fbd719a9-9a94-491d-a5aa-c16aa407a23e "/mnt/test/files/boot"
mount -o ro,noexec,norecovery /dev/mapper/grp1-home "/mnt/test/files/home"

mtt.sh also has a “-U” option to unmount a mounted directory. It will unwind LVM volume groups, RAID arrays, loopback mounts, etc. And again “-D” shows what’s happening:

# mtt.sh -D -U /mnt/test
+++++ unmounted "/mnt/test/files/home" (device is "/dev/mapper/grp1-home")
+++++ volume group name grp1
+++++ Found RAID device /dev/md126
+++++ unmounted "/mnt/test/files/boot" (device is "/dev/md127")
+++++ Found RAID device /dev/md127
+++++ unmounted "/mnt/test/files" (device is "/dev/mapper/grp1-root")
+++++ volume group name grp1
+++++ Found RAID device /dev/md126
+++++ vgchange -a n grp1
+++++ Stopping RAID devices /dev/md126 /dev/md127
+++++ Disconnecting loop devices
+++++ ewfmount: unmounting "/mnt/test/img/file*"

Note that when unmounting, just specify the directory to unmount without “-d“.

Exporting Logical Images

If we’re planning on analyzing the image with a commercial forensic tool, it’s often useful to create logical images of the individual file systems. That way we can analyze the data without having to use Linux and mtt.sh to get everything mounted.

When using mtt.sh to mount an image, add the “-E” (“export”) option to export logical images of each mounted file system as E01s. Add a “-S size” option to specify the size (in bytes) of the chunks in the export. The default is 4294967296 (4GiB).

The exported images are written to the “exported” subdirectory of the target directory. Make sure the file system where the image is mounted has enough space to receive the exported data!

# mtt.sh -E -d /mnt/test disk1.E01 disk2.E01
[...]

Status: at 95%.
acquired 72 GiB (77761282048 bytes) of total 76 GiB (81830871040 bytes).
completion in 7 second(s) with 503 MiB/s (527941103 bytes/second).

Status: at 97%.
acquired 74 GiB (79835004928 bytes) of total 76 GiB (81830871040 bytes).
completion in 4 second(s) with 500 MiB/s (524556865 bytes/second).

Acquiry completed at: Oct 17, 2026 00:32:28

Written: 76 GiB (81830872356 bytes) in 2 minute(s) and 35 second(s) with 503 MiB/s (527941111 bytes/second).
MD5 hash calculated over data: a0fbcc858ddba2426e999a793f17eeaa
ewfacquire: SUCCESS
# ls -lh /mnt/test/exported/
total 2.3G
-rw-r--r-- 1 root root 194M Oct 17 00:29 test-boot.E01
-rw-r--r-- 1 root root 860 Oct 17 00:29 test-boot.txt
-rw-r--r-- 1 root root 409M Oct 17 00:32 test-home.E01
-rw-r--r-- 1 root root 7.4K Oct 17 00:32 test-home.txt
-rw-r--r-- 1 root root 1.7G Oct 17 00:29 test-root.E01
-rw-r--r-- 1 root root 3.9K Oct 17 00:29 test-root.txt

The *.txt files are a log of each acquisition along with the calculated hash value for the logical image.

Shenanigans

I’ve previously blogged about issues with mounting images that have duplicate LVM volume names and UUIDs. The short summary is that if we have two images with the same volume name or UUIDs Linux will flatly refuse to mount the second image. Unfortunately it’s all too common to encounter images that were derived from the same “master” image, resulting in two images that have identical RAID, LVM, and file system UUIDs even though they are different images with different file system content. But we often want to mount these images side by side.

To finesse this issue, mtt.sh has options to change the LVM volume name and all significant file system UUIDs. In order to accomplish this without permanently changing the original image files, mtt.sh uses xmount to create a writable cache file in front of the original images. All changes are written in the cache file only, leaving the original images files untouched.

Use “-V newname” to change just the LVM volume group name– for example when there are two different images that use the same generic LVM name. Use “-A newname” to change both the LVM volume name and the image UUIDs. Below we are mounting the same image on two different directories to demonstrate that the name/UUID changing code works:

# mtt.sh -A test1 -d /mnt/test1 disk1.E01 disk2.E01
Making /mnt/test1, hope that is OK
# mtt.sh -A test2 -d /mnt/test2 disk1.E01 disk2.E01
Making /mnt/test2, hope that is OK
# ls /mnt/test*/files
/mnt/test1/files:
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr

/mnt/test2/files:
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr

Note that if an image is already mounted with the unmodified name/UUIDs, then mtt.sh fails when mounting a second image– even with the “-V” or “-A” option enabled. This is because Linux detects the duplicate information and interferes long before mtt.sh has a chance to change anything. So make to use “-V“/”-A” from the start if mounting images like this side by side.

Aside from modifying the volume name and UUIDs, mtt.sh also needs to change the file system UUIDs as well. Unfortunately this is not possible on a “dirty” file system. So “mtt.sh -A” needs to mount each file system read-write so that the journal can be replayed. As with everything else, these changes are only reflected in the cache file and not in the original image files. But the file system we end up looking at may end up being slightly different from what we see if we looked at the original “dirty” file system. Once the journal has been cleared, mtt.sh unmounts the file system, changes the UUID, and remounts the file system in read-only mode.

However, there are sometimes weird cases where it is useful to experiment with a writable version of the image. The “-W” (“writable”) option uses the same cache file hack that “-V” and “-A” use but doesn’t change any of the LVM name and UUID info. Instead it mounts the file systems in read-write mode. Any changes we make will be written to the cache file and not impact the original image.

# mtt.sh -W -d /mnt/test disk1.E01 disk2.E01
Making /mnt/test, hope that is OK
# echo yes I can write here >>/mnt/test/files/newfile
# ls -l /mnt/test/files/newfile
-rw-r--r-- 1 root root 21 Oct 17 01:07 /mnt/test/files/newfile

Like the “-A” option, “-W” has the side-effect of clearing out any unfinished transactions in the file system journal. So with “-W” what we see is the file system as it would look after rebooting and journal recovery.

Leave a Reply