使用 CREATE_SUSPENDED 标志和 JobObject 从 CreateProcessAsUser 为 C# 进程设置 ProcessStartInfo

Posted

技术标签:

【中文标题】使用 CREATE_SUSPENDED 标志和 JobObject 从 CreateProcessAsUser 为 C# 进程设置 ProcessStartInfo【英文标题】:Setting up ProcessStartInfo for C# process from CreateProcessAsUser with CREATE_SUSPENDED flag and JobObject 【发布时间】:2021-10-26 01:41:29 【问题描述】:

在我的 C# 程序中,我需要 (1) 创建一个处于挂起状态的进程并 (2) 修改令牌。我这样做是为了可以将其注册到 JobObject 以便如果父进程在子进程仍在运行时意外死亡,则子进程会被杀死。我需要根据业务需求修改令牌。

我发现不可能将未启动的 C# Process 添加到 JobObject,或在暂停状态,或修改其令牌。所以,我使用 C++ CreateProcessAsUser 来完成这些事情。到目前为止,一切顺利:

      [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
      private static extern bool CreateProcessAsUser(
        IntPtr hToken,
        String lpApplicationName,
        String lpCommandLine,
        IntPtr lpProcessAttributes,
        IntPtr lpThreadAttributes,
        bool bInheritHandle,
        uint dwCreationFlags,
        IntPtr lpEnvironment,
        String lpCurrentDirectory,
        ref STARTUPINFO lpStartupInfo,
        out PROCESS_INFORMATION lpProcessInformation);

      public static uint CreateSuspendedProcess(string appPath, string cmdLine = null, bool visible = false)
            result = CreateProcessAsUser(
              hUserToken, // Modified token - working great
              appPath, // Application Name - doesn't end up in Process.ProcessStartInfo?
              cmdLine, // is null
              IntPtr.Zero,
              IntPtr.Zero,
              false,
              dwCreationFlags, // contains CREATE_SUSPENDED
              pEnv,
              null, // working directory
              ref startInfo, // not related to C# ProcessStartInfo?
              out procInfo);

// does other stuff, and then returns the Process ID

我遇到问题的地方实际上是开始这个​​过程。

从调用者(参见下面的 sn-p)中,我尝试从使用 CreateProcessAsUser 创建的进程的 ID 中获取进程。 CreateProcessAsUser 创建的进程没有包含文件名的 StartInfo。我希望 appPath 的功能与 StartInfo.FileName 相同,但这里有一些我不明白的地方,因为 process.StartInfo 似乎是虚拟信息,per the documentation I read here 表示 GetProcesses 等,不会返回 StartInfo 并且 StartInfo 无法修改一旦一个过程开始。我想创建一个处于挂起状态的进程算作启动。

我是一名新手开发人员,在试图解决这个问题之前从未使用过 C++,但我能够学到的是,也许我不应该尝试做 Process.Start - 但我没有找到满足将流程注册到 JobObject 需求的任何替代方案。

 var processId = CreateSuspendedProcess(startInfo.FileName, startInfo.Arguments);

 IntPtr hProcess = IntPtr.Zero;

 using (var job = new Job())
 using (var process = Process.GetProcessById((int)processId)) // use the suspended process
 

    var jobSuccess = job.AddProcess(process.Id); // this works

    if (!jobSuccess)
    
       // do not proceed if process cannot be run in job object; dispose of both
       throw new Exception("Failed to add process to job object.");
    

    // === I want the start info to have the filename, but can't except in Debug
    //process.StartInfo.FileName = startInfo.FileName;

    // other code here
    Process.Start(); // Get a no FileName error

【问题讨论】:

以下内容可能会有所帮助:***.com/questions/3342941/… 【参考方案1】:

是的,答案是避免使用 C# Process 类方法,而是手动打开和恢复进程中的所有线程。

  [DllImport("kernel32.dll")]
  static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);

  [DllImport("kernel32.dll")]
  static extern int ResumeThread(IntPtr hThread);

【讨论】:

以上是关于使用 CREATE_SUSPENDED 标志和 JobObject 从 CreateProcessAsUser 为 C# 进程设置 ProcessStartInfo的主要内容,如果未能解决你的问题,请参考以下文章

Java类的标志出现了一个大j,好像action找不到这个类?

[LeetCode]最大系列(最大正方形221,最大加号标志764)

如何在 FPNTextField 中检测国家代码和更改标志

带有标志的“继续”作用于哪个循环?

python3.5中的标志位

Codeforces 1142D Foreigner (DP)