Winapi: Get the process which has specific handle of a file

For this task, starting with Windows Vista special exist FileProcessIdsUsingFileInformation FILE_INFORMATION_CLASS.

So we need open file with FILE_READ_ATTRIBUTES (this is possible even if somebody open file with 0 share mode. of if we have no access to file (by it DACL) but have read access to parent directory). and call NtQueryInformationFile with FileProcessIdsUsingFileInformation. on return we got FILE_PROCESS_IDS_USING_FILE_INFORMATION structure (defined in wdm.h) where list of ProcessId which hold this file(open file handle or mapped section. say if this file is exe/dll – we got process ids where it loaded). good also with this print process name for every id:

volatile UCHAR guz = 0;

NTSTATUS PrintProcessesUsingFile(HANDLE hFile)
{
    NTSTATUS status;
    IO_STATUS_BLOCK iosb;

    ULONG cb = 0, rcb = FIELD_OFFSET(FILE_PROCESS_IDS_USING_FILE_INFORMATION, ProcessIdList[64]);

    union {
        PVOID buf;
        PFILE_PROCESS_IDS_USING_FILE_INFORMATION ppiufi;
    };

    PVOID stack = alloca(guz);

    do 
    {
        if (cb < rcb)
        {
            cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
        }

        if (0 <= (status = NtQueryInformationFile(hFile, &iosb, ppiufi, cb, FileProcessIdsUsingFileInformation)))
        {
            if (ppiufi->NumberOfProcessIdsInList)
            {
                PrintProcessesUsingFile(ppiufi);
            }
        }

        rcb = (ULONG)iosb.Information;

    } while (status == STATUS_INFO_LENGTH_MISMATCH);

    return status;
}

NTSTATUS PrintProcessesUsingFile(POBJECT_ATTRIBUTES poa)
{
    IO_STATUS_BLOCK iosb;
    HANDLE hFile;
    NTSTATUS status;
    if (0 <= (status = NtOpenFile(&hFile, FILE_READ_ATTRIBUTES, poa, &iosb, FILE_SHARE_VALID_FLAGS, 0)))
    {
        status = PrintProcessesUsingFile(hFile);
        NtClose(hFile);
    }

    return status;
}

NTSTATUS PrintProcessesUsingFile(PCWSTR FileName)
{
    UNICODE_STRING ObjectName;
    NTSTATUS status = RtlDosPathNameToNtPathName_U_WithStatus(FileName, &ObjectName, 0, 0);
    if (0 <= status)
    {
        OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName };
        status = PrintProcessesUsingFile(&oa);
        RtlFreeUnicodeString(&ObjectName);
    }

    return status;
}

NTSTATUS PrintProcessesUsingFile(PFILE_PROCESS_IDS_USING_FILE_INFORMATION ppiufi)
{
    NTSTATUS status;

    ULONG cb = 0x8000;

    do 
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        if (PVOID buf = new BYTE[cb])
        {
            if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
            {
                union {
                    PVOID pv;
                    PBYTE pb;
                    PSYSTEM_PROCESS_INFORMATION pspi;
                };

                pv = buf;
                ULONG NextEntryOffset = 0;

                do 
                {
                    pb += NextEntryOffset;

                    ULONG NumberOfProcessIdsInList = ppiufi->NumberOfProcessIdsInList;

                    PULONG_PTR ProcessIdList = ppiufi->ProcessIdList;
                    do 
                    {
                        if (*ProcessIdList++ == (ULONG_PTR)pspi->UniqueProcessId)
                        {
                            DbgPrint("%p %wZ\n", pspi->UniqueProcessId, &pspi->ImageName);
                            break;
                        }
                    } while (--NumberOfProcessIdsInList);

                } while (NextEntryOffset = pspi->NextEntryOffset);
            }

            delete [] buf;
        }

    } while (status == STATUS_INFO_LENGTH_MISMATCH);

    return status;
}

Leave a Comment