You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows系统下如何获取各进程打开的文件列表?

获取Windows进程已打开文件列表的代码改造

要在你现有代码基础上实现列出每个进程的已打开文件,需要借助Windows Native API扩展功能,同时处理进程权限问题。以下是改造后的完整方案:

核心改动说明

  • 添加权限提升逻辑,获取SE_DEBUG_NAME权限,否则无法访问系统级进程的句柄信息
  • 使用NtQuerySystemInformation(Windows原生API)获取全系统句柄数据
  • 筛选目标进程的文件句柄,通过GetFinalPathNameByHandle解析文件路径

改造后的完整代码

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

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

// 链接所需系统库
#pragma comment(lib, "ntdll.lib")
#pragma comment(lib, "psapi.lib")

using namespace std;

// 定义原生API的函数指针类型
typedef NTSTATUS(NTAPI* pNtQuerySystemInformation)(
    SYSTEM_INFORMATION_CLASS SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
);

// 提升进程权限
BOOL EnablePrivilege(LPCWSTR privilegeName) {
    HANDLE hToken;
    TOKEN_PRIVILEGES tp;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
        return FALSE;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!LookupPrivilegeValueW(NULL, privilegeName, &tp.Privileges[0].Luid)) {
        CloseHandle(hToken);
        return FALSE;
    }

    BOOL result = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
    CloseHandle(hToken);
    return result;
}

// 打印进程名称及已打开文件列表
void PrintProcessOpenFiles(DWORD processID) {
    TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
    // 打开进程,请求必要权限
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_DUP_HANDLE, FALSE, processID);

    if (NULL != hProcess) {
        // 获取进程名称
        HMODULE hMod;
        DWORD cbNeeded;
        if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
            GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName) / sizeof(TCHAR));
        }

        _tprintf(TEXT("\n%s  (PID: %u)\n已打开文件:\n"), szProcessName, processID);

        // 获取NtQuerySystemInformation函数地址
        pNtQuerySystemInformation NtQuerySystemInformation = 
            (pNtQuerySystemInformation)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQuerySystemInformation");

        if (!NtQuerySystemInformation) {
            _tprintf(TEXT("无法获取系统句柄信息接口\n"));
            CloseHandle(hProcess);
            return;
        }

        // 动态分配缓冲区存储系统句柄数据
        ULONG bufferSize = 0x10000;
        PSYSTEM_HANDLE_INFORMATION handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(bufferSize);
        NTSTATUS status;

        // 自动扩容缓冲区直到容纳所有数据
        while ((status = NtQuerySystemInformation(SystemHandleInformation, handleInfo, bufferSize, NULL)) == STATUS_INFO_LENGTH_MISMATCH) {
            bufferSize *= 2;
            handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, bufferSize);
        }

        if (!NT_SUCCESS(status)) {
            _tprintf(TEXT("获取系统句柄信息失败: 0x%X\n"), status);
            free(handleInfo);
            CloseHandle(hProcess);
            return;
        }

        // 遍历所有句柄,筛选目标进程的文件句柄
        for (ULONG i = 0; i < handleInfo->HandleCount; i++) {
            SYSTEM_HANDLE_TABLE_ENTRY_INFO handleEntry = handleInfo->Handles[i];

            if (handleEntry.UniqueProcessId != processID) {
                continue;
            }

            // 将目标进程的句柄复制到当前进程
            HANDLE hDupHandle;
            if (!DuplicateHandle(hProcess, (HANDLE)handleEntry.Handle, GetCurrentProcess(), &hDupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
                continue;
            }

            // 判断是否为磁盘文件句柄
            DWORD fileType = GetFileType(hDupHandle);
            if (fileType == FILE_TYPE_DISK) {
                TCHAR filePath[MAX_PATH];
                // 获取文件规范化路径
                DWORD pathLen = GetFinalPathNameByHandle(hDupHandle, filePath, MAX_PATH, FILE_NAME_NORMALIZED);
                if (pathLen > 0 && pathLen <= MAX_PATH) {
                    _tprintf(TEXT("  %s\n"), filePath);
                }
            }

            CloseHandle(hDupHandle);
        }

        free(handleInfo);
    } else {
        _tprintf(TEXT("\n无法打开进程 (PID: %u)\n"), processID);
    }

    CloseHandle(hProcess);
}

int startup(void) {
    // 提升SE_DEBUG权限,否则无法访问部分系统进程
    if (!EnablePrivilege(SE_DEBUG_NAME)) {
        _tprintf(TEXT("无法提升调试权限,部分进程信息无法获取\n"));
    }

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

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

    cProcesses = cbNeeded / sizeof(DWORD);

    // 遍历所有进程,打印其已打开文件
    for (i = 0; i < cProcesses; i++) {
        if (aProcesses[i] != 0) {
            PrintProcessOpenFiles(aProcesses[i]);
        }
    }

    return 0;
}

int main(int argc, char** argv) {
    startup();
    return 0;
}

注意事项

  • 代码必须以管理员权限运行,否则无法访问大部分系统进程
  • NtQuerySystemInformation是未公开的原生API,主流Windows 10/11版本均兼容,但后续系统版本可能有变动
  • 部分受保护的系统进程句柄无法复制,这类进程的文件列表会无法获取

内容的提问来源于stack exchange,提问作者mstoreysmith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 07:50:58