shihy_ 2024-01-25 23:31 采纳率: 60%
浏览 79

C++WindowsAPI获取其他进程打开的文件句柄全路径

就是说要做一个获取目标进程打开的所有文件的功能,我的想法是先遍历目标进程的所有关联文件句柄,然后根据句柄获取被打开文件的源路径,然后就可以根据路径自行打开了。

现在的问题是我不知道是权限问题还是什么原因,目标文件句柄无法被获取全路径(注意这个文件句柄不属于当前进程,也就是说这个文件是被其他程序打开的)

遍历目标进程的所有关联文件句柄的功能已经实现了,代码如下:

#define _WIN32_WINNT 0x0600
#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
#include <Psapi.h>
//#include <ntifs.h>

#pragma comment(lib, "Psapi.lib")

#ifndef STATUS_INFO_LENGTH_MISMATCH
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
#endif
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif

typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
    ULONG SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
);

typedef struct _SYSTEM_HANDLE {
    ULONG ProcessId;
    BYTE ObjectTypeNumber;
    BYTE Flags;
    USHORT Handle;
    PVOID Object;
    ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;

typedef struct __SYSTEM_HANDLE_INFORMATION {
    ULONG HandleCount;
    SYSTEM_HANDLE Handles[1];
} _R_SYSTEM_HANDLE_INFORMATION, *_R_PSYSTEM_HANDLE_INFORMATION;

#define SystemHandleInformation 16
#define ObjectBasicInformation 0
#define ObjectNameInformation 1
#define ObjectTypeInformation 2

std::vector<HANDLE> GetProcessHandles(DWORD processId) {
    std::vector<HANDLE> handles;

    _NtQuerySystemInformation NtQuerySystemInformation =
        (_NtQuerySystemInformation)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
    if (!NtQuerySystemInformation) {
        std::cerr << "Could not find NtQuerySystemInformation" << std::endl;
        return handles;
    }

    _R_PSYSTEM_HANDLE_INFORMATION handleInfo;
    ULONG handleInfoSize = 0x10000;
    ULONG neededSize;
    NTSTATUS status;

    handleInfo = (_R_PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize);

    while ((status = NtQuerySystemInformation(SystemHandleInformation, handleInfo, handleInfoSize,
                     &neededSize)) == STATUS_INFO_LENGTH_MISMATCH) {
        handleInfo = (_R_PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2);
    }

    if (!NT_SUCCESS(status)) {
        std::cerr << "NtQuerySystemInformation failed" << std::endl;
        return handles;
    }

    for (ULONG i = 0; i < handleInfo->HandleCount; i++) {
        SYSTEM_HANDLE handle = handleInfo->Handles[i];
        if (handle.ProcessId == processId) {
            handles.push_back((HANDLE)handle.Handle);
        }
    }

    free(handleInfo);

    return handles;
}

而这段代码也的确可以获取到目标进程的句柄,这里的目标进程,也就是被获取句柄路径的测试程序代码如下:

#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
#include <Psapi.h>

#pragma comment(lib, "Psapi.lib")

#ifndef STATUS_INFO_LENGTH_MISMATCH
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
#endif
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif

typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
    ULONG SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
);

typedef struct _SYSTEM_HANDLE {
    ULONG ProcessId;
    BYTE ObjectTypeNumber;
    BYTE Flags;
    USHORT Handle;
    PVOID Object;
    ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;

typedef struct _SYSTEM_HANDLE_INFORMATION {
    ULONG HandleCount;
    SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

#define SystemHandleInformation 16
#define ObjectBasicInformation 0
#define ObjectNameInformation 1
#define ObjectTypeInformation 2

std::vector<HANDLE> GetProcessHandles(DWORD processId) {
    std::vector<HANDLE> handles;

    _NtQuerySystemInformation NtQuerySystemInformation =
        (_NtQuerySystemInformation)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
    if (!NtQuerySystemInformation) {
        std::cerr << "Could not find NtQuerySystemInformation" << std::endl;
        return handles;
    }

    PSYSTEM_HANDLE_INFORMATION handleInfo;
    ULONG handleInfoSize = 0x10000;
    ULONG neededSize;
    NTSTATUS status;

    handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize);

    while ((status = NtQuerySystemInformation(SystemHandleInformation, handleInfo, handleInfoSize,
                     &neededSize)) == STATUS_INFO_LENGTH_MISMATCH) {
        handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2);
    }

    if (!NT_SUCCESS(status)) {
        std::cerr << "NtQuerySystemInformation failed" << std::endl;
        return handles;
    }

    for (ULONG i = 0; i < handleInfo->HandleCount; i++) {
        SYSTEM_HANDLE handle = handleInfo->Handles[i];
        if (handle.ProcessId == processId) {
            handles.push_back((HANDLE)handle.Handle);
        }
    }

    free(handleInfo);

    return handles;
}

std::string GetFileNameFromHandle(HANDLE hFile) {
    char szTemp[UNICODE_STRING_MAX_CHARS];
    HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 1, NULL);
    if (hFileMap) {
        void *pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
        if (pMem) {
            if (GetMappedFileNameA(GetCurrentProcess(), pMem, szTemp, sizeof(szTemp))) {
                UnmapViewOfFile(pMem);
                CloseHandle(hFileMap);
                return szTemp;
            }
            UnmapViewOfFile(pMem);
        }
        CloseHandle(hFileMap);
    }
    return "";
}

int main() {
    HANDLE hFile = CreateFileA("N:\\OpenedFilesView\\readme.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
                               FILE_ATTRIBUTE_NORMAL,
                               NULL);
    if (hFile != INVALID_HANDLE_VALUE) {
        std::string fileName = GetFileNameFromHandle(hFile);
        std::cout << std::hex << hFile << std::endl;
        std::cout << "File name: " << fileName << std::endl;
    }
    std::cin.get();
    CloseHandle(hFile);
    return 0;
}

而下面是我现在用的获取文件句柄全路径的代码,获取当前进程的句柄路径是可以的,但是其他程序都不行:

#include <Windows.h>
#include <tchar.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

// Function to get the file path from a handle (wide character version)
EXTERN_C BOOL GetFilePathFromHandleW(HANDLE hFile, LPWSTR lpszPath, UINT cchMax);

// Function to get the file path from a handle (multibyte character version)
EXTERN_C BOOL GetFilePathFromHandleA(HANDLE hFile, LPSTR  lpszPath, UINT cchMax);

// Macro to calculate the number of elements in an array
#ifndef _countof
#define  _countof(array) (sizeof(array)/sizeof((array)[0]))
#endif

// Function to get the volume name by handle
EXTERN_C BOOL GetVolumeNameByHandle(HANDLE hFile, LPWSTR szVolumeName, UINT cchMax) {
    BOOL bResult = FALSE;
    WCHAR szBuf[500] = { 0 };
    WCHAR *pIter = szBuf;
    int i = 0;
    BY_HANDLE_FILE_INFORMATION stFileInfo = { 0 };

    // Get file information by handle
    if (FALSE == GetFileInformationByHandle(hFile, &stFileInfo)) {
        OutputDebugString(_T("GetFileInformationByHandle failed."));
        return bResult;
    }

    // Get logical drive strings
    if (0 == GetLogicalDriveStringsW(_countof(szBuf), szBuf)) {
        OutputDebugString(_T("GetLogicalDriveStringsW failed."));
        return bResult;
    }

    // Iterate through each drive
    for (; pIter; pIter += 4) {
        DWORD dwVolumeSerialNumber = 0;

        // Get volume information
        if (GetVolumeInformationW(pIter, NULL, 0, &dwVolumeSerialNumber, NULL, NULL, NULL, 0)) {
            // Compare volume serial number with file's volume serial number
            if (dwVolumeSerialNumber == stFileInfo.dwVolumeSerialNumber) {
                // Copy volume name to output buffer
                lstrcpynW(szVolumeName, pIter, cchMax);
                bResult = TRUE;
                break;
            }
        }
    }

    return bResult;
}

// Structure for IO status block
typedef struct _IO_STATUS_BLOCK {
    LONG Status;
    LONG Information;
} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK;

// Structure for file name information
typedef struct _FILE_NAME_INFORMATION {
    ULONG FileNameLength;
    WCHAR FileName[MAX_PATH];
} FILE_NAME_INFORMATION;

// Import ZwQueryInformationFile function from ntdll.dll
__declspec(dllimport) LONG __stdcall ZwQueryInformationFile(
    IN HANDLE FileHandle,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    OUT PVOID FileInformation,
    IN ULONG FileInformationLength,
    IN ULONG FileInformationClass
);

// Typedef for ZwQueryInformationFile function
typedef LONG(__stdcall *PFN_ZwQueryInformationFile)(
    IN HANDLE FileHandle,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    OUT PVOID FileInformation,
    IN ULONG FileInformationLength,
    IN ULONG FileInformationClass
);

// Function to get the file path from a handle (wide character version)
EXTERN_C BOOL GetFilePathFromHandleW(HANDLE hFile, LPWSTR lpszPath, UINT cchMax) {
    BOOL bResult = FALSE;
    WCHAR szValue[MAX_PATH] = { 0 };

    IO_STATUS_BLOCK isb = { 0 };
    FILE_NAME_INFORMATION fni = { 0 };
    HANDLE hNtDll = NULL;
    PFN_ZwQueryInformationFile pfn_ZwQueryInformationFile = NULL;

    // Check for invalid parameters
    if (INVALID_HANDLE_VALUE == hFile || NULL == lpszPath || 0 == cchMax) {
        OutputDebugString(_T("Invalid parameters."));
        return bResult;
    }

    // Get handle to ntdll.dll
    hNtDll = GetModuleHandle(_T("ntdll.dll"));
    if (NULL == hNtDll) {
        OutputDebugString(_T("Failed to get handle to ntdll.dll."));
        return bResult;
    }

    // Get address of ZwQueryInformationFile function
    pfn_ZwQueryInformationFile = (PFN_ZwQueryInformationFile)GetProcAddress(reinterpret_cast<HMODULE>(hNtDll),
                                 "ZwQueryInformationFile");
    if (NULL == pfn_ZwQueryInformationFile) {
        OutputDebugString(_T("Failed to get address of ZwQueryInformationFile."));
        return bResult;
    }

    // Call ZwQueryInformationFile function with class 9 (FileNameInformation)
    if (0 != pfn_ZwQueryInformationFile(hFile, &isb, &fni, sizeof(fni), 9)) {
        OutputDebugString(_T("ZwQueryInformationFile failed."));
        return bResult;
    }

    // Get volume name by handle
    if (FALSE == GetVolumeNameByHandle(hFile, szValue, _countof(szValue))) {
        OutputDebugString(_T("GetVolumeNameByHandle failed."));
        return bResult;
    }

    // Append file name to volume name
    PathAppendW(szValue, fni.FileName);

    // Copy full path to output buffer
    lstrcpynW(lpszPath, szValue, cchMax);

    bResult = TRUE;
    return bResult;
}

// Function to get the file path from a handle (multibyte character version)
EXTERN_C BOOL GetFilePathFromHandleA(HANDLE hFile, LPSTR lpszPath, UINT cchMax) {
    BOOL bResult = FALSE;
    WCHAR szTmep[MAX_PATH] = { 0 };

    // Check for invalid parameters
    if (INVALID_HANDLE_VALUE == hFile || NULL == lpszPath || 0 == cchMax) {
        OutputDebugString(_T("Invalid parameters."));
        return bResult;
    }

    // Call wide character version of GetFilePathFromHandle
    if (FALSE == GetFilePathFromHandleW(hFile, szTmep, _countof(szTmep))) {
        OutputDebugString(_T("GetFilePathFromHandleW failed."));
        return bResult;
    }

    // Convert wide character string to multibyte character string
    if (0 == WideCharToMultiByte(CP_ACP, 0, szTmep, lstrlenW(szTmep), lpszPath, cchMax, NULL, NULL)) {
        OutputDebugString(_T("WideCharToMultiByte failed."));
        return bResult;
    }

    bResult = TRUE;
    return bResult;
}


#include <iostream>
using namespace std;

int main() {
    CHAR RetCHAR[1145];
    HANDLE hf/* = CreateFileA("N:\\OpenedFilesView\\readme.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL)*/;
    cin >> hf;
    if (!GetFilePathFromHandleA(hf, RetCHAR, 1145)) {
        cout << "fuck!";
    }
    cout << RetCHAR;
    cin.get();
    cin.get();
    cin.get();
    return 0;
}

不胜感激!

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2024-01-26 08:04
    关注

    【相关推荐】




    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    评论

报告相同问题?

问题事件

  • 创建了问题 1月25日