CreateProcessAsUser Creating Window in Active Session

不打扰是莪最后的温柔 提交于 2019-12-03 02:29:18

As you are probably aware already, the isolation of Session 0 is for security reason and you can read more about it here http://msdn.microsoft.com/en-us/windows/hardware/gg463353.aspx

With regard to why your console app is created in active session (e.g. session 1), this actually linked back directly to your user token. When you ask for current user token, this token automatically carried with it the session id information - in this case it is the login terminal services session (session 1). This session id is reference by the token which then replicated in the DuplicateTokenEx and then used in the CreateProcessAsUser call. In order to force the creation of the your console application in session 0, you will need to make an explicit call to the SetTokenInformation API (advapi32.dll), passed in your hDupedToken before calling CreateProcessAsUser like below

..................
UInt32 dwSessionId = 0;  // set it to session 0
SetTokenInformation(hDupedToken, TokenInformationClass.TokenSessionId, ref dwSessionId, (UInt32) IntPtr.Size);
.................
CreateProcessAsUser(hDupedToken, ....)

Here is more info on SetTokenInformation http://msdn.microsoft.com/en-us/library/windows/desktop/aa379591(v=vs.85).aspx

I was able to implement the initial post as a working solution on my end, however, I can't seem to find a way to keep my console Window hidden. I tried STARTF_USESHOWWINDOW and SW_HIDE but my command window still pops up. Any idea why?

    public const int STARTF_USESHOWWINDOW = 0x0000000;
    public const int SW_HIDE = 0;


   public static Process CreateProcessAsUser(string filename, string args)
    {
        var hToken = WindowsIdentity.GetCurrent().Token;
        var hDupedToken = IntPtr.Zero;

        var pi = new PROCESS_INFORMATION();
        var sa = new SECURITY_ATTRIBUTES();
        sa.Length = Marshal.SizeOf(sa);

        try
        {
            if (!DuplicateTokenEx(
                    hToken,
                    GENERIC_ALL_ACCESS,
                    ref sa,
                    (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
                    (int)TOKEN_TYPE.TokenPrimary,
                    ref hDupedToken
                ))
                throw new Win32Exception(Marshal.GetLastWin32Error());

            var si = new STARTUPINFO();
            si.cb = Marshal.SizeOf(si);
            si.lpDesktop = String.Empty; 

            si.dwFlags = STARTF_USESHOWWINDOW;
            si.wShowWindow = SW_HIDE;

            var path = Path.GetFullPath(filename);
            var dir = Path.GetDirectoryName(path);

            // Revert to self to create the entire process; not doing this might
            // require that the currently impersonated user has "Replace a process
            // level token" rights - we only want our service account to need
            // that right.
            using (var ctx = WindowsIdentity.Impersonate(IntPtr.Zero))
            {
                UInt32 dwSessionId = 1;  // set it to session 0
                SetTokenInformation(hDupedToken, TOKEN_INFORMATION_CLASS.TokenSessionId,
                    ref dwSessionId, (UInt32)IntPtr.Size);
                if (!CreateProcessAsUser(
                                        hDupedToken,
                                        path,
                                        string.Format("\"{0}\" {1}", filename.Replace("\"", "\"\""), args),
                                        ref sa, ref sa,
                                        false, 0, IntPtr.Zero,
                                        dir, ref si, ref pi
                                ))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            return Process.GetProcessById(pi.dwProcessID);
        }
        finally
        {
            if (pi.hProcess != IntPtr.Zero)
                CloseHandle(pi.hProcess);
            if (pi.hThread != IntPtr.Zero)
                CloseHandle(pi.hThread);
            if (hDupedToken != IntPtr.Zero)
                CloseHandle(hDupedToken);
        }
    }

Try messing around with the CharSet named parameter of MarshalAs, StructLayout, and DllImport. You might need to add MarshalAs to various strings in order to do this. Don't bother with Unicode: you aren't using this. I recommend setting them all to CharSet.Ansi first. Run all the tests that you've already tried--that is, setting the desktop and all that fun stuff. If it crashes, switch them all to auto. If it still doesn't work, remove them all.

Assuming none of this works, switch to CreateUserProcessW and CharSet.Unicode so you know what you're getting. On second thought, just skip to this step.

If you need to set the UnmanagedType with MarshalAs for strings, you want UnmanagedType.LPStr for Ansi, UnmanagedType.LPTStr for Auto, and UnmanagedType.LPWStr for Unicode. Actually, do this for all your strings anyway.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!