public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref Structs.SECURITY_ATTRIBUTES lpProcessAttributes, ref Structs.SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, ref Structs.STARTUPINFO2 lpStartupInfo, out Structs.PROCESS_INFORMATION lpProcessInformation);
// From https://www.codeproject.com/Articles/35773/Subverting-Vista-UAC-in-Both-32-and-64-bit-Archite public static bool StartProcessAsLoggedUser(String applicationName, string startingDir, out Structs.PROCESS_INFORMATION procInfo) { int winlogonPid = 0; IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero; procInfo = new Structs.PROCESS_INFORMATION(); // obtain the currently active session id; every logged on user in the system has a unique session id uint dwSessionId = WinAPI.WTSGetActiveConsoleSessionId(); // obtain the process id of the winlogon process that is running within the currently active session // -- chaged by ty // Process[] processes = Process.GetProcessesByName("winlogon"); Process[] processes = Process.GetProcessesByName("explorer"); foreach (Process p in processes) { if ((uint)p.SessionId == dwSessionId) { winlogonPid = p.Id; } } // obtain a handle to the winlogon process //hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid); hProcess = WinAPI.OpenProcess(Structs.ProcessAccessFlags.CreateProcess | Structs.ProcessAccessFlags.DuplicateHandle | Structs.ProcessAccessFlags.QueryInformation, false, winlogonPid); // obtain a handle to the access token of the winlogon process if (!WinAPI.OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken)) { WinAPI.CloseHandle(hProcess); return(false); } // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser // I would prefer to not have to use a security attribute variable and to just // simply pass null and inherit (by default) the security attributes // of the existing token. However, in C# structures are value types and therefore // cannot be assigned the null value. Structs.SECURITY_ATTRIBUTES sa = new Structs.SECURITY_ATTRIBUTES(); sa.nLength = Marshal.SizeOf(sa); // copy the access token of the winlogon process; the newly created token will be a primary token if (!WinAPI.DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)Structs.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)Structs.TOKEN_TYPE.TokenPrimary, ref hUserTokenDup)) { WinAPI.CloseHandle(hProcess); WinAPI.CloseHandle(hPToken); return(false); } // By default CreateProcessAsUser creates a process on a non-interactive window station, meaning // the window station has a desktop that is invisible and the process is incapable of receiving // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user // interaction with the new process. Structs.STARTUPINFO2 si = new Structs.STARTUPINFO2(); si.cb = (int)Marshal.SizeOf(si); si.lpDesktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop // flags that specify the priority and creation method of the process int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; // create a new process in the current user's logon session bool result = WinAPI.CreateProcessAsUser(hUserTokenDup, // client's access token null, // file to execute applicationName, // command line ref sa, // pointer to process SECURITY_ATTRIBUTES ref sa, // pointer to thread SECURITY_ATTRIBUTES false, // handles are not inheritable dwCreationFlags, // creation flags IntPtr.Zero, // pointer to new environment block startingDir, // name of current directory ref si, // pointer to STARTUPINFO structure out procInfo // receives information about new process ); // invalidate the handles WinAPI.CloseHandle(hProcess); WinAPI.CloseHandle(hPToken); WinAPI.CloseHandle(hUserTokenDup); return(result); // return the result }