本文介绍如何生成在模拟用户的上下文下运行的进程。
原始产品版本: ASP.NET
原始 KB 数: 889251
简介
本分步文章介绍如何生成在 ASP.NET 页面中模拟用户上下文下运行的进程。 若要生成在模拟用户的上下文下运行的进程,不能使用该方法 System.Diagnostics.Process.Start
。 这是因为在 ASP.NET 中,模拟是在线程级别而不是在进程级别执行的。 因此,从 ASP.NET 生成的任何进程都将在 ASP.NET 工作进程的上下文中运行,而不是在模拟上下文下运行。
技术说明
若要解决此问题,必须对以下 Win32 API 进行平台调用(P/Invoke) 调用:
该
CreateProcessAsUser
函数在某个参数中指定的安全令牌标识下创建一个进程。 但是,对函数的CreateProcessAsUser
调用需要主令牌。 因此,必须将模拟令牌转换为主令牌。该
DuplicateTokenEx
函数将模拟令牌转换为主令牌。 对函数的CreateProcessAsUser
调用使用此主令牌。
注意
若要使对函数的调用 CreateProcessAsUser
正常工作,必须将以下安全用户权限分配给模拟用户:
- 在运行 Windows 的计算机上,向模拟用户分配 “替换进程级令牌 ”用户权限和 “增加配额 ”用户权限。
- 在运行 Windows Server 或 Windows XP 的计算机上,将“替换进程级令牌”用户权限分配给模拟用户。
生成进程的步骤
Microsoft 提供的编程示例仅用于进行说明,而不提供明示或默示担保。 这包括但不限于适销性或对特定用途的适用性的默示担保。 本文假设您熟悉正在演示的编程语言和用于创建和调试过程的工具。 Microsoft 支持工程师可以帮助解释特定过程的功能,但他们不会修改这些示例以提供新增功能或构建步骤以满足你的特定需要。 若要生成在模拟用户的上下文下运行的进程,请执行以下步骤:
在 Visual Studio .NET 中,创建新的 Visual C# ASP.NET Web 应用程序,然后将应用程序 命名为Q889251。
在代码视图中打开WebForm1.aspx文件。
在 WebForm1.aspx 文件中,将以下语句添加到使用代码块。
using System.Runtime.InteropServices; using System.Security.Principal;
找到类似于以下代码行的代码行。
public class WebForm1 : System.Web.UI.Page
在步骤 4 中标识的代码行之后,添加以下代码。
[StructLayout(LayoutKind.Sequential)] public struct STARTUPINFO { public int cb; public String lpReserved; public String lpDesktop; public String lpTitle; public uint dwX; public uint dwY; public uint dwXSize; public uint dwYSize; public uint dwXCountChars; public uint dwYCountChars; public uint dwFillAttribute; public uint dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public uint dwProcessId; public uint dwThreadId; } [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES { public int Length; public IntPtr lpSecurityDescriptor; public bool bInheritHandle; } [DllImport("kernel32.dll", EntryPoint="CloseHandle", SetLastError=true, CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)] public extern static bool CloseHandle(IntPtr handle); [DllImport("advapi32.dll", EntryPoint="CreateProcessAsUser", SetLastError=true, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.StdCall)] public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx")] public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
在解决方案资源管理器中,右键单击WebForm1.aspx,然后单击“打开”。 Web 窗体在 设计视图中打开。
在 “视图 ”菜单上,单击“ HTML 源”。
将 HTML 源窗口中的所有现有代码替换为以下代码。
<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="Q889251.WebForm1" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <HTML> <HEAD> <title>WebForm1</title> <meta name="GENERATOR" Content="Microsoft Visual Studio 7.0"> <meta name="CODE_LANGUAGE" Content="C#"> <meta name="vs_defaultClientScript" content="JavaScript"> <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5"> </HEAD> <body> <form id="Form1" method="post" runat="server"> <P> </P> <P> Enter Path of process to be run (with relevant parameters) <asp:TextBox id="TextBox1" runat="server"></asp:TextBox> </P> <P> <asp:Button id="Button1" runat="server" Text="CreateProcess"></asp:Button> </P> <P> <asp:Label id="Label1" runat="server">Status:</asp:Label> </P> <P> <asp:Label id="Label2" runat="server">Impersonated Identity:</asp:Label> </P> </form> </body> </HTML>
在 “视图 ”菜单上,单击“ 设计”。
双击 CreateProcess。 该方法
Button1_Click
插入代码中,代码将显示在内容窗格中。使用下面的代码替换现有
Button1_Click
方法。private void Button1_Click(object sender, System.EventArgs e) { IntPtr Token = new IntPtr(0); IntPtr DupedToken = new IntPtr(0); bool ret; Label2.Text+=WindowsIdentity.GetCurrent().Name.ToString(); SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); sa.bInheritHandle = false; sa.Length = Marshal.SizeOf(sa); sa.lpSecurityDescriptor = (IntPtr)0; Token = WindowsIdentity.GetCurrent().Token; const uint GENERIC_ALL = 0x10000000; const int SecurityImpersonation = 2; const int TokenType = 1; ret = DuplicateTokenEx(Token, GENERIC_ALL, ref sa, SecurityImpersonation, TokenType, ref DupedToken); if (ret == false) { Label1.Text +="DuplicateTokenEx failed with " + Marshal.GetLastWin32Error(); } else { Label1.Text+= "DuplicateTokenEx SUCCESS"; STARTUPINFO si = new STARTUPINFO(); si.cb = Marshal.SizeOf(si); si.lpDesktop = ""; string commandLinePath; commandLinePath = TextBox1.Text; PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); ret = CreateProcessAsUser(DupedToken,null,commandLinePath, ref sa, ref sa, false, 0, (IntPtr)0, "c:\\", ref si, out pi); if (ret == false) { Label1.Text +="CreateProcessAsUser failed with " + Marshal.GetLastWin32Error(); } else { Label1.Text +="CreateProcessAsUser SUCCESS. The child PID is" + pi.dwProcessId; CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } ret = CloseHandle(DupedToken); if (ret == false) { Label1.Text+=Marshal.GetLastWin32Error(); } else { Label1.Text+="CloseHandle SUCCESS"; } } }
在 “生成” 菜单上,单击 “生成解决方案” 。
在“调试”菜单上,单击“启动” 。
在 WebForm1 页中,键入要启动的进程的路径。 例如,键入
SystemDriver \Windows\Notepad.exe
。单击“ CreateProcess”。