I'm trying to close a specific file handle of a process from a kernelmode driver on Windows. For this, I'm using ZwQuerySystemInformation
to enumerate all handles on the system and then filter them based on a given process id and by checking for a specific substring in the handle name. However, I'm not sure how I can close this handle once I found the target. Using NtClose
returns STATUS_INVALID_HANDLE
.
My code looks like this:
BOOL TerminateHandle(DWORD64 processId)
{
BOOL retVal = FALSE;
PSYSTEM_HANDLE_INFORMATION handleInfo = NULL;
PSYSTEM_HANDLE_TABLE_ENTRY_INFO handleEntry = NULL;
POBJECT_NAME_INFORMATION nameInfo = NULL;
ULONG required = 0, size = 0, requiredName = 0;
NTSTATUS handleInfoStatus;
do {
if (handleInfo)
{
fpExFreePool(handleInfo);
handleInfo = NULL;
}
size += 1024;
if(!(handleInfo = fpExAllocatePool(NonPagedPool, size)))
goto Done;
} while ((handleInfoStatus = fpZwQuerySystemInformation(0x10, handleInfo, size, &required)) == STATUS_INFO_LENGTH_MISMATCH);
if (!NT_SUCCESS(handleInfoStatus))
goto Done;
for (DWORD i = 0; i < handleInfo->NumberOfHandles; i++)
{
requiredName = 0;
handleEntry = (PSYSTEM_HANDLE_TABLE_ENTRY_INFO)&handleInfo->Handles[i];
if (handleEntry->UniqueProcessId != processId)
continue;
fpObQueryNameString(handleEntry->Object, NULL, 0, &requiredName);
if (requiredName && (nameInfo = fpExAllocatePool(NonPagedPool, requiredName)))
{
if (NT_SUCCESS(fpObQueryNameString(handleEntry->Object, nameInfo, required, &requiredName)) && nameInfo->Name.Buffer)
{
if (FindSubstring(nameInfo->Name.Buffer, nameInfo->Name.Length / sizeof(WCHAR), L"ExampleSubStr", 13))
{
fpDbgPrintEx(0, 0, "Found: %wZ\n", &nameInfo->Name);
fpDbgPrintEx(0, 0, "Try closing: %x\n", NtClose((HANDLE)handleEntry->HandleValue)); //STATUS_INVALID_HANDLE
}
}
fpExFreePool(nameInfo);
}
}
Done:
if (handleInfo)
fpExFreePool(handleInfo);
return retVal;
}
By the way, is there a way to make this code more efficient? Iterating through all handles of the system is not very resource friendly.