获取卷信息

使用内核链表和快速互斥体。

快速互斥体不支持递归获取,也就是不允许自己线程重复获取。

一般互斥体只其他线程,自己线程可以多次取得。

1
2
3
4
5
6
7
8
9
10
11
FAST_MUTEX __VolumeInfoLock;
LIST_ENTRY __VolumeInfoList;


void InitializeVolumeInfo()
{
ExInitializeFastMutex(&__VolumeInfoLock);
InitializeListHead(&__VolumeInfoList);

EnumVolumeInfo();
}

枚举卷信息

从A盘开始,将路径转为UnicodeString,再转到OA,调用ZwCreateFile获取卷句柄,调用ZwQueryObject获取对象信息,插入数据结构中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
void EnumVolumeInfo()
{
WCHAR DosDevice[] = L"\\DosDevices\\X:";
UNICODE_STRING v1;
WCHAR i;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE VolumeHandle;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;

OBJECT_NAME_INFORMATION* ObjectNameInfo = NULL;
ULONG ObjectNameInfoLength = BUFFER_SIZE_MAX;

FreeVolumeInfo();

ObjectNameInfo = (OBJECT_NAME_INFORMATION*)AllocateBufferFromLookAsideList(); // 动态申请内存
if (ObjectNameInfo == NULL)
return;

for (i = 0; i < 26; i++)
{
// 从A盘开始遍历
DosDevice[12] = L'A' + i;

RtlInitUnicodeString(&v1, DosDevice);

InitializeObjectAttributes(&ObjectAttributes,
&v1, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);

Status = ZwCreateFile(
&VolumeHandle,
SYNCHRONIZE | FILE_ANY_ACCESS,
&ObjectAttributes,
&IoStatusBlock,
NULL,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE,
NULL,
0);

if (NT_SUCCESS(Status) == FALSE)
continue;

ObjectNameInfoLength = BUFFER_SIZE_MAX;
Status = ZwQueryObject(VolumeHandle, 1, ObjectNameInfo, ObjectNameInfoLength,
&ObjectNameInfoLength);
if (NT_SUCCESS(Status) == TRUE)
AddVolumeInfo(VolumeHandle, L'A' + i, &ObjectNameInfo->Name);

ZwClose(VolumeHandle);
}

if (ObjectNameInfo != NULL)
FreeBufferToLookAsideList(ObjectNameInfo);
}

解析卷信息

ObReferenceObjectByHandle从句柄到对象,FileObject->DeviceObject->Vpb由文件对象获取Vpb,Vpb->DeviceObject获取Vpb对象,判断是否存在。

动态申请VOLUME_INFO结构,将各种信息放入,插入链表中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
void AddVolumeInfo(
HANDLE VolumeHandle,
WCHAR VolumeName,
UNICODE_STRING* DeviceName)
{
VOLUME_INFO* v5 = NULL;
FILE_OBJECT* FileObject = NULL;
PVPB Vpb = NULL;
DEVICE_OBJECT* VpbDeviceObject = NULL;

ULONG v7 = sizeof(VOLUME_INFO) + (DeviceName->Length + 1) * sizeof(WCHAR);

NTSTATUS Status = ObReferenceObjectByHandle(VolumeHandle,
0, 0, KernelMode, (PVOID*)&FileObject, NULL);
if (!NT_SUCCESS(Status))
{
return;
}

if (!FileObject || !FileObject->DeviceObject || !FileObject->DeviceObject->Vpb)
{
goto Exit;
}

Vpb = FileObject->DeviceObject->Vpb; //卷参数块 (VPB) 结构用于将表示已装载的文件系统卷的设备对象映射到表示物理或虚拟磁盘设备的设备对象 https://learn.microsoft.com/zh-cn/windows-hardware/drivers/ddi/wdm/ns-wdm-_vpb
VpbDeviceObject = Vpb->DeviceObject;
if (!VpbDeviceObject)
{
goto Exit;
}

v5 = (VOLUME_INFO*)AllocateBuffer(v7);
if (v5 == NULL)
{
goto Exit;
}
v5->DeviceObject = FileObject->DeviceObject;
v5->VpbDeviceObject = VpbDeviceObject;
v5->VolumeName = VolumeName;
memcpy(&v5->DeviceName[0], DeviceName->Buffer, DeviceName->Length);
v5->Length = DeviceName->Length / sizeof(WCHAR);


ExAcquireFastMutex(&__VolumeInfoLock);
InsertTailList(&__VolumeInfoList, &v5->ListEntry);

ExReleaseFastMutex(&__VolumeInfoLock);
Exit:
ObDereferenceObject(FileObject);
return;
}

释放卷信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
VOID FreeVolumeInfo()
{

VOLUME_INFO* v5 = NULL;
LIST_ENTRY* v1 = NULL;

ExAcquireFastMutex(&__VolumeInfoLock);

if (IsListEmpty(&__VolumeInfoList) == TRUE)
goto Exit;

while (IsListEmpty(&__VolumeInfoList) == FALSE)
{
v1 = RemoveHeadList(&__VolumeInfoList);
if (v1 == NULL)
continue;

v5 = CONTAINING_RECORD(v1, VOLUME_INFO, ListEntry);
if (v5 == NULL)
continue;

FreeBuffer(v5);
}

Exit:
InitializeListHead(&__VolumeInfoList);
ExReleaseFastMutex(&__VolumeInfoLock);
}