Search code examples
c++windowskernelntdll

GetFinalPathByHandle returns the same path for all handles returned by NtQuerySystemInformation


I want to retrieve all file paths that are accessed by processes in my OS. List of processes is retrieved and those has correct handle values. So now I want to use GetFinalPathNameByHandle function to get path to those files, but Path variable is the same for all records. I need a hand here guys.

Source code is here: http://pastebin.com/nU26Vcsd or here if pastebin is not accessible http://hastebin.com/wahudogawa.avrasm

Line 66 is where I need help. Path is the same for each file handler of the tested process and is equal to the path where this program is executed( and not the process start folder).

I run it as: testprogram.exe | grep 5231 where 5231 is a PID of the process I need.

Results looks like:

PID: 5231        FileHandlePid: 44       The final path is: \Device\HarddiskVolume4\KillFileHandle\C++\Debug

While those should be like:

PID: 5231        FileHandlePid: 44       The final path is: \Device\HarddiskVolume2\Users\username\AppData\Roaming\testapp

Or correct me please if I am wrong in expected result.


Latest addition:

Thanks to @Raymond Chen comments I am trying to move forward and use DuplicateHandle() funtion. So far I've updated code (hardcoded pid for now, sorry) , added HandleValueTemp, trying to pass it to DuplicateHandle. The output is changed to nonprintable characters.

for (i = 0; i < hCount; ++i)
if ((hFirstEntry[i].ObjectType == 28))
{
    HANDLE TargetHandleValueTemp = (HANDLE)hFirstEntry[i].HandleValue;
    HANDLE SourceProcHandleTemp = OpenProcess(PROCESS_DUP_HANDLE, FALSE, hFirstEntry[i].OwnerPid);

    if (!DuplicateHandle(SourceProcHandleTemp, (HANDLE)hFirstEntry[i].HandleValue, GetCurrentProcess(), &TargetHandleValueTemp, 0, FALSE, DUPLICATE_SAME_ACCESS))
    {
        cout << "Error in DuplicateHandle"
    }

    CloseHandle(SourceProcHandleTemp);
    TCHAR Path[MAX_PATH];
    DWORD dwret = GetFinalPathNameByHandle(TargetHandleValueTemp, Path, MAX_PATH, 0);
    _tprintf(TEXT("PID: %d\tFileHandle: %d\tThe final path is: %s\n"), hFirstEntry[i].OwnerPid, TargetHandleValueTemp, Path);
    CloseHandle(TargetHandleValueTemp);
}

Digging further and looking in comments from time to time. Maybe this code can be useful to someone else here.


Solution

  • Thanks to @RaymondChen and @HarryJohnston comments in question I was able to get to working result. I leave it here for case when someone else needs that. The code is a bit crappy but further formatting is up to you. Remember to update OwnerPid in loop to your own when testing.

    #include <Windows.h>
    #include <stdio.h>
    #include <string.h>
    #include <tchar.h>
    #include <iostream>
    
    #define START_ALLOC                 0x1000
    #define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
    #define SystemHandleInformation     0x10
    
    typedef long(__stdcall *NtQSI)(
    ULONG  SystemInformationClass,
    PVOID  SystemInformation,
    ULONG  SystemInformationLength,
    PULONG ReturnLength
    );
    
    typedef struct _SYSTEM_HANDLE_ENTRY {
    ULONG  OwnerPid;
    BYTE   ObjectType;
    BYTE   HandleFlags;
    USHORT HandleValue;
    PVOID  ObjectPointer;
    ACCESS_MASK  AccessMask;
    } SYSTEM_HANDLE_ENTRY, *PSYSTEM_HANDLE_ENTRY;
    
    int main()
    {
    HMODULE hNtDll = NULL;
    NtQSI   pNtQSI = NULL;
    PVOID   pMem = NULL;
    ULONG   allocSize = START_ALLOC;
    ULONG   retVal = 0;
    // --------------------------------
    ULONG   hCount = 0;
    PSYSTEM_HANDLE_ENTRY hFirstEntry = NULL;
    // --------------------------------
    ULONG   i;
    
    hNtDll = LoadLibraryA("NTDLL.dll");
    
    if (!hNtDll)
        return 1;
    
    pNtQSI = (NtQSI)GetProcAddress(hNtDll, "NtQuerySystemInformation");
    
    if (!pNtQSI) {
        FreeLibrary(hNtDll);
        return 2;
    }
    
    pMem = malloc(allocSize);
    
    while (pNtQSI(SystemHandleInformation, pMem, allocSize, &retVal)
        == STATUS_INFO_LENGTH_MISMATCH) {
        pMem = realloc(pMem, allocSize *= 2);
    }
    
    hCount = *(ULONG*)pMem;
    hFirstEntry = (PSYSTEM_HANDLE_ENTRY)((PBYTE)pMem + 4);
    
    for (i = 0; i < hCount; ++i)
    if ((hFirstEntry[i].ObjectType == 30) && (hFirstEntry[i].OwnerPid == 5628))
    {
        HANDLE TargetHandleValueTemp = (HANDLE)hFirstEntry[i].HandleValue;
        HANDLE SourceProcHandleTemp = OpenProcess(PROCESS_DUP_HANDLE, FALSE, hFirstEntry[i].OwnerPid);
    
        if (!DuplicateHandle(SourceProcHandleTemp, (HANDLE)hFirstEntry[i].HandleValue, GetCurrentProcess(), &TargetHandleValueTemp, 0, FALSE, DUPLICATE_SAME_ACCESS))
        {
            TargetHandleValueTemp = (HANDLE)hFirstEntry[i].HandleValue;
        }
    
        CloseHandle(SourceProcHandleTemp);
        TCHAR Path[MAX_PATH];
        DWORD dwret = GetFinalPathNameByHandle(TargetHandleValueTemp, Path, MAX_PATH, 0);
        _tprintf(TEXT("PID: %d\tFileHandle: %d\tThe final path is: %s\n"), hFirstEntry[i].OwnerPid, TargetHandleValueTemp, Path);
        CloseHandle(TargetHandleValueTemp);
    }
    
    free(pMem);
    FreeLibrary(hNtDll);
    }