/// <summary> /// The function launches an application at low integrity level. /// </summary> /// <param name="commandLine"> /// The command line to be executed. The maximum length of this string is 32K /// characters. /// </param> /// <param name="selectedIntegrityLevel"> /// Numeric representation of integrity level with which process has to be started /// </param> /// <remarks> /// To start a low-integrity process, /// 1) Duplicate the handle of the current process, which is at medium /// integrity level. /// 2) Use SetTokenInformation to set the integrity level in the access token /// to Low. /// 3) Use CreateProcessAsUser to create a new process using the handle to /// the low integrity access token. /// </remarks> public static void CreateSpecificIntegrityProcess(string commandLine, int selectedIntegrityLevel) { SafeTokenHandle hToken = null; SafeTokenHandle hNewToken = null; IntPtr pIntegritySid = IntPtr.Zero; int cbTokenInfo = 0; IntPtr pTokenInfo = IntPtr.Zero; STARTUPINFO si = new STARTUPINFO(); PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); try { // Open the primary access token of the process. if (!NativeMethod.OpenProcessToken(Process.GetCurrentProcess().Handle, NativeMethod.TOKEN_DUPLICATE | NativeMethod.TOKEN_ADJUST_DEFAULT | NativeMethod.TOKEN_QUERY | NativeMethod.TOKEN_ASSIGN_PRIMARY, out hToken)) { throw new Win32Exception(); } // Duplicate the primary token of the current process. if (!NativeMethod.DuplicateTokenEx(hToken, 0, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out hNewToken)) { throw new Win32Exception(); } // Create the low integrity SID. if (!NativeMethod.AllocateAndInitializeSid( ref NativeMethod.SECURITY_MANDATORY_LABEL_AUTHORITY, 1, selectedIntegrityLevel, 0, 0, 0, 0, 0, 0, 0, out pIntegritySid)) { throw new Win32Exception(); } TOKEN_MANDATORY_LABEL tml; tml.Label.Attributes = NativeMethod.SE_GROUP_INTEGRITY; tml.Label.Sid = pIntegritySid; // Marshal the TOKEN_MANDATORY_LABEL struct to the native memory. cbTokenInfo = Marshal.SizeOf(tml); pTokenInfo = Marshal.AllocHGlobal(cbTokenInfo); Marshal.StructureToPtr(tml, pTokenInfo, false); // Set the integrity level in the access token to low. if (!NativeMethod.SetTokenInformation(hNewToken, TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, pTokenInfo, cbTokenInfo + NativeMethod.GetLengthSid(pIntegritySid))) { throw new Win32Exception(); } // Create the new process at the Low integrity level. si.cb = Marshal.SizeOf(si); if (!NativeMethod.CreateProcessAsUser(hNewToken, null, commandLine, IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, null, ref si, out pi)) { throw new Win32Exception(); } } finally { // Centralized cleanup for all allocated resources. if (hToken != null) { hToken.Close(); hToken = null; } if (hNewToken != null) { hNewToken.Close(); hNewToken = null; } if (pIntegritySid != IntPtr.Zero) { NativeMethod.FreeSid(pIntegritySid); pIntegritySid = IntPtr.Zero; } if (pTokenInfo != IntPtr.Zero) { Marshal.FreeHGlobal(pTokenInfo); pTokenInfo = IntPtr.Zero; cbTokenInfo = 0; } if (pi.hProcess != IntPtr.Zero) { NativeMethod.CloseHandle(pi.hProcess); pi.hProcess = IntPtr.Zero; } if (pi.hThread != IntPtr.Zero) { NativeMethod.CloseHandle(pi.hThread); pi.hThread = IntPtr.Zero; } } }