尝试获取客户端进程可执行路径时出现“拒绝访问”错误

时间:2016-11-04 11:26:03

标签: c# windows wcf winapi namedpipeserverstream

我正在处理作为Windows服务托管的WCF服务,该服务使用命名管道 - NamedPipeServerStream (用户权限)在服务器和客户端进程之间建立安全连接。要检查客户端进程的真实性,我需要验证客户端进程可执行文件的数字签名,因此我试图通过使用其进程ID来获取客户端的可执行路径。

我使用 Windows 7 Professional SP1(64位)操作系统 Visual Studio 2015社区版进行开发。服务器(Windows服务)和客户端进程(其他exe)都仅以 Release x64 模式构建。

当某个客户端进程连接到服务器时,我试图获取客户端进程的exe路径,但它在以下代码行中抛出“拒绝访问”错误

return Process.GetProcessById(processId).MainModule.FileName;

因此,为了解决这个问题,我已经搜索了一下,并尝试了一些其他的实验性试验,如下所述,似乎也没有成功。

实验性试验

  1. 尝试使用查询访问权限获取客户端进程句柄但失败了 - >始终返回0,最后一次Win32错误为5(拒绝访问
  2. OpenProcess(ProcessAccessFlags.PROCESS_QUERY_INFORMATION, false, processId);

    1. 尝试使用有限的查询访问权限获取客户端进程句柄但失败 - >始终返回0,最后一次Win32错误为5(拒绝访问
    2. OpenProcess(ProcessAccessFlags.PROCESS_QUERY_LIMITED_INFORMATION, false, processId);

      1. 设置SeDebugPrivilege并继续获取具有有限查询权限但未通过的客户端进程句柄 - > SeDebugPrivilege已启用但仍为流程句柄返回0,最后一个Win32错误为5(拒绝访问)。
      2. 尝试使用app.manifest文件(requireAdministrator属性)将管理员权限设置为Windows服务,但失败了 - > 拒绝访问
      3. 尝试使用ManagementObject获取进程信息属性但失败 - >对象引用未设置为对象的实例
      4. 将“Windows服务”的登录帐户从“本地服务”更改为“本地系统”但未通过
      5. 但是,我在示例Windows控制台应用程序中尝试了上述所有方法,该应用程序运行正常,没有任何错误,并且在Windows服务中也不起作用。此外,我尝试将控制台应用程序转换为dll并在服务器中引用它以获取客户端进程信息但失败 - >再次访问被拒绝

        我完全不知道发生了什么以及如何解决它。你的建议真有帮助。

        编辑:请查找OpenProcess和ProcessAccessFlags的代码段,如下所示:

        public static string GetProcessExecutablePath(int processId)
        {
            try
            {
                string exePath = string.Empty;
                //If running on Vista or later use the new function
                if (Environment.OSVersion.Version.Major >= 6)
                {
                    return GetProcessExecutablePathAboveVista(processId);
                }
                return Process.GetProcessById(processId).MainModule.FileName;
            }
            catch (Exception ex)
            {
                return "Exception in GetProcessExecutablePath(): " + ex.Message + ": " + ex.InnerException;
            }
        }    
        
        private static string GetProcessExecutablePathAboveVista(int processId)
        {
            var buffer = new StringBuilder(1024);
            IntPtr hprocess = NativeMethods.OpenProcess(NativeMethods.ProcessAccessFlags.PROCESS_QUERY_LIMITED_INFORMATION,
                                              false, processId);
            if (hprocess != IntPtr.Zero)
            {
                try
                {
                    int size = buffer.Capacity;
                    if (NativeMethods.QueryFullProcessImageName(hprocess, 0, buffer, out size))
                    {
                        return buffer.ToString();
                    }
                    else
                    {
                        return "Failed in QueryFullProcessImageName(): " + Marshal.GetLastWin32Error();;
                    }
                }
                catch (Exception ex)
                {
                    return "Exception in: " + ex.Message;
                }
                finally
                {
                    NativeMethods.CloseHandle(hprocess);
                }
            }
            else
            {
                return "Handle is Zero: " + Marshal.GetLastWin32Error();
            }
        }
        

        NativeMethods.cs

        [Flags]
        public enum ProcessAccessFlags
        {
            PROCESS_TERMINATE = 0x0001,
            PROCESS_CREATE_THREAD = 0x0002,
            PROCESS_VM_OPERATION = 0x0008,
            PROCESS_VM_READ = 0x0010,
            PROCESS_VM_WRITE = 0x0020,
            PROCESS_DUP_HANDLE = 0x0040,
            PROCESS_CREATE_PROCESS = 0x0080,
            PROCESS_SET_QUOTA = 0x0100,
            PROCESS_SET_INFORMATION = 0x0200,
            PROCESS_QUERY_INFORMATION = 0x0400,
            PROCESS_SUSPEND_RESUME = 0x0800,
            PROCESS_QUERY_LIMITED_INFORMATION = 0x1000,
            SYNCHRONIZE = 0x100000,
            DELETE = 0x00010000,
            READ_CONTROL = 0x00020000,
            WRITE_DAC = 0x00040000,
            WRITE_OWNER = 0x00080000,
            STANDARD_RIGHTS_REQUIRED = 0x000F0000,
            PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF
        }
        
        [DllImport("Kernel32.dll", EntryPoint = "OpenProcess", SetLastError = true)]
        public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId);
        
        [DllImport("Kernel32.dll", EntryPoint = "QueryFullProcessImageName", SetLastError = true)]
        public static extern bool QueryFullProcessImageName(IntPtr hprocess, int dwFlags, StringBuilder lpExeName, out int size);
        
        [DllImport("Kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseHandle(IntPtr hHandle);
        

1 个答案:

答案 0 :(得分:0)

对于从Vista开始以通过pid获取过程映像文件名的Windows,您可以使用NtQuerySystemInformation(SystemProcessInformation, ...)获取每个进程的SYSTEM_PROCESS_INFORMATION结构数组。此结构有PVOID UniqueProcessId来查找您要查找的pid,UNICODE_STRING ImageName来获取图像文件名,请参阅 https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms724509(v=vs.85).aspx https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/process.htm