列出 Windows 上打开的文件?

问题描述 投票:0回答:1

对于我正在开发的文件浏览器,我需要在 Windows 系统上生成打开文件的列表。

我已经开始使用成功生成进程 ID 列表的代码。有没有办法把它变成列出每个进程打开的所有文件的方法?

#include <cstdlib>
#include <iostream>
#include <cstring>

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <psapi.h>

using namespace std;


void PrintProcessNameAndID(DWORD processID) {
    TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");

    // Get a handle to the process.

    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
            PROCESS_VM_READ,
            FALSE, processID);

    // Get the process name.

    if (NULL != hProcess) {
        HMODULE hMod;
        DWORD cbNeeded;

        if (EnumProcessModules(hProcess, &hMod, sizeof (hMod),
                &cbNeeded)) {
            GetModuleBaseName(hProcess, hMod, szProcessName,
                    sizeof (szProcessName) / sizeof (TCHAR));
        }
    }

    // Print the process name and identifier.

    _tprintf(TEXT("%s  (PID: %u)\n"), szProcessName, processID);

    // Release the handle to the process.

    CloseHandle(hProcess);
}

int startup(void) {
    // Get the list of process identifiers.

    DWORD aProcesses[1024], cbNeeded, cProcesses;
    unsigned int i;

    if (!EnumProcesses(aProcesses, sizeof (aProcesses), &cbNeeded)) {
        return 1;
    }


    // Calculate how many process identifiers were returned.

    cProcesses = cbNeeded / sizeof (DWORD);

    // Print the name and process identifier for each process.

    for (i = 0; i < cProcesses; i++) {
        if (aProcesses[i] != 0) {
            PrintProcessNameAndID(aProcesses[i]);
        }
    }

    return 0;
}

int main(int argc, char** argv) {

    startup();

    return 0;
}

c++ file winapi file-in-use
1个回答
2
投票

执行此操作的典型方法是使用 NtQueryInformationProcess 的“未记录”功能来枚举句柄。请注意,这将返回相对于设备的文件路径 - 您需要使用 GetVolumePathName 然后将其与驱动器号相关联。

#include <windows.h>
#include <memory>
#include <string>

#define NT_SUCCESS(status) (status >= 0)

#define STATUS_INFO_LENGTH_MISMATCH      ((NTSTATUS)0xC0000004L)

enum PROCESSINFOCLASS {
    ProcessHandleInformation = 51
};

struct PROCESS_HANDLE_TABLE_ENTRY_INFO {
    HANDLE HandleValue;
    ULONG_PTR HandleCount;
    ULONG_PTR PointerCount;
    ULONG GrantedAccess;
    ULONG ObjectTypeIndex;
    ULONG HandleAttributes;
    ULONG Reserved;
};

// private
struct PROCESS_HANDLE_SNAPSHOT_INFORMATION {
    ULONG_PTR NumberOfHandles;
    ULONG_PTR Reserved;
    PROCESS_HANDLE_TABLE_ENTRY_INFO Handles[1];
};

typedef NTSTATUS(NTAPI* t_NtQueryInformationProcess)(
    HANDLE ProcessHandle,
    PROCESSINFOCLASS ProcessInformationClass,
    PVOID ProcessInformation,
    ULONG ProcessInformationLength,
    PULONG ReturnLength);

t_NtQueryInformationProcess NtQueryInformationProcess()
{
    static t_NtQueryInformationProcess f_NtQueryInformationProcess = NULL;
    if (!f_NtQueryInformationProcess)
    {
        HMODULE h_NtDll = GetModuleHandle("Ntdll.dll"); // Ntdll is loaded into EVERY process!
        f_NtQueryInformationProcess = (t_NtQueryInformationProcess)GetProcAddress(h_NtDll, "NtQueryInformationProcess");
    }
    return f_NtQueryInformationProcess;
}

struct ThreadData {
    HANDLE hDup;
    std::wstring name;
};

enum OBJECT_INFORMATION_CLASS
{
    ObjectBasicInformation,
    ObjectNameInformation,
    ObjectTypeInformation,
    ObjectAllInformation,
    ObjectDataInformation
};

struct UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
};

struct OBJECT_NAME_INFORMATION
{
    UNICODE_STRING Name; // defined in winternl.h
    WCHAR NameBuffer;
};

struct OBJECT_TYPE_INFORMATION {
    UNICODE_STRING TypeName;
    ULONG TotalNumberOfObjects;
    ULONG TotalNumberOfHandles;
};

typedef NTSTATUS(NTAPI* t_NtQueryObject)(HANDLE Handle, OBJECT_INFORMATION_CLASS Info, PVOID Buffer, ULONG BufferSize, PULONG ReturnLength);

t_NtQueryObject NtQueryObject();
std::wstring GetFileHandleNameInformation_GetMappedFileName(HANDLE fileHandle);

/// <summary>
/// Loads/retrieves the NtQueryObject function from NtDll 
/// </summary>
/// <returns>The functor for the NtQueryObject function</returns>
t_NtQueryObject NtQueryObject()
{
    static t_NtQueryObject f_NtQueryObject = NULL;
    if (!f_NtQueryObject)
    {
        HMODULE h_NtDll = GetModuleHandle("Ntdll.dll"); // Ntdll is loaded into EVERY process!
        f_NtQueryObject = (t_NtQueryObject)GetProcAddress(h_NtDll, "NtQueryObject");
    }
    return f_NtQueryObject;
}

/// <summary>
/// Calls NtQueryObject to get the filename for the file handle
/// Remark: NtQueryObject uses Device name for the drives
/// </summary>
/// <param name="fileHandle">The file handle</param>
/// <returns>The filename.</returns>
std::wstring GetFileHandleNameInformation_NtQueryObject(HANDLE fileHandle)
{
    ULONG szNeeded;
    auto status = ::NtQueryObject()(fileHandle, ObjectNameInformation, NULL, 0, &szNeeded);

    //Get handle name information
    std::unique_ptr<BYTE[]> nameBuffer = std::make_unique<BYTE[]>(szNeeded);
    OBJECT_NAME_INFORMATION* nameInfo = (OBJECT_NAME_INFORMATION*)nameBuffer.get();
    status = NtQueryObject()(fileHandle, ObjectNameInformation, nameInfo, szNeeded, &szNeeded);

    return std::wstring{ nameInfo->Name.Buffer, nameInfo->Name.Length / sizeof(WCHAR) };
}

std::vector<std::wstring> ProcessFileHandles(HANDLE hProcess)
{
    //Get the concatenated list of handles for the process. This gets the buffer length first, then gets the actual buffer of information
    ULONG size = 1 << 10;
    std::unique_ptr<BYTE[]> buffer;
    for (;;)
    {
        buffer = std::make_unique<BYTE[]>(size);
        auto status = ::NtQueryInformationProcess()(hProcess, ProcessHandleInformation, buffer.get(), size, &size);

        if (NT_SUCCESS(status))
        {
            break;
        }

        if (status == STATUS_INFO_LENGTH_MISMATCH)
        {
            size += 1 << 10;
            continue;
        }

        printf("Error enumerating handles\n");
        return {};
    }

    bool result = false;

    //Look through the handles to find our target file path
    std::vector<std::wstring> filePaths;
    auto info = reinterpret_cast<PROCESS_HANDLE_SNAPSHOT_INFORMATION*>(buffer.get());

    for (ULONG i = 0; i < info->NumberOfHandles; i++)
    {
        HANDLE h = info->Handles[i].HandleValue;
        HANDLE hTarget;
        if (!::DuplicateHandle(hProcess, h, ::GetCurrentProcess(), &hTarget, 0, FALSE, DUPLICATE_SAME_ACCESS))
        {
            continue;   // move to next handle
        }

        //Get size of buffer
        ULONG szNeeded;
        auto status = NtQueryObject()(hTarget, ObjectTypeInformation, NULL, 0, &szNeeded);

        //Get handle type information
        std::unique_ptr<BYTE[]> typeBuffer = std::make_unique<BYTE[]>(szNeeded);
        OBJECT_TYPE_INFORMATION* typeInfo = (OBJECT_TYPE_INFORMATION*)typeBuffer.get();
        status = NtQueryObject()(hTarget, ObjectTypeInformation, typeInfo, szNeeded, &szNeeded);

        if (!NT_SUCCESS(status) || typeInfo == nullptr)
        {
            continue;
        }

        if (::_wcsnicmp(typeInfo->TypeName.Buffer, L"File", 4) == 0)
        {
            std::wstring handlePath = GetFileHandleNameInformation_NtQueryObject(hTarget);
            filePaths.push_back(handlePath);
        }

        CloseHandle(hTarget);
    }

    return filePaths;
}
© www.soinside.com 2019 - 2024. All rights reserved.