A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about kernel-mode development.
 #3357  by Mehdi
 Sat Nov 06, 2010 8:03 am
Hi
Is there any know/documented way for killing a handle from Kernel?
(I mean, send the handle from user mode app to driver via IOCTL, then kill it)
I've written a user mode app, but it cannot kill some handles.
I've also disassembled the driver of Unlocker, but I don't wanna copy/paste/steal others' source code (I want to learn how to do it)
(I don't need full source code; just show me the way)
Thanks
 #3360  by Mehdi
 Sat Nov 06, 2010 8:23 am
There are so many applications that do this (for example: Process Explorer)
I just want to close the File handles (not named pipes ....)
Does ZwClose work for all scenarios? (I want to be able to close file handles from kernel mode, so I can delete that file)
 #3361  by EP_X0FF
 Sat Nov 06, 2010 8:33 am
ZwClose works only with current process handle table.
ProcessExplorer uses ZwDuplicateObject - with flag DUPLICATE_CLOSE_SOURCE
Code: Select all
 if (Options & DUPLICATE_CLOSE_SOURCE) {

            KeStackAttachProcess( &SourceProcess->Pcb, &ApcState );

            NtClose( SourceHandle );

            KeUnstackDetachProcess (&ApcState);
        }
 #3362  by Cr4sh
 Sat Nov 06, 2010 3:25 pm
Here is example of source code, that closes file object handle by file name:
Code: Select all
#include "stdafx.h"

UCHAR FileObjectTypeIndex = 0;
//--------------------------------------------------------------------------------------
UCHAR GetFileObjectTypeIndex(PUNICODE_STRING usSomeFileName)
{
    UCHAR Ret = 0;
    OBJECT_ATTRIBUTES ObjAttr;
    HANDLE hFile;
    IO_STATUS_BLOCK StatusBlock;

    InitializeObjectAttributes(&ObjAttr, usSomeFileName, OBJ_CASE_INSENSITIVE , NULL, NULL);

    // we need a handle of some file
    NTSTATUS ns = ZwOpenFile(
        &hFile, 
        FILE_READ_DATA | SYNCHRONIZE, 
        &ObjAttr, &StatusBlock, 
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 
        FILE_SYNCHRONOUS_IO_NONALERT
    );
    if (NT_SUCCESS(ns))
    {
        // get list of all handles in system
        PSYSTEM_HANDLE_INFORMATION Info = (PSYSTEM_HANDLE_INFORMATION)GetSysInf(SystemHandleInformation);
        if (Info)
        {
            HANDLE CurrentProcessId = PsGetCurrentProcessId();

            // find our handle in list
            for (ULONG i = 0; i < Info->NumberOfHandles; i++)
            {
                if (Info->Handles[i].UniqueProcessId == (USHORT)CurrentProcessId &&
                    Info->Handles[i].HandleValue == (USHORT)hFile)
                {
                    // return value of object type index (for file object)
                    Ret = Info->Handles[i].ObjectTypeIndex;
                    break;
                }
            }

            M_FREE(Info);
        }

        ZwClose(hFile);
    }    
    else
    {
        DbgMsg(__FILE__, __LINE__, "ZwOpenFile() fails; status: 0x%.8x\n", ns);
    }

    return Ret;
}
//--------------------------------------------------------------------------------------
BOOLEAN CloseFileHandlesByName(PUNICODE_STRING usFileName)
{
    if (FileObjectTypeIndex == 0)
    {
        UNICODE_STRING usSomeFileName;
        RtlInitUnicodeString(&usSomeFileName, L"\\SystemRoot\\system32\\ntdll.dll");

        FileObjectTypeIndex = GetFileObjectTypeIndex(&usSomeFileName);
        if (FileObjectTypeIndex == 0)
        {
            DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Invalid FileObjectTypeIndex\n");
            return FALSE;
        }        
    }

    DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Closing all handles for '%wZ'\n", usFileName);

    // get list of all handles in system
    PSYSTEM_HANDLE_INFORMATION Info = (PSYSTEM_HANDLE_INFORMATION)GetSysInf(SystemHandleInformation);
    if (Info)
    {
        for (ULONG i = 0; i < Info->NumberOfHandles; i++)
        {
            if (Info->Handles[i].ObjectTypeIndex == FileObjectTypeIndex)
            {
                PFILE_OBJECT FileObject = (PFILE_OBJECT)Info->Handles[i].Object;
                // volume parameters block is not present in named pipes
                // dirty trick, but working
                if (FileObject->Vpb)
                {
                    // get name of the object
                    POBJECT_NAME_INFORMATION NameInfo = GetObjectName(FileObject);
                    if (NameInfo)
                    {                        
                        if (RtlEqualUnicodeString(&NameInfo->Name, usFileName, TRUE))
                        {
                            DbgMsg(__FILE__, __LINE__, "  ProcessId: %d, Handle: "IFMT"\n", 
                                Info->Handles[i].UniqueProcessId, Info->Handles[i].HandleValue);

                            if (Info->Handles[i].UniqueProcessId == 4)
                            {
                                // don't close handles in system process
                                goto skip;
                            }

                            PEPROCESS Process;
                            // get process pointer
                            NTSTATUS ns = PsLookupProcessByProcessId((HANDLE)Info->Handles[i].UniqueProcessId, &Process);
                            if (NT_SUCCESS(ns))
                            {
                                KAPC_STATE ApcState;
                                // attach to a target process
                                KeStackAttachProcess(Process, &ApcState);

                                __try
                                {
                                    // close handle of our file
                                    ZwClose((HANDLE)Info->Handles[i].HandleValue);
                                }
                                __except (EXCEPTION_EXECUTE_HANDLER)
                                {
                                    DbgMsg(__FILE__, __LINE__, __FUNCTION__"() EXCEPTION\n");
                                }
                                
                                KeUnstackDetachProcess(&ApcState);

                                ObDereferenceObject(Process);
                            }
                            else
                            {
                                DbgMsg(__FILE__, __LINE__, "PsLookupProcessByProcessId() fails; status: 0x%.8x\n", ns);
                            }
                        }
skip:
                        M_FREE(NameInfo);
                    }
                }                
            }
        }

        M_FREE(Info);

        return TRUE;
    }

    return FALSE;
}
//--------------------------------------------------------------------------------------
// EoF