/// <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> /// <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> internal void CreateLowIntegrityProcess(string commandLine) { 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, NativeMethod.SECURITY_MANDATORY_LOW_RID, 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; } } }
/// <summary> /// 此函数以低完整性级别启动一个应用程序 /// </summary> /// <param name="commandLine"> /// 需要被执行的命令行。此字符串最长为32K个字符。 /// </param> /// <remarks> /// 启动一个低完整性进程 /// 1) 复制当前进程的句柄,它拥有中完整性级别 /// 2)使用SetTokenInformation设置访问进程的完整性级别为低。 /// 3)使用CreateProcessAsUser及低完整性级别的访问令牌创建一个新的进程。 /// </remarks> internal void CreateLowIntegrityProcess(string commandLine) { SafeTokenHandle hToken = null; SafeTokenHandle hNewToken = null; string strIntegritySid = "S-1-16-4096"; // Low integrity SID string 低完整性SID字符串 IntPtr pIntegritySid = IntPtr.Zero; int cbTokenInfo = 0; IntPtr pTokenInfo = IntPtr.Zero; STARTUPINFO si = new STARTUPINFO(); PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); try { // 打开进程的主访问令牌。 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(); } // 复制当前进程的主令牌。 if (!NativeMethod.DuplicateTokenEx(hToken, 0, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out hNewToken)) { throw new Win32Exception(); } // 创建低完整性SID。 if (!NativeMethod.ConvertStringSidToSid(strIntegritySid, out pIntegritySid)) { throw new Win32Exception(); } TOKEN_MANDATORY_LABEL tml; tml.Label.Attributes = NativeMethod.SE_GROUP_INTEGRITY; tml.Label.Sid = pIntegritySid; // 转换TOKEN_MANDATORY_LABEL结构至native内存。 cbTokenInfo = Marshal.SizeOf(tml); pTokenInfo = Marshal.AllocHGlobal(cbTokenInfo); Marshal.StructureToPtr(tml, pTokenInfo, false); // 设置访问令牌的完整性级别为低。 if (!NativeMethod.SetTokenInformation(hNewToken, TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, pTokenInfo, cbTokenInfo + NativeMethod.GetLengthSid(pIntegritySid))) { throw new Win32Exception(); } // 以低完整性级别创建一个新进程。 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 { // 集中清理已分配的资源 if (hToken != null) { hToken.Close(); hToken = null; } if (hNewToken != null) { hNewToken.Close(); hNewToken = null; } if (pIntegritySid != IntPtr.Zero) { Marshal.FreeHGlobal(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; } } }