Microsoft ASP.NET 가장한 사용자의 컨텍스트에서 실행되는 프로세스를 생성합니다.

이 문서에서는 가장된 사용자의 컨텍스트에서 실행되는 프로세스를 생성하는 방법을 설명합니다.

원래 제품 버전: ASP.NET
원래 KB 번호: 889251

소개

이 단계별 문서에서는 ASP.NET 페이지에서 가장한 사용자의 컨텍스트에서 실행되는 프로세스를 생성하는 방법을 설명합니다. 가장된 사용자의 컨텍스트에서 실행되는 프로세스를 생성하려면 메서드를 System.Diagnostics.Process.Start 사용할 수 없습니다. ASP.NET 가장은 프로세스 수준이 아닌 스레드 수준에서 수행되기 때문입니다. 따라서 ASP.NET 생성되는 모든 프로세스는 가장된 컨텍스트가 아닌 ASP.NET 작업자 프로세스의 컨텍스트에서 실행됩니다.

기술에 대한 설명

이 문제를 해결하려면 다음 Win32 API에 대한 플랫폼 호출(P/Invoke) 호출을 수행해야 합니다.

  • 함수는 CreateProcessAsUser 매개 변수 중 하나에 지정된 보안 토큰의 ID 아래에 프로세스를 만듭니다. 그러나 함수를 호출하려면 CreateProcessAsUser 기본 토큰이 필요합니다. 따라서 가장된 토큰을 기본 토큰으로 변환해야 합니다.

  • 함수는 DuplicateTokenEx 가장된 토큰을 기본 토큰으로 변환합니다. 함수에 대한 호출은 CreateProcessAsUser 이 기본 토큰을 사용합니다.

참고

함수 호출이 CreateProcessAsUser 작동하려면 가장한 사용자에게 다음 보안 사용자 권한을 할당해야 합니다.

  • Windows를 실행하는 컴퓨터에서 프로세스 수준 토큰 사용자 바꾸기 권한 및 가장된 사용자에게 할당량 사용자 권한 증가를 할당합니다.
  • Windows Server 또는 Windows XP를 실행하는 컴퓨터에서 가장된 사용자에게 프로세스 수준 토큰 바꾸기 권한을 할당합니다.

프로세스를 생성하는 단계

Microsoft에서 제공하는 프로그래밍 예제는 예시를 위한 것일 뿐이며 이와 관련하여 명시적이거나 묵시적인 어떠한 보증도 하지 않습니다. 이는 상품성이나 특정 목적에 대한 적합성의 묵시적인 보증을 포함하며 이에 제한되지 않습니다. 이 문서에서는 예제에 사용되고 있는 프로그래밍 언어와 프로시저를 만들고 디버깅하는 데 사용되는 도구를 사용자가 잘 알고 있는 것으로 가정합니다. Microsoft 지원 엔지니어는 사용자에게 도움이 되도록 특정 프로시저에 대한 기능을 설명할 수 있지만 사용자의 특정 요구 사항에 맞도록 예제를 수정하여 추가 기능을 제공하거나 프로시저를 구성하지는 않습니다. 가장된 사용자의 컨텍스트에서 실행되는 프로세스를 생성하려면 다음 단계를 수행합니다.

  1. Visual Studio .NET에서 새 Visual C# ASP.NET 웹 애플리케이션을 만든 다음 애플리케이션 이름을 Q889251.

  2. 코드 보기에서 WebForm1.aspx 파일을 엽니다.

  3. WebForm1.aspx 파일에서 다음 문을 using 코드 블록에 추가합니다.

    using System.Runtime.InteropServices;
    using System.Security.Principal;
    
  4. 다음 코드 줄과 비슷한 코드 줄을 찾습니다.

    public class WebForm1 : System.Web.UI.Page
    
  5. 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);
    
  6. 솔루션 탐색기 WebForm1.aspx 마우스 오른쪽 단추로 클릭한 다음 열기를 클릭합니다. 웹 양식이 디자인 보기에서 열립니다.

  7. 보기 메뉴에서 HTML 원본을 클릭합니다.

  8. 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>&nbsp;</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>
    
  9. 보기 메뉴에서 디자인을 클릭합니다.

  10. CreateProcess를 두 번 클릭합니다. Button1_Click 메서드가 코드에 삽입되고 코드가 콘텐츠 창에 나타납니다.

  11. 기존 메서드를 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";
            }
        }
    }
    
  12. 빌드 메뉴에서 솔루션 빌드를 클릭합니다.

  13. 디버그 메뉴에서 시작을 클릭합니다.

  14. WebForm1 페이지에서 시작하려는 프로세스의 경로를 입력합니다. 예를 들어 SystemDriver \Windows\Notepad.exe를 입력합니다.

  15. CreateProcess를 클릭합니다.

참조