本文共计4186个字,预计阅读时长15.7分钟。
原理
首先我们要知道驱动加载后, 会向对象目录表中的\driver 与\FileSystem 写入 驱动服务名, 那么我们只需要遍历这两张表拿到名称, 通过ObReferenceObjectByName函数即可获取驱动对象。而在这里我们可以使用微软提供的ZwQueryDirectoryObject函数获取对应的对象目录表。
遍历驱动代码
auto EnumerateObject = [&](UNICODE_STRING* Directory)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
OBJECT_ATTRIBUTES ObjAttr = { 0 };
HANDLE FileHandle = 0;
IO_STATUS_BLOCK IoStatusBlock = { 0 };
PVOID FileInformation = 0;
ULONG Length = sizeof(FILE_DIRECTORY_INFORMATION); // 这个数设置的太小会导致ZwQueryDirectoryFile蓝屏。
UNICODE_STRING driverName = RTL_CONSTANT_STRING(L"Driver");
InitializeObjectAttributes(&ObjAttr, Directory, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
ntStatus = ZwOpenDirectoryObject(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ObjAttr);
if (!NT_SUCCESS(ntStatus)) return ntStatus;
Length = Length + 520; // 为何加这个数字,请看ZwEnumerateFile1的说明。
FileInformation = ExAllocatePool(NonPagedPool, Length);
if (NULL == FileInformation)
{
ZwClose(FileHandle);
return STATUS_UNSUCCESSFUL;
}
RtlZeroMemory(FileInformation, Length);
BOOLEAN RestartScan;
ULONG Context = 0;
ULONG ReturnedLength = 0;
do
{
UNICODE_STRING FileName = { 0 };
POBJECT_DIRECTORY_INFORMATION podi = 0;
UNICODE_STRING FullName = { 0 };
RestartScan = FALSE; // 为TRUE会导致死循环;
ntStatus = ZwQueryDirectoryObject(FileHandle, FileInformation, Length, TRUE, RestartScan, &Context, &ReturnedLength);
if (STATUS_NO_MORE_FILES != ntStatus && STATUS_SUCCESS != ntStatus)
return ntStatus;
podi = (POBJECT_DIRECTORY_INFORMATION)FileInformation;
// 不是驱动对象就放过。
if (RtlCompareUnicodeString(&podi->TypeName, &driverName, TRUE) != 0)
{
continue;
}
// 申请要显示的内存,另一思路是格式化。
FullName.MaximumLength = (USHORT)Length + Directory->MaximumLength;
FullName.Buffer = (PWCH)ExAllocatePool(NonPagedPool, FullName.MaximumLength);
if (NULL == FullName.Buffer) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlZeroMemory(FullName.Buffer, FullName.MaximumLength);
RtlCopyUnicodeString(&FullName, Directory);
ntStatus = RtlAppendUnicodeToString(&FullName, L"\\");
if (!NT_SUCCESS(ntStatus)) {
ExFreePool(FullName.Buffer);
break;
}
ntStatus = RtlAppendUnicodeStringToString(&FullName, &podi->Name);
if (!NT_SUCCESS(ntStatus)) {
ExFreePool(FullName.Buffer);
break;
}
//DBG_PRINT("Name %wZ\n", &FullName);
PDRIVER_OBJECT DriverObject = nullptr;
/* 对比查找 */
ntStatus = ObReferenceObjectByName(
&FullName,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL, FILE_ANY_ACCESS,
*IoDriverObjectType,
KernelMode,
NULL,
(PVOID*)&DriverObject
);
if (NT_SUCCESS(ntStatus))
{
/* Add */
Mylist->push(DriverObject);
}
ExFreePool(FullName.Buffer);
} while (STATUS_NO_MORE_FILES != ntStatus);
if (STATUS_NO_MORE_FILES == ntStatus)
ntStatus = STATUS_SUCCESS;
if (FileInformation)
{
ExFreePool(FileInformation);
FileInformation = NULL;
}
ZwClose(FileHandle);
return ntStatus;
};
测试用例 分别遍历 driver 与 FileSystem 两个目录
UNICODE_STRING directory = RTL_CONSTANT_STRING(L"\\driver");
UNICODE_STRING FileSystem = RTL_CONSTANT_STRING(L"\\FileSystem");
ntStatus = EnumerateObject(&directory);
ntStatus = EnumerateObject(&FileSystem);
遍历系统中所有的驱动对象