private void SetTokenMandatoryLabel(IntPtr token, SecurityMandatoryLabel securityMandatoryLabel) { // Create the low integrity SID. IntPtr integritySid; if (!NativeMethods.AllocateAndInitializeSid( ref NativeMethods.SECURITY_MANDATORY_LABEL_AUTHORITY, 1, (int)securityMandatoryLabel, 0, 0, 0, 0, 0, 0, 0, out integritySid)) { throw new Win32Exception(); } var tokenMandatoryLabel = new TokenMandatoryLabel { Label = default(SidAndAttributes) }; tokenMandatoryLabel.Label.Attributes = NativeMethods.SE_GROUP_INTEGRITY; tokenMandatoryLabel.Label.Sid = integritySid; //// Marshal the TOKEN_MANDATORY_LABEL structure to the native memory. var sizeOfTokenMandatoryLabel = Marshal.SizeOf(tokenMandatoryLabel); var tokenInfo = Marshal.AllocHGlobal(sizeOfTokenMandatoryLabel); Marshal.StructureToPtr(tokenMandatoryLabel, tokenInfo, false); // Set the integrity level in the access token if (!NativeMethods.SetTokenInformation( token, TokenInformationClass.TokenIntegrityLevel, tokenInfo, sizeOfTokenMandatoryLabel + NativeMethods.GetLengthSid(integritySid))) { throw new Win32Exception(); } //// SafeNativeMethods.CloseHandle(integritySid); //// SafeNativeMethods.CloseHandle(tokenInfo); }
// Based on http://blogs.microsoft.co.il/sasha/2009/07/09/launch-a-process-as-standard-user-from-an-elevated-process/ public unsafe static Process CreateProcessAsStandardUser(string exePath, string arguments, bool launchSuspended = false) { //Enable SeIncreaseQuotaPrivilege in this process. (This requires administrative privileges.) IntPtr hProcessToken = IntPtr.Zero; var currentProcess = Process.GetCurrentProcess(); if (!OpenProcessToken(currentProcess.Handle, TokenAcess.AdjustPrivileges, out hProcessToken)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } try { TokenPrivileges tkp = new TokenPrivileges(); tkp.PrivilegeCount = 1; if (!LookupPrivilegeValue(null, IncreaseQuotaName, out Luid luid)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } tkp.Attributes = PrivilegeEnabled; if (!AdjustTokenPrivileges(hProcessToken, false, ref tkp, 0, IntPtr.Zero, IntPtr.Zero)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } finally { CloseHandle(hProcessToken); } //Get window handle representing the desktop shell. This might not work if there is no shell window, or when //using a custom shell. Also note that we're assuming that the shell is not running elevated. IntPtr hShellWnd = GetShellWindow(); if (hShellWnd == IntPtr.Zero) { throw new InvalidOperationException("Unable to locate shell window; you might be using a custom shell"); } int shellPid; GetWindowThreadProcessId(hShellWnd, out shellPid); if (shellPid == 0) { throw new Win32Exception(Marshal.GetLastWin32Error()); } //Open the desktop shell process in order to get the process token. IntPtr hShellProcess = OpenProcess(ProcessQueryInformation, false, shellPid); if (hShellProcess == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } IntPtr hShellProcessToken = IntPtr.Zero; IntPtr hPrimaryToken = IntPtr.Zero; try { //Get the process token of the desktop shell. if (!OpenProcessToken(hShellProcess, TokenAcess.Duplicate, out hShellProcessToken)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } //Duplicate the shell's process token to get a primary token. const TokenAcess tokenRights = TokenAcess.Query | TokenAcess.AssignPrimary | TokenAcess.Duplicate | TokenAcess.AdjustDefault | TokenAcess.AdjustSessionId; if (!DuplicateTokenEx(hShellProcessToken, tokenRights, IntPtr.Zero, SecurityImpersonationLevel.Impersonation, TokenType.Primary, out hPrimaryToken)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } if (!IsUacEnabled) { if (!ConvertStringSidToSid(MediumIntegritySid, out IntPtr sid)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } // Set integrity level to Medium TokenMandatoryLabel tokenMandatoryLabel = new TokenMandatoryLabel(); tokenMandatoryLabel.Label.Attributes = GroupIntegrity; tokenMandatoryLabel.Label.Sid = sid; var size = Marshal.SizeOf(tokenMandatoryLabel) + GetLengthSid(sid); if (!SetTokenInformation(hPrimaryToken, TokenInformationClass.IntegrityLevel, &tokenMandatoryLabel, size)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } // Remove elevation from token - Commented out because I couldn't get it to work. //TokenElevation elevation = new TokenElevation(); //if (!SetTokenInformation(hPrimaryToken, TokenInformationClass.Elevation, &elevation, 4)) // throw new Win32Exception(Marshal.GetLastWin32Error()); } //Start the target process with the new token. StartupInfo startupInfo = new StartupInfo(); ProcessInformation pi = new ProcessInformation(); var creationFlags = launchSuspended ? CreateSuspended : 0; if (!CreateProcessWithTokenW(hPrimaryToken, 0, exePath, exePath + " " + arguments, creationFlags, IntPtr.Zero, IntPtr.Zero, ref startupInfo, out pi)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } CloseHandle(pi.ProcessHandle); CloseHandle(pi.ThreadHandle); return(Process.GetProcessById(pi.ProcessId)); } finally { if (hShellProcessToken != IntPtr.Zero) { CloseHandle(hShellProcessToken); } if (hPrimaryToken != IntPtr.Zero) { CloseHandle(hPrimaryToken); } if (hShellProcess != IntPtr.Zero) { CloseHandle(hShellProcess); } } }