2012-05-11 76 views
2

我需要创建一个新进程,但它是另一个进程而不是当前进程的“子进程”,例如重新生成新进程。如何使用C#中的STARTUPINFOEX调用CreateProcess()并重新生成子进程

下都让我几乎没有.NET : How to call CreateProcessAsUser() with STARTUPINFOEX from C#.NET : How to PInvoke UpdateProcThreadAttributehttp://winprogger.com/launching-a-non-child-process/

using System; 
using System.Diagnostics; 
using System.IO; 
using System.Runtime.InteropServices; 

public class ProcessCreator 
{ 
    [DllImport("kernel32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool CreateProcess(
     string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, 
     ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, 
     IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo, 
     out PROCESS_INFORMATION lpProcessInformation); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool UpdateProcThreadAttribute(
     out IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue, 
     IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool InitializeProcThreadAttributeList(
     out IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize); 

    public static bool CreateProcess(int parentProcessId) 
    { 
     const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000; 
     const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000; 

     var pInfo = new PROCESS_INFORMATION(); 
     var sInfoEx = new STARTUPINFOEX(); 
     sInfoEx.StartupInfo = new STARTUPINFO(); 

     if (parentProcessId > 0) 
     { 
      var lpSize = IntPtr.Zero; 
      IntPtr dummyPtr; 
      var success = InitializeProcThreadAttributeList(out dummyPtr, 1, 0, ref lpSize); 
      if (success || lpSize == IntPtr.Zero) 
      { 
       return false; 
      } 

      sInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize); 
      if (sInfoEx.lpAttributeList == IntPtr.Zero) 
      { 
       return false; 
      } 

      success = InitializeProcThreadAttributeList(out sInfoEx.lpAttributeList, 1, 0, ref lpSize); 
      if (!success) 
      { 
       return false; 
      } 

      var parentHandle = Process.GetProcessById(parentProcessId).Handle; 
      success = UpdateProcThreadAttribute(
       out sInfoEx.lpAttributeList, 
       0, 
       (IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, 
       parentHandle, 
       (IntPtr)IntPtr.Size, 
       IntPtr.Zero, 
       IntPtr.Zero); 
      if (!success) 
      { 
       return false; 
      } 

      sInfoEx.StartupInfo.cb = Marshal.SizeOf(sInfoEx); 
     } 


     var pSec = new SECURITY_ATTRIBUTES(); 
     var tSec = new SECURITY_ATTRIBUTES(); 
     pSec.nLength = Marshal.SizeOf(pSec); 
     tSec.nLength = Marshal.SizeOf(tSec); 
     var lpApplicationName = Path.Combine(Environment.SystemDirectory, "notepad.exe"); 
     return CreateProcess(lpApplicationName, null, ref pSec, ref tSec, false, EXTENDED_STARTUPINFO_PRESENT, IntPtr.Zero, null, ref sInfoEx, out pInfo); 
    } 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
    struct STARTUPINFOEX 
    { 
     public STARTUPINFO StartupInfo; 
     public IntPtr lpAttributeList; 
    } 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
    struct STARTUPINFO 
    { 
     public Int32 cb; 
     public string lpReserved; 
     public string lpDesktop; 
     public string lpTitle; 
     public Int32 dwX; 
     public Int32 dwY; 
     public Int32 dwXSize; 
     public Int32 dwYSize; 
     public Int32 dwXCountChars; 
     public Int32 dwYCountChars; 
     public Int32 dwFillAttribute; 
     public Int32 dwFlags; 
     public Int16 wShowWindow; 
     public Int16 cbReserved2; 
     public IntPtr lpReserved2; 
     public IntPtr hStdInput; 
     public IntPtr hStdOutput; 
     public IntPtr hStdError; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    internal struct PROCESS_INFORMATION 
    { 
     public IntPtr hProcess; 
     public IntPtr hThread; 
     public int dwProcessId; 
     public int dwThreadId; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct SECURITY_ATTRIBUTES 
    { 
     public int nLength; 
     public IntPtr lpSecurityDescriptor; 
     public int bInheritHandle; 
    } 
} 

ProcessCreator.CreateProcess(0)开始记事本作为当前进程的孩子这是默认的行为。到现在为止还挺好。

如果传入的值不是0,则代码会尝试启动记事本作为进程ID与输入值匹配的进程的子进程(我假定进程现在存在)。

不幸的部分不工作,并抛出以下异常:检测

FatalExecutionEngineError 消息:运行时遇到一个致命错误。错误的地址位于线程0x1de0处的0x69a2c7ad处。错误代码是0xc0000005。此错误可能是CLR中的错误,也可能是用户代码中不安全或不可验证的部分。此错误的常见来源包括COM-interop或PInvoke的用户编组错误,这可能会破坏堆栈。

任何指针非常赞赏。

+0

Mabye http://stackoverflow.com/questions/1427196/net-how-to-pinvoke-updateprocthreadattribute有一些有用的信息 –

+1

不过,我不希望该系统允许一个进程的重新育儿;这似乎是一个巨大的安全问题。 –

+0

谢谢彼得,我发现你链接的问题很有帮助,但仅限于我目前的观点。这篇文章http://winprogger.com/launching-a-non-child-process/似乎表明我想实现的目标应该是可能的。我可能错误地把这篇文章翻译成C#,我似乎无法弄清楚什么。 –

回答

4

您的代码有两个问题。首先,InitializeProcThreadAttributeListUpdateProcThreadAttribute函数的lpAttributeList参数必须输入为IntPtr,而没有out修饰符。其次,UpdateProcThreadAttribute函数的lpValue参数必须是指针到属性值(在你的情况下,parentHandle),而不是值本身。以下是固定代码。

using System; 
using System.Diagnostics; 
using System.IO; 
using System.Runtime.InteropServices; 

public class ProcessCreator 
{ 
    [DllImport("kernel32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool CreateProcess(
     string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, 
     ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, 
     IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo, 
     out PROCESS_INFORMATION lpProcessInformation); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool UpdateProcThreadAttribute(
     IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue, 
     IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool InitializeProcThreadAttributeList(
     IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool DeleteProcThreadAttributeList(IntPtr lpAttributeList); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    static extern bool CloseHandle(IntPtr hObject); 

    public static bool CreateProcess(int parentProcessId) 
    { 
     const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000; 
     const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000; 

     var pInfo = new PROCESS_INFORMATION(); 
     var sInfoEx = new STARTUPINFOEX(); 
     sInfoEx.StartupInfo.cb = Marshal.SizeOf(sInfoEx); 
     IntPtr lpValue = IntPtr.Zero; 

     try 
     { 
      if (parentProcessId > 0) 
      { 
       var lpSize = IntPtr.Zero; 
       var success = InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize); 
       if (success || lpSize == IntPtr.Zero) 
       { 
        return false; 
       } 

       sInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize); 
       success = InitializeProcThreadAttributeList(sInfoEx.lpAttributeList, 1, 0, ref lpSize); 
       if (!success) 
       { 
        return false; 
       } 

       var parentHandle = Process.GetProcessById(parentProcessId).Handle; 
       // This value should persist until the attribute list is destroyed using the DeleteProcThreadAttributeList function 
       lpValue = Marshal.AllocHGlobal(IntPtr.Size); 
       Marshal.WriteIntPtr(lpValue, parentHandle); 

       success = UpdateProcThreadAttribute(
        sInfoEx.lpAttributeList, 
        0, 
        (IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, 
        lpValue, 
        (IntPtr)IntPtr.Size, 
        IntPtr.Zero, 
        IntPtr.Zero); 
       if (!success) 
       { 
        return false; 
       } 
      } 

      var pSec = new SECURITY_ATTRIBUTES(); 
      var tSec = new SECURITY_ATTRIBUTES(); 
      pSec.nLength = Marshal.SizeOf(pSec); 
      tSec.nLength = Marshal.SizeOf(tSec); 
      var lpApplicationName = Path.Combine(Environment.SystemDirectory, "notepad.exe"); 
      return CreateProcess(lpApplicationName, null, ref pSec, ref tSec, false, EXTENDED_STARTUPINFO_PRESENT, IntPtr.Zero, null, ref sInfoEx, out pInfo); 
     } 
     finally 
     { 
      // Free the attribute list 
      if (sInfoEx.lpAttributeList != IntPtr.Zero) 
      { 
       DeleteProcThreadAttributeList(sInfoEx.lpAttributeList); 
       Marshal.FreeHGlobal(sInfoEx.lpAttributeList); 
      } 
      Marshal.FreeHGlobal(lpValue); 

      // Close process and thread handles 
      if (pInfo.hProcess != IntPtr.Zero) 
      { 
       CloseHandle(pInfo.hProcess); 
      } 
      if (pInfo.hThread != IntPtr.Zero) 
      { 
       CloseHandle(pInfo.hThread); 
      } 
     } 
    } 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
    struct STARTUPINFOEX 
    { 
     public STARTUPINFO StartupInfo; 
     public IntPtr lpAttributeList; 
    } 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
    struct STARTUPINFO 
    { 
     public Int32 cb; 
     public string lpReserved; 
     public string lpDesktop; 
     public string lpTitle; 
     public Int32 dwX; 
     public Int32 dwY; 
     public Int32 dwXSize; 
     public Int32 dwYSize; 
     public Int32 dwXCountChars; 
     public Int32 dwYCountChars; 
     public Int32 dwFillAttribute; 
     public Int32 dwFlags; 
     public Int16 wShowWindow; 
     public Int16 cbReserved2; 
     public IntPtr lpReserved2; 
     public IntPtr hStdInput; 
     public IntPtr hStdOutput; 
     public IntPtr hStdError; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    internal struct PROCESS_INFORMATION 
    { 
     public IntPtr hProcess; 
     public IntPtr hThread; 
     public int dwProcessId; 
     public int dwThreadId; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct SECURITY_ATTRIBUTES 
    { 
     public int nLength; 
     public IntPtr lpSecurityDescriptor; 
     public int bInheritHandle; 
    } 
} 
相关问题