NtQueryVolumeInformationFile
Retrieves filesystem and volume properties (label, size, device type, attributes) for the volume backing a file handle.
Prototype
NTSTATUS NtQueryVolumeInformationFile( HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| FileHandle | HANDLE | in | Handle to any file or directory on the volume of interest; FILE_READ_ATTRIBUTES is sufficient. |
| IoStatusBlock | PIO_STATUS_BLOCK | out | Receives the completion status and number of bytes written to FsInformation. |
| FsInformation | PVOID | out | Caller-supplied buffer that receives the volume info structure matching FsInformationClass. |
| Length | ULONG | in | Size in bytes of the FsInformation buffer. |
| FsInformationClass | FS_INFORMATION_CLASS | in | Which class to retrieve: FileFsVolumeInformation=1, Label=2, Size=3, Device=4, Attribute=5, etc. |
Syscall IDs by Windows version
| Windows version | Syscall ID | Build |
|---|---|---|
| Win10 1507 | 0x49 | win10-1507 |
| Win10 1607 | 0x49 | win10-1607 |
| Win10 1703 | 0x49 | win10-1703 |
| Win10 1709 | 0x49 | win10-1709 |
| Win10 1803 | 0x49 | win10-1803 |
| Win10 1809 | 0x49 | win10-1809 |
| Win10 1903 | 0x49 | win10-1903 |
| Win10 1909 | 0x49 | win10-1909 |
| Win10 2004 | 0x49 | win10-2004 |
| Win10 20H2 | 0x49 | win10-20h2 |
| Win10 21H1 | 0x49 | win10-21h1 |
| Win10 21H2 | 0x49 | win10-21h2 |
| Win10 22H2 | 0x49 | win10-22h2 |
| Win11 21H2 | 0x49 | win11-21h2 |
| Win11 22H2 | 0x49 | win11-22h2 |
| Win11 23H2 | 0x49 | win11-23h2 |
| Win11 24H2 | 0x49 | win11-24h2 |
| Server 2016 | 0x49 | winserver-2016 |
| Server 2019 | 0x49 | winserver-2019 |
| Server 2022 | 0x49 | winserver-2022 |
| Server 2025 | 0x49 | winserver-2025 |
Kernel module
Related APIs
Syscall stub
4C 8B D1 mov r10, rcx B8 49 00 00 00 mov eax, 0x49 F6 04 25 08 03 FE 7F 01 test byte ptr [0x7FFE0308], 1 75 03 jne short +3 0F 05 syscall C3 ret CD 2E int 2Eh C3 ret
Undocumented notes
Backs the entire Win32 `GetVolumeInformationW` / `GetDiskFreeSpaceExW` / `GetDriveTypeW` family. The kernel routes the IRP via `IopXxxControlFile` → `IRP_MJ_QUERY_VOLUME_INFORMATION` to the filesystem driver mounted on the device object underlying `FileHandle` (NTFS, FAT32, exFAT, ReFS, network redirectors). The SSN `0x49` is one of the longest-stable syscall numbers in the entire NT table — unchanged from Windows 10 1507 through Win11 24H2 and Server 2025 — because `Query` and `Set` volume info have been ABI-locked since NT 3.51. The five most-used classes in practice are: `FileFsVolumeInformation` (label + serial + creation time), `FileFsLabelInformation` (write-only sibling), `FileFsSizeInformation` (sectors/clusters/free), `FileFsDeviceInformation` (`FILE_DEVICE_DISK` vs `FILE_DEVICE_CD_ROM` vs `FILE_DEVICE_NETWORK_FILE_SYSTEM`), and `FileFsAttributeInformation` (filesystem name + flags such as `FILE_READ_ONLY_VOLUME`).
Common malware usage
**This is one of the single most-used syscalls in modern ransomware.** LockBit (all generations 1.0 → 4.0 / Black), BlackCat / ALPHV, Royal, Conti, Hive, Akira and BlackSuit all walk drive letters `A:` through `Z:`, open each root, and issue `NtQueryVolumeInformationFile(FileFsDeviceInformation)` to learn the device type — that's how they decide that `D:` is removable USB (encrypt with high priority and use a different ransom-note template), `Z:` is `FILE_DEVICE_NETWORK_FILE_SYSTEM` (encrypt over SMB — high impact, fast lateral spread), and `X:` is a CD-ROM (skip). They also pull `FileFsAttributeInformation` to detect `FILE_READ_ONLY_VOLUME` and skip Windows recovery / boot media that would only waste IO and trigger SmartScreen. Some families (Conti leak) further fingerprint `FileFsVolumeInformation::SerialNumber` to deduplicate logical mounts pointing at the same physical volume — preventing double-encryption of an iSCSI LUN.
Detection opportunities
Sysmon has no event for this; it's a Tier-1 syscall used by Explorer, Defender, Backup APIs and basically every storage UI. Detection must look at *patterns*: a single process issuing `NtQueryVolumeInformationFile(FileFsDeviceInformation)` against more than ~5 distinct root handles within seconds, especially when followed by `NtOpenFile` enumerations of those roots, is the canonical ransomware drive-discovery footprint. Microsoft Defender for Endpoint detects this via the `BehaviorEntities` schema: a single PID touching `FsRtl`-marked root handles across multiple `DeviceType` values within 60 s scores heavily on the `Ransomware:Behavior:DriveEnumeration` rule. ETW provider `Microsoft-Windows-Kernel-File` event 12/14 with `IrpFlags & IRP_MJ_QUERY_VOLUME_INFORMATION` gives kernel-level visibility without depending on user-mode hooks (which the ransomware bypasses via direct syscall).
Direct syscall examples
asmx64 direct stub
; Direct syscall stub for NtQueryVolumeInformationFile (SSN 0x49 across all builds)
NtQueryVolumeInformationFile PROC
mov r10, rcx ; syscall convention
mov eax, 49h ; SSN — historically stable, but resolve dynamically anyway
syscall
ret
NtQueryVolumeInformationFile ENDPcRansomware-style drive enumeration (FileFsDeviceInformation)
// Classic LockBit/Conti pattern: probe A: through Z:, classify by DeviceType,
// pick encryption order accordingly. FILE_READ_ATTRIBUTES is enough access.
typedef struct _FILE_FS_DEVICE_INFORMATION {
ULONG DeviceType; // FILE_DEVICE_DISK=0x07, _CD_ROM=0x02, _NETWORK_FILE_SYSTEM=0x14
ULONG Characteristics; // FILE_REMOVABLE_MEDIA=0x01, FILE_READ_ONLY_DEVICE=0x02, ...
} FILE_FS_DEVICE_INFORMATION;
for (WCHAR d = L'A'; d <= L'Z'; ++d) {
WCHAR path[] = L"\\??\\X:\\"; path[4] = d;
UNICODE_STRING us; RtlInitUnicodeString(&us, path);
OBJECT_ATTRIBUTES oa; InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE h; IO_STATUS_BLOCK iosb;
if (!NT_SUCCESS(NtOpenFile(&h, FILE_READ_ATTRIBUTES, &oa, &iosb,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE))) continue;
FILE_FS_DEVICE_INFORMATION info = { 0 };
NtQueryVolumeInformationFile(h, &iosb, &info, sizeof(info),
4 /* FileFsDeviceInformation */);
// info.DeviceType / info.Characteristics now drive encryption strategy.
NtClose(h);
}rustFileFsAttributeInformation — skip read-only volumes
// Cargo: ntapi = "0.4", winapi = { version = "0.3", features = ["ntstatus", "winnt"] }
use ntapi::ntioapi::{NtQueryVolumeInformationFile, IO_STATUS_BLOCK, FileFsAttributeInformation};
use std::mem::MaybeUninit;
#[repr(C)]
struct FileFsAttributeInfo {
file_system_attributes: u32, // FILE_READ_ONLY_VOLUME = 0x00080000
maximum_component_name_length: i32,
file_system_name_length: u32,
file_system_name: [u16; 32],
}
unsafe fn is_read_only(h: *mut core::ffi::c_void) -> bool {
let mut iosb: MaybeUninit<IO_STATUS_BLOCK> = MaybeUninit::uninit();
let mut info: MaybeUninit<FileFsAttributeInfo> = MaybeUninit::uninit();
let st = NtQueryVolumeInformationFile(
h, iosb.as_mut_ptr(), info.as_mut_ptr().cast(),
core::mem::size_of::<FileFsAttributeInfo>() as u32,
FileFsAttributeInformation,
);
st >= 0 && (info.assume_init().file_system_attributes & 0x0008_0000) != 0
}MITRE ATT&CK mappings
Last verified: 2026-05-20