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

如何通过进程ID获取wininit.exe等系统文件路径?现有实现无法生效

问题原因

你遇到的无法获取wininit.exe等系统进程路径的问题,核心是两个限制:

  • 权限不足:普通用户权限(甚至未开调试特权的管理员权限)都无法访问会话0里的系统核心进程的模块信息,Process.GetProcesses()拿不到主模块路径、WMI返回空都是这个原因
  • 架构不匹配:如果你的程序编译为32位,在64位系统上运行时受WoW64机制限制,无法读取64位系统进程的路径信息

修复步骤

1. 调整项目基础配置

首先修改项目编译参数:
右键项目 → 「属性」→ 「生成」页,取消勾选「首选32位」,平台目标选择Any CPU。

2. 配置程序管理员启动权限

给项目添加应用程序清单文件(app.manifest),将requestedExecutionLevel节点修改为如下配置,确保程序启动时请求管理员权限:

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

3. 开启SeDebugPrivilege调试特权

管理员账号默认没有开启调试特权,需要手动启用才能访问系统进程信息,下面是完整的可用代码,包含特权开启逻辑和两种路径获取实现:

工具类代码(包含特权开启和路径获取)

using System;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Runtime.InteropServices;

public static class ProcessPathHelper
{
    // 开启调试特权所需的Win32 API定义
    [StructLayout(LayoutKind.Sequential)]
    private struct LUID
    {
        public uint LowPart;
        public int HighPart;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct LUID_AND_ATTRIBUTES
    {
        public LUID Luid;
        public uint Attributes;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct TOKEN_PRIVILEGES
    {
        public uint PrivilegeCount;
        public LUID_AND_ATTRIBUTES Privileges;
    }

    private const uint SE_PRIVILEGE_ENABLED = 0x00000002;
    private const string SE_DEBUG_NAME = "SeDebugPrivilege";
    private const uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
    private const uint TOKEN_QUERY = 0x0008;

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, uint BufferLength, IntPtr PreviousState, IntPtr ReturnLength);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool CloseHandle(IntPtr hObject);

    // 调用一次即可开启当前进程的调试特权
    public static bool EnableDebugPrivilege()
    {
        IntPtr hToken = IntPtr.Zero;
        try
        {
            if (!OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out hToken))
                return false;

            LUID luid;
            if (!LookupPrivilegeValue(null, SE_DEBUG_NAME, out luid))
                return false;

            TOKEN_PRIVILEGES tp = new TOKEN_PRIVILEGES();
            tp.PrivilegeCount = 1;
            tp.Privileges.Luid = luid;
            tp.Privileges.Attributes = SE_PRIVILEGE_ENABLED;

            if (!AdjustTokenPrivileges(hToken, false, ref tp, (uint)Marshal.SizeOf(tp), IntPtr.Zero, IntPtr.Zero))
                return false;

            return Marshal.GetLastWin32Error() == 0;
        }
        finally
        {
            if (hToken != IntPtr.Zero)
                CloseHandle(hToken);
        }
    }

    // 方法1:基于WMI的实现(你原有代码的修复版)
    public static string GetMainModuleFilePathByWmi(int processId)
    {
        try
        {
            string wmiQueryString = $"SELECT ProcessId, ExecutablePath FROM Win32_Process WHERE ProcessId = {processId}";
            using (var searcher = new ManagementObjectSearcher(wmiQueryString))
            {
                using (var results = searcher.Get())
                {
                    ManagementObject mo = results.Cast<ManagementObject>().FirstOrDefault();
                    if (mo != null && mo["ExecutablePath"] != null)
                    {
                        return mo["ExecutablePath"].ToString();
                    }
                }
            }
        }
        catch
        {
            // 按需处理异常
        }
        return null;
    }

    // 方法2:基于Win32 API的实现(性能更高,更适合任务管理器场景)
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, [Out] char[] lpExeName, ref uint lpdwSize);

    private const uint PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;

    public static string GetMainModuleFilePathByApi(int processId)
    {
        IntPtr hProcess = IntPtr.Zero;
        try
        {
            hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, processId);
            if (hProcess == IntPtr.Zero)
                return null;

            uint bufferSize = 1024;
            char[] buffer = new char[bufferSize];
            if (QueryFullProcessImageName(hProcess, 0, buffer, ref bufferSize))
            {
                return new string(buffer, 0, (int)bufferSize);
            }
        }
        catch
        {
            // 按需处理异常
        }
        finally
        {
            if (hProcess != IntPtr.Zero)
                CloseHandle(hProcess);
        }
        return null;
    }
}

调用示例

程序启动时先调用一次EnableDebugPrivilege()开启特权,之后就可以正常获取所有进程的路径了:

// 程序初始化阶段执行一次
ProcessPathHelper.EnableDebugPrivilege();

// 后续获取进程路径
int pid = 你的进程ID;
// 两种方法二选一即可,API版本性能更高
string path1 = ProcessPathHelper.GetMainModuleFilePathByWmi(pid);
string path2 = ProcessPathHelper.GetMainModuleFilePathByApi(pid);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 13:24:01