Closing file handle of process from kernelmode driver

Dear members,

I need to edit a system configuration file from a kernel mode driver. However, I am unable to open the file using ZwCreateFile because another process has an open handle to this file (ZwCreateFile returns STATUS_SHARING_VIOLATION). I thought that the easiest way to solve this problem is to simply close the handle that’s blocking the access. To do this, I use ZwQuerySystemInformation to enumerate all handles and then filter them out based on process id and a specific substring in the object name. However, once I found the target handle I cannot close it using Zw/NtClose (STATUS_INVALID_HANDLE). Why does this error occur and how can I properly close the handle?

My current code looks as follows (note: the code is running from a system thread inside the System process, and the handles I was testing this with were also in the System process, so the handles should be valid):

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, requiredName, &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;
}

Thank you for your help in advance!

What you are proposing will likely cause the application that is currently using the file to crash, is this really your intent? First why do you think you need this? Second, if you do need this would renaming the existing file, copying it to a new version with your changes, and finally marking the old file for deletion do what you want? The second approach doesn’t need to go through all challenges of walking the handle table which is a bad idea, and does not crash the running application, though depending on what has the file open it could still mess up the system, so you really need to think about this.

@Don_Burn said:
What you are proposing will likely cause the application that is currently using the file to crash, is this really your intent? First why do you think you need this? Second, if you do need this would renaming the existing file, copying it to a new version with your changes, and finally marking the old file for deletion do what you want? The second approach doesn’t need to go through all challenges of walking the handle table which is a bad idea, and does not crash the running application, though depending on what has the file open it could still mess up the system, so you really need to think about this.

Thank you for your answer.
Of course stability is an important aspect here. Through testing with external tools I was able to verify that closing the handle does not crash the application or cause any other negative side effects. I cannot just create a new file and delete the old one because the path to the file is hardcoded in Windows system components and is used during the OS initialization - this means I really need to be able to modify the already existing file or at least get a handle to it to overwrite it.

“Of course stability is an important aspect here. Through testing with external tools I was able to verify that closing the handle does not crash the application or cause any other negative side effects.”

Verifying that something will not have negative effects is extremely hard. Doing it once or twice is not enough, you basically have to analyze the code, and all subsequent versions of the code to ensure it won’t cause problems. I don’t know how you do that.

“I cannot just create a new file and delete the old one because the path to the file is hardcoded in Windows system components and is used during the OS initialization - this means I really need to be able to modify the already existing file or at least get a handle to it to overwrite it.”

This is why I recommended renaming the existing file, so you could create one with the hardcoded path. Note: even then the if the application is modifying the file you lose the modifications which is not what people are going to expect.

Before you go further step back and explain to the group what you are trying to do. There are ways to get access to the file, but your approach is just wrong.

1 Like

@Don_Burn said:
“Of course stability is an important aspect here. Through testing with external tools I was able to verify that closing the handle does not crash the application or cause any other negative side effects.”

Verifying that something will not have negative effects is extremely hard. Doing it once or twice is not enough, you basically have to analyze the code, and all subsequent versions of the code to ensure it won’t cause problems. I don’t know how you do that.

“I cannot just create a new file and delete the old one because the path to the file is hardcoded in Windows system components and is used during the OS initialization - this means I really need to be able to modify the already existing file or at least get a handle to it to overwrite it.”

This is why I recommended renaming the existing file, so you could create one with the hardcoded path. Note: even then the if the application is modifying the file you lose the modifications which is not what people are going to expect.

Before you go further step back and explain to the group what you are trying to do. There are ways to get access to the file, but your approach is just wrong.

Alright. So first off, I’m relatively new to kernel programming (although I have quite some experience with low level Windows development), so I might be missing an obvious point here.
I’ll try to explain the situation in a more detailed way:

I want to modify a system configuration file that is used during the initialization of the Windows OS. My attempts to alter the file are failing as the System process (PID 4) always has an open handle to this file (from boot to shutdown). This handle prevents me from reading, writing, superseding, renaming or deleting the file (STATUS_SHARING_VIOLATION). As I am not aware of other ways to modify the file, the only solution to this I can think of is closing this handle. From my tests and investigation (reverse engineering and blackbox testing) I can tell that there are no obvious complications if this handle gets closed by external code - of course, this would require more testing before it can be implemented in a finished product, but for now it seems like the only viable option to me.

I hope this clears things up!

Instead of force closing the existing handle, I suggest looking into invoking IoCreateFileEx with IO_IGNORE_SHARE_ACCESS_CHECK. However, it seems unlikely that modifying a file that’s presently opened by a system component with exclusive share access is not going to have negative consequences, since that component is probably not expecting its contents to change under its feet, so I echo Don’s warnings that this is probably not the right approach.

@Koby_Kahane said:
Instead of force closing the existing handle, I suggest looking into invoking IoCreateFileEx with IO_IGNORE_SHARE_ACCESS_CHECK. However, it seems unlikely that modifying a file that’s presently opened by a system component with exclusive share access is not going to have negative consequences, since that component is probably not expecting its contents to change under its feet, so I echo Don’s warnings that this is probably not the right approach.

I didn’t know about IoCreateFileEx, thank you! The file gets changed very frequently and can even be changed by the user through a standard Windows usermode component (I’m not sure how though). I solved the issue by using ZwDuplicateObject with the HandleValue member and that way it was possible for me to get the file handle.

I still wonder, why didn’t ZwClose work in this case?

consider why the system process would open and keep this handle open for the entire time that windows runs - it is clearly an attempt to prevent anyone from doing what you are attempting.

I suggest that you look at PendingFileRenameOperations

1 Like

Or, you know, write a file system filter?

Peter

1 Like