Introduction
In large-scale environments using Virtual Desktop Infrastructure (VDI) platforms like Citrix, incident responders can find it challenging to identify the initial point of compromise. While some setups use non-persistent sessions with golden image restoration, many environments persist user data on remote file servers. Instead of storing profiles as standard folders, it is common to find them stored within Virtual Hard Disk (VHDX) files.
These VHDX files often contain valuable forensic artefacts such as NTUSER.DAT hives and application execution traces. Investigating them manually, however, becomes inefficient at scale, especially when dealing with thousands of user profiles.
This blog post introduces a method for automating forensic analysis of VHDX-based user profiles using Velociraptor, our preferred DFIR tool. The goal is to scale investigations efficiently and reliably without compromising forensic integrity.
VHDX
Virtual Hard Disk v2 (VHDX) is a file format representing a virtual hard disk drive, containing its own partition layout and file system. It is commonly used in VDI environments to store individual user data, such as the roaming profile and the NTUSER.DAT registry hive.
From a forensic perspective, VHDX files can hold high-value artefacts, such as evidence of application execution via UserAssist and persistence mechanisms through registry run keys, both typically found within the NTUSER.DAT hive.
It is common for VDI platforms to store the contents of C:\Users\<Username>\
within a dedicated VHDX file, effectively treating each user profile as a standalone virtual disk image.
The Velociraptor Way
Velociraptor is a modern, open-source DFIR (Digital Forensics and Incident Response) tool used by many organisations to hunt for threats, collect artefacts, and conduct scalable investigations across enterprise environments. The link below provides an introduction to the tool and details on building artefacts.
https://www.infoguard.ch/en/blog/csirt-optimisation-event-log-analysis-recording-dfir
While Velociraptor supports VHDX accessors that allow direct parsing of virtual disk images. This setup typically requires custom artefacts designed for specific use cases, such as parsing UserAssist or registry hives within a mounted VHDX file. Therefore, each forensic check would require a dedicated artefact capable of understanding the VHDX structure.
A more scalable approach is to reuse existing Velociraptor artefacts, such as Windows.Registry.UserAssist
or Windows.Registry.NTUser
, without modification. The purpose of this research was to enable that capability: to support native artefacts when analysing data stored in VHDX-based user profiles.
To achieve this, we leverage virtual Velociraptor clients, instances configured to remap their environment to a specific VHDX file, similar to how Velociraptor operates in deaddisk mode. In this blog post, we’ll refer to these as virtual Velociraptor clients.
The concept is simple: run a virtual client on the file server where VHDX profiles are stored, and remap its configuration to point to one or more VHDX images. Several technical steps are required to make this work reliably. Let’s explore them one by one.
Windows.Sys.Users
Many Velociraptor artefacts which target the user registry, such as Windows.Registry.UserAssist,
access the NTUSER.DAT
hive through the Windows.Registry.NTUser
artefact. However, this artefact relies on Windows.Sys.Users
to enumerate the list of user profiles present on the system.
By default, the Windows.Sys.Users
artefact retrieves user information from the following registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*
This works as expected on endpoint systems but fails on virtual Velociraptor clients, where this registry key relates to the one on the file server and not from the VHDX-based profiles. In such environments, since the key is from a system-based hive, it only reflects the local system users, not those stored in VHDX containers.
As a result, Velociraptor is unable to discover or parse the NTUSER.DAT hives located inside the VHDX files.
To overcome this, we explore two possible solutions:
- Fake registry remapping: inject a synthetic
ProfileList
registry hive. - Artefact override: customise
Windows.Sys.Users
to support VHDX discovery logic.
Fake registry remapping
One approach to solving the user enumeration problem is to remap not only the file system to the VHDX image, but also the ProfileList
registry key. By providing a custom registry hive that mimics this key, Velociraptor can be tricked into “seeing” the VHDX-hosted profiles as if they were locally present.
In the example below, we use PowerShell to:
- Create temporary registry keys for each user.
- Set their
ProfileImagePath
values to simulate the standard Windows user structure. - Export the registry hive to a
.dat
file.
# Define paths for the temporary hive and final file
$tempHivePath = "HKLM\Software\Velociraptor"
$binaryFilePath = "C:/Program Files/Velociraptor/Profile/ProfileList.dat"
# Add the users to the temp hive
reg.exe add "$($tempHivePath)\Brontosaurus" /v "ProfileImagePath" /t REG_EXPAND_SZ /d "C:\Users\Brontosaurus" /f
reg.exe add "$($tempHivePath)\Stegosaurus" /v "ProfileImagePath" /t REG_EXPAND_SZ /d "C:\Users\Stegosaurus" /f
reg.exe add "$($tempHivePath)\Tyrannosaurus" /v "ProfileImagePath" /t REG_EXPAND_SZ /d "C:\Users\Tyrannosaurus" /f
# Export the temp hive
reg exe save $tempHivePath $binaryFilePath
# Cleanup the temp hive
reg.exe delete $tempHivePath /f
Next, we configure a YAML remapping to instruct Velociraptor to mount this exported hive in place of the original ProfileList
key:
- type: mount
description: 'Registry - HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'
from:
accessor: raw_reg
prefix: |
{
"Path": "/"
"DelegateAccessor": "file"
"DelegatePath": "C:/Program Files/Velociraptor/Profile/ProfileList.dat"
}
path_type: registry
"on" :
accessor: registry
prefix: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList
path_type: registry
With this setup, any call to Windows.Sys.Users
will retrieve the synthetic entries we defined, allowing downstream artefacts (like Windows.Registry.NTUser
) to function correctly. However, this approach has limitations. It involves manual steps that must be repeated whenever new users are added. Therefore, it is most suitable for small-scale, targeted investigations or proof-of-concept testing.
Artefact Override
A more robust and scalable solution is to override the default Windows.Sys.Users
artefact. The customised version maintains compatibility with standard systems while adding logic to detect and enumerate VHDX-based profiles when operating in a virtual Velociraptor client context.
The core idea is to introduce a conditional check based on the Velociraptor client’s label. If the client is tagged with a specific label (e.g., remapped_profile), the artefact will scan for NTUSER.DAT files within C:\Users\*\
instead of relying on the traditional registry key.
The VQL override below illustrates this logic:
LET GetTimestamp(High, Low) = if(condition=High,
then=timestamp(winfiletime=High * 4294967296 + Low))
// lookupSID() may not be available on deaddisk analysis
LET Standard = SELECT split(string=Key.OSPath.Basename, sep="-")[-1] as Uid,
"" AS Gid,
LookupSIDCache(SID=Key.OSPath.Basename || "") AS Name,
Key.OSPath as Description,
ProfileImagePath as Directory,
Key.OSPath.Basename as UUID,
Key.Mtime as Mtime,
{
SELECT Mtime
FROM stat(filename=expand(path=ProfileImagePath))
} AS HomedirMtime,
dict(ProfileLoadTime=GetTimestamp(
High=LocalProfileLoadTimeHigh, Low=LocalProfileLoadTimeLow),
ProfileUnloadTime=GetTimestamp(
High=LocalProfileUnloadTimeHigh, Low=LocalProfileUnloadTimeLow)
) AS Data
FROM read_reg_key(globs=remoteRegKey, accessor="registry")
// User list for remapped VHDX profiles emulating the Standard one
LET VHDXProfile = SELECT
OSPath.Components[-2] AS Uid,
OSPath.Dirname AS Directory,
OSPath.Components[-2] AS UUID,
OSPath.Components[-2] AS Name,
"" AS Gid,
Mtime,
Mtime AS HomedirMtime,
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\" + OSPath.Components[-2] AS Description
FROM glob(globs="C:/Users/*/NTUSER.DAT")
// Get the labels of the agent
LET agent_config = SELECT labels FROM config
// Take the appropriate user list method
SELECT * FROM if(condition=agent_config.labels=~labelName, then=VHDXProfile, else=Standard)
Once the artefact override is written, it can be deployed at the server level using the following command:
/usr/local/bin/velociraptor —config /etc/velociraptor/server.config.yaml —definitions /etc/velociraptor/artifact_definitions frontend
With this configuration, the Velociraptor server will automatically distribute the custom artefact to clients. There’s no need to modify individual client configurations. Any virtual client launched with the appropriate label (e.g., remapped_profile) will use the VHDX logic seamlessly.
This is a better solution as it centralises logic, reduces operational overhead, and supports dynamic scaling, making it ideal for multi-user investigations.
Remapping Configuration
Once the user enumeration issue is resolved using the artefact override, the next step is to create a remapping configuration that links specific user profile paths (e.g. C:\Users\Brontomerus
) to their corresponding VHDX files.
This remapping is crucial: it allows Velociraptor’s artefacts, which expect standard Windows paths, to transparently operate on data stored within VHDX containers.
Below is an example of a remapping configuration for the NTFS accessor, pointing C:\Users\Brontomerus
to a specific VHDX file:
- type: mount
description: 'NTFS - Brontomerus'
from:
accessor: raw_ntfs
prefix: |
{
"DelegateAccessor": "offset",
"Delegate": {
"DelegateAccessor": "vhdx",
"DelegatePath": "F:/VHDX/Profile_Brontomerus.VHDX",
"Path":"/1048576"
},
"Path": "/Profile"
}
"on":
accessor: ntfs
prefix: '\\.\C:\Users\Brontomerus'
path_type: ntfs
This remapping allows the virtual Velociraptor client to access the contents of the VHDX file as if it were the actual C:\Users\Brontomerus
directory on disk. To ensure full compatibility with Velociraptor artefacts, similar remappings should be created for:
file
accessor for standard file operationsauto
accessor for hybrid path resolutionregistry
accessor for registry hive access
When these accessors are mapped properly, standard artefacts (like Windows.Registry.NTUser
, Windows.Registry.UserAssist
, etc.) will function as expected within the virtual client context.
Virtual Client Creation
With the remapping configuration in place, we can now launch a virtual Velociraptor client. This is a standalone Velociraptor process that operates like a deaddisk client, using the remapped paths to access the contents of a specific VHDX file as if it were a local user profile.
The following PowerShell command starts the virtual client using the appropriate configuration and remapping YAML file:
Start-Process -FilePath '.\Velociraptor.exe' -ArgumentList '—config client.config.yaml —config.client-writeback-windows="velociraptor_vhdx.writeback.yaml" —config.client-local-buffer-filename-windows="C:\Windows\Temp\velociraptor_vhdx_Buffer.bin" —remap "C:\Program Files\Velociraptor\velociraptor_vhdx_remapping.yaml" —config.client-labels=remapped_profile client' -WorkingDirectory 'C:\Program Files\Velociraptor' -WindowStyle Hidden
Once launched, the virtual client behaves like any standard Velociraptor endpoint, but its file system and registry access are redirected to the contents of the mounted VHDX. This enables seamless browsing of the virtual profile via the Virtual File System (VFS).
It also allows running existing artefacts or any other profile-level checks.
This virtual client is not persistent. If the system reboots or the client crashes, the process must be relaunched. Fortunately, this can be done using the same artefact described later in this post.
Let’s Scale Up
With a single virtual client successfully analysing one user profile, the next logical step is to scale the approach. During real-world incidents, it is common to have multiple users to investigate. Investigating each profile manually is inefficient, so automation and parallelisation become essential.
However, running multiple virtual Velociraptor clients on the same host introduces performance considerations. In our tests, we evaluated three strategies for scaling up to 1,000 user profiles (each stored in a ~2 GB VHDX file).
All in One Remapping
This approach loads all VHDX files into a single remapping configuration, resulting in a YAML file about 2.6 MB in size. While ideally efficient, it caused instability; the virtual client crashed during execution of simple artefacts (e.g., Generic.Client.Info
), probably due to too many VHDX files being open simultaneously, exceeding system limits.
One-to-One Clients
Here, we spun up one virtual Velociraptor client per user profile. This would work best as each profile has its own virtual client, which eases the logic. However, this resulted in excessive system resource usage and hundreds of active processes, which is not sustainable for large-scale investigations.
Batching: The Optimal Middle Ground
The most effective approach was to launch multiple virtual clients, each handling a batch of 40 profiles. This method balances load across processes and avoids overwhelming system resources.
With this configuration, we analysed the UserAssist of 1,000 VHDX files in under 30 seconds.
Use a batching strategy tuned to your environment (e.g. 20–50 profiles per client). The optimal batch size will depend on your hardware and the size of the VHDX files.
Artefacts
The artefacts have been divided into four main functions: the initial setup, the creation of the remapping configuration file, the virtual Velociraptor client runner, and the virtual Velociraptor client remover.
To streamline the investigation of VHDX-based user profiles, we developed a suite of Velociraptor artefacts to automate the entire process, from configuration to client execution and teardown. These artefacts fall into four primary categories:
- Server setup: allow the whole setup to work
- Configuration builder: generates remapping YAML files for virtual clients
- Virtual client runner: launches Velociraptor processes with profile mappings
- Cleanup manager: shuts down virtual clients and removes config artefacts
Windows.Sys.Users (Override)
This custom override of the standard Windows.Sys.Users
artefact handles both traditional systems and virtual clients. It determines which enumeration logic to use based on a label assigned to the client (e.g. remapped_profile
).
Parameters:
remoteRegKey
: Location of the registry key holding the profile list.labelName
: Client label that signals the use of VHDX-based enumeration.
In standard mode, it enumerates from the Windows registry. For virtual clients, it uses a glob
search for C:\Users\*\NTUSER.DAT
, indicating valid user hives within mounted VHDX files.
Windows.Vhdx.RemapConfigBuilder
This artefact generates the remapping configuration files required by each virtual Velociraptor client. It automatically detects user profiles, organises them into batches, and writes the YAML files to disk.
Parameters:
vhdxFolderPath
: Directory containing VHDX profile files.usernameExtractor
: Regex used to extract usernames from filenames.user
: Optional filter to restrict which profiles to process.virtualHostname
: Hostname to assign to the virtual clients.batchSize
: Number of profiles per virtual client.vhdxOffset
: NTFS start offset inside VHDX (default: 1048576).
The artefact creates a Vhdx/Remapping
directory within the Velociraptor staging directory and populates it with one YAML file per batch. Filenames are sorted using the first extracted username for easy lookup. Internally, the artefact uses:
Shadow remapping for
data
,raw_reg
, andzip
accessorsMount remapping for
ntfs
,file
,auto
, andregistry
accessors
Once executed, the artefact will list the path of the created profiles in the results section.
Windows.Vhdx.VirtualClientRunner
This artefact launches one Velociraptor process per remapping file, effectively simulating a client that represents a set of user profiles.
Parameters:
customLabel
: Label to assign to virtual clients (must match label used inWindows.Sys.Users
).remappingFile
: One or more remapping YAML files to launch.
It creates a subdirectory Vhdx/Writeback
for temporary writeback data. Each remapping file is passed into a PowerShell process that starts the virtual client. Once executed, the artefact lists all successfully started virtual clients.
Windows.Vhdx.VirtualClientRemover
This artefact stops running virtual clients and optionally deletes all related configuration files.
Parameters:
RemappingFile
: Specific remapping file or directory to target.RemoveConfiguration
: If enabled, deletesVhdx
folder and its subfolders.ReallyKillProcess
: If enabled, terminates running Velociraptor processes.
It searches for running clients based on remapping file usage and performs cleanup accordingly.
Security Considerations
All testing described in this research was conducted on offline VHDX files, that is, files no longer actively managed by services like Citrix or Windows profile management tools.
In live environments, where VHDX profiles may still be in use or mounted, several risks should be considered:
- Writeback conflicts: If Velociraptor or the OS attempts to write to an active VHDX file, it may result in data corruption or race conditions.
- Profile locking: Some virtualisation platforms may lock VHDX files during use, preventing remapping or causing artefact failures.
- System performance: Mounting and scanning a large number of VHDX files can place a significant load on the host system.
Recommendations:
- Perform investigations on copies of VHDX files whenever possible.
- Avoid using this approach directly on live Citrix or VDI environments without controlled testing.
- Start with small user subsets and adjust batch size based on your environment’s capacity.
- Monitor resource usage (I/O, memory, open handles) when scaling beyond hundreds of profiles.
While we successfully analysed 1,000 small (2 GB) VHDX profiles in under a minute, larger profiles or more aggressive batching may introduce bottlenecks. Tailor your approach to match the capabilities and constraints of your infrastructure.
Conclusion
This VHDX Velociraptor artefact suite provides a scalable and efficient method for conducting forensic investigations across user profiles stored in VHDX files. By leveraging virtual clients with remapped environments, analysts can reuse standard artefacts, such as UserAssist
or NTUSER.DAT
parsers, without modification.
In our testing, this approach enabled the analysis of over 1,000 VHDX profiles in under a minute, significantly reducing the effort and complexity traditionally associated with VHDX triage.
While further validation is recommended in live or larger-scale environments, this methodology opens the door to high-volume, profile-level investigations using familiar DFIR tooling, without sacrificing speed or forensic integrity.