【问题标题】:Getting all processes in desktop获取桌面中的所有进程
【发布时间】:2020-08-24 20:45:08
【问题描述】:

我使用 CreateDesktop 创建了一个新桌面,并希望能够枚举该桌面中的所有进程。

我试过这个:

foreach (Process process in Process.GetProcesses())
{
    foreach (ProcessThread processThread in process.Threads)
    {
        IntPtr hDesk = GetThreadDesktop((uint)processThread.Id);
        if (hDesk == desk)
        {
            // Do something
        }
    }
}

但是,我得到 Access is denied 异常。我也可以用

EnumDesktopWindows

但是,这不适用于命令行应用程序。 (我试图阻止键盘记录器)

有没有办法让桌面中的所有进程? 谢谢

【问题讨论】:

  • 您以管理员身份尝试过 CMD 吗?
  • 是的,它仍然显示访问被拒绝
  • 有趣。我要试试这个。所以你想创建一个桌面,然后枚举创建的桌面上的所有窗口,对吗?如果以IntPtr.Zero 作为第一个参数调用EnumDesktopWindows 会发生什么?
  • 好吧,我知道如何在 Windows 上做到这一点,但是控制台应用程序呢?这就是我想要实现的目标
  • @Andy 非常感谢您的宝贵时间!

标签: c# .net winapi


【解决方案1】:

我花了最后一个小时玩这个,我在控制台窗口中运行良好。代码很乱,但你应该可以通过它:

class Program
{
    private static class Win32Native
    {
        [Flags]
        public enum CreateDesktopFlags : uint
        {
            DF_NONE = 0,
            DF_ALLOWOTHERACCOUNTHOOK = 1
        }

        [Flags]
        public enum CreateWindowAccessMask : uint
        {
            DESKTOP_READOBJECTS = 0x0001,
            DESKTOP_CREATEWINDOW = 0x0002,
            DESKTOP_CREATEMENU = 0x0004,
            DESKTOP_HOOKCONTROL = 0x0008,
            DESKTOP_JOURNALRECORD = 0x0010,
            DESKTOP_JOURNALPLAYBACK = 0x0020,
            DESKTOP_ENUMERATE = 0x0040,
            DESKTOP_WRITEOBJECTS = 0x0080,
            DESKTOP_SWITCHDESKTOP = 0x0100,
            DESKTOP_ALL_ACCESS = 0x01FF
        }

        [Flags]
        public enum CreateProcessFlags : uint
        {
            CREATE_NEW_CONSOLE = 0x00000010,
            CREATE_NEW_PROCESS_GROUP = 0x00000200
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct STARTUPINFO
        {
            public int cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public int dwX;
            public int dwY;
            public int dwXSize;
            public int dwYSize;
            public int dwXCountChars;
            public int dwYCountChars;
            public int dwFillAttribute;
            public int dwFlags;
            public short wShowWindow;
            public short cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public int dwProcessId;
            public int dwThreadId;
        }

        [DllImport("user32.dll")]
        public static extern IntPtr GetProcessWindowStation();

        [return: MarshalAs(UnmanagedType.Bool)]
        public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

        [return: MarshalAs(UnmanagedType.Bool)]
        public delegate bool EnumDesktopProc([MarshalAs(UnmanagedType.LPWStr)] string lpszDesktop, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumWindowsProc lpfn, IntPtr lParam);

        [DllImport("user32.dll", EntryPoint = "GetWindowTextW", CharSet = CharSet.Unicode)]
        public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

        [DllImport("user32.dll", EntryPoint = "GetClassNameW", CharSet = CharSet.Unicode)]
        public static extern int GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

        [DllImport("user32.dll", SetLastError = true, EntryPoint = "CreateDesktopW", CharSet = CharSet.Unicode)]
        public static extern IntPtr CreateDesktop(
            string lpszDesktop, IntPtr lpszDevice,
            IntPtr pDevMode, CreateDesktopFlags dwFlags,
            CreateWindowAccessMask dwDesiredAccess,
            IntPtr lpsa);

        [DllImport("user32.dll", SetLastError = true, EntryPoint = "EnumDesktopsW", CharSet = CharSet.Unicode)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumDesktops(IntPtr hwinsta, EnumDesktopProc lpEnumFunc, IntPtr lParam);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseDesktop(IntPtr hDesktop);

        [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "CreateProcessW", CharSet = CharSet.Unicode)]
        [return:MarshalAs(UnmanagedType.Bool)]
        public static extern bool CreateProcess(
            string lpApplicationName,
            string lpCommandLine,
            IntPtr lpProcessAttributes,
            IntPtr lpThreadAttributes,
            bool bInheritHandles,
            CreateProcessFlags dwCreationFlags,
            IntPtr lpEnvironment,
            string lpCurrentDirectory,
            ref STARTUPINFO lpStartupInfo,
            out PROCESS_INFORMATION lpProcessInformation);

        [DllImport("kernel32.dll")]
        [return:MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseHandle(IntPtr hObject);

        [DllImport("kernel32.dll")]
        [return:MarshalAs(UnmanagedType.Bool)]
        public static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode);
    }

    static int Main(string[] args)
    {
        StringBuilder sbWndText = new StringBuilder(512),
            sbWndClass = new StringBuilder(512);

        Console.WriteLine("Trying current desktop:");
        if(!Win32Native.EnumDesktopWindows(IntPtr.Zero, (hWnd, lParam) =>
        {
            Win32Native.GetWindowText(hWnd, sbWndText, sbWndText.Capacity);
            Win32Native.GetClassName(hWnd, sbWndClass, sbWndClass.Capacity);

            Console.WriteLine($"Found Window: {hWnd} with title \"{sbWndText}\" and class name \"{sbWndClass}\"");

            return true;
        }, IntPtr.Zero))
        {
            var error = Marshal.GetLastWin32Error();
            Console.WriteLine($"EnumDesktopWindows for current desktop failed with error {error}");
        }

        Console.WriteLine("Current desktops: ");
        Win32Native.EnumDesktops(Win32Native.GetProcessWindowStation(), (desktopName, lParam) =>
        {
            Console.WriteLine($"Found desktop: {desktopName}");
            return true;
        }, IntPtr.Zero);

        Console.WriteLine("Trying new desktop:");
        const string DesktopName = "ANDY DESKTOP NEATO 2";

        var hDesktop = Win32Native.CreateDesktop(
            DesktopName, IntPtr.Zero, IntPtr.Zero,
            Win32Native.CreateDesktopFlags.DF_ALLOWOTHERACCOUNTHOOK,
            Win32Native.CreateWindowAccessMask.DESKTOP_ALL_ACCESS,
            IntPtr.Zero);

        if(hDesktop != IntPtr.Zero)
        {
            Win32Native.EnumDesktops(Win32Native.GetProcessWindowStation(), (desktopName, lParam) =>
            {
                Console.WriteLine($"Found desktop: {desktopName}");
                return true;
            }, IntPtr.Zero);

            var si = new Win32Native.STARTUPINFO();
            si.cb = Marshal.SizeOf(si);
            si.lpDesktop = DesktopName;
            var pi = new Win32Native.PROCESS_INFORMATION();

            if(!Win32Native.CreateProcess(
                null, "cmd.exe", IntPtr.Zero, IntPtr.Zero, false,
                Win32Native.CreateProcessFlags.CREATE_NEW_CONSOLE |
                    Win32Native.CreateProcessFlags.CREATE_NEW_PROCESS_GROUP,
                IntPtr.Zero, null, ref si, out pi))
            {
                var error = Marshal.GetLastWin32Error();
                Console.WriteLine($"Unable to create process on new desktop: {error}");
            }

            Console.WriteLine("WAITING 2 SECONDS FOR PROCESS TO START...");
            Thread.Sleep(2000); // breath so the process starts

            if (!Win32Native.EnumDesktopWindows(hDesktop, (hWnd, lParam) =>
            {
                Win32Native.GetWindowText(hWnd, sbWndText, sbWndText.Capacity);
                Win32Native.GetClassName(hWnd, sbWndClass, sbWndClass.Capacity);

                Console.WriteLine($"Found Window: {hWnd} with title \"{sbWndText}\" and class name \"{sbWndClass}\"");

                return true;
            }, IntPtr.Zero))
            {
                var error = Marshal.GetLastWin32Error();
                Console.WriteLine($"EnumDesktopWindows for new desktop failed with error {error}");
            }

            // IMPORTANT: close the processes you start, otherwise you desktop won't self-destruct.
            Win32Native.TerminateProcess(pi.hProcess, 42);
            Win32Native.CloseHandle(pi.hProcess);
            Win32Native.CloseHandle(pi.hThread);
            Win32Native.CloseDesktop(hDesktop);
        }
        else
        {
            Console.WriteLine($"Unable to create desktop: {Marshal.GetLastWin32Error()}");
        }

        return 0;
    }
}

所以我认为您在使用EnumDesktopWindows 时遇到的问题是,当您致电CreateDesktop 时,您没有要求足够的权限。我将所有权限设置为(0x1FF 的值),然后 EnumDesktopWindows 为我工作。

请记住,如果您调用EnumDesktopWindows 并且没有要枚举的窗口,那么当您调用GetLastError 时,它将返回值为0 的false。

所以为了证明它确实有效,我所做的是我在新桌面中创建了一个进程 (cmd.exe),然后调用 EnumDesktopWindows。

另外请记住,如果您不销毁新桌面中的所有进程,则桌面不会“自毁”,并且在所有进程被销毁或您注销/重新启动之前它将一直处于活动状态。

我也以普通用户的身份运行它。我不需要提升为管理员来完成这项工作。

【讨论】:

【解决方案2】:

但是,这不适用于命令行应用程序。 (我在尝试 防止键盘记录器)

假设你想阻止hooking keyboard桌面的输入。

由于钩子需要一个消息循环来接收键盘消息,这需要创建一个窗口。因此限制其他用户创建与您的桌面关联的窗口应用程序可以防止他们记录键盘输入。

如果您想检查给定进程的桌面名称,以查看它是否与您的桌面名称相同(适用于窗口应用程序),您可以按照以下步骤操作:

  1. 调用OpenProcess() 以从目标进程ID 中获取HANDLE。
  2. 调用NtQueryInformationProcess()获取进程的PEB结构的地址。
  3. 致电ReadProcessMemory() 阅读PEB。它的ProcessParams.DesktopName 字段包含当前与进程关联的工作站/桌面的名称(PEB.ProcessParams 中可用的字段比 MSDN 显示的要多)。

参考“How to get window station for a given process?”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-31
    • 1970-01-01
    • 1970-01-01
    • 2013-01-29
    • 1970-01-01
    相关资源
    最近更新 更多