C#中的挂起过程

时间:2020-03-05 18:55:39  来源:igfitidea点击:

如何在C#中挂起整个流程(就像单击"挂起"时的Process Explorer一样)。

我正在使用Process.Start启动Process,并且在某个事件中,我想暂停该进程以便能够对其进行"快照"进行调查。

解决方案

回答

可以在CodeProject上找到使用Win32 p / invoke的详细解决方案。

回答

有关win32的基础知识,请参见此CodeProject文章:http://www.codeproject.com/KB/threads/pausep.aspx。此示例代码利用了SDK中的ToolHelp32库,因此,我建议我们使用一个简单的接口(例如" SuspendProcess(uint processID))"将此示例代码转换为非托管C ++ / CLI库。

Process.Start将返回一个Process对象,我们可以从该对象获取流程ID,然后根据上述内容将其传递给新库。

戴夫

回答

这是我的建议:

[Flags]
    public enum ThreadAccess : int
    {
      TERMINATE = (0x0001),
      SUSPEND_RESUME = (0x0002),
      GET_CONTEXT = (0x0008),
      SET_CONTEXT = (0x0010),
      SET_INFORMATION = (0x0020),
      QUERY_INFORMATION = (0x0040),
      SET_THREAD_TOKEN = (0x0080),
      IMPERSONATE = (0x0100),
      DIRECT_IMPERSONATION = (0x0200)
    }

    [DllImport("kernel32.dll")]
    static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
    [DllImport("kernel32.dll")]
    static extern uint SuspendThread(IntPtr hThread);
    [DllImport("kernel32.dll")]
    static extern int ResumeThread(IntPtr hThread);
    [DllImport("kernel32", CharSet = CharSet.Auto,SetLastError = true)]
    static extern bool CloseHandle(IntPtr handle);

private static void SuspendProcess(int pid)
{
  var process = Process.GetProcessById(pid);

  if (process.ProcessName == string.Empty)
    return;

  foreach (ProcessThread pT in process.Threads)
  {
    IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);

    if (pOpenThread == IntPtr.Zero)
    {
      continue;
    }

    SuspendThread(pOpenThread);

    CloseHandle(pOpenThread);
  }
}

public static void ResumeProcess(int pid)
{
  var process = Process.GetProcessById(pid);

  if (process.ProcessName == string.Empty)
    return;

  foreach (ProcessThread pT in process.Threads)
  {
    IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);

    if (pOpenThread == IntPtr.Zero)
    {
      continue;
    }

    var suspendCount = 0;
    do
    {
      suspendCount = ResumeThread(pOpenThread);
    } while (suspendCount > 0);

    CloseHandle(pOpenThread);
  }
}

回答

所以真的,其他答案显示的是正在挂起进程的线程,没有办法真正挂起该进程(即在一个调用中)....

另一个不同的解决方案是实际调试我们要启动的目标进程,请参见Mike Stall的博客,以获取有关如何从托管上下文实现此目标的一些建议。

如果实现调试器,则将能够扫描内存或者我们想要的其他快照。

但是,我想指出的是,从技术上讲,现在确实可以做到这一点。即使我们确实调试了目标调试对象进程,系统上的另一个进程也可能会注入一个线程,并且将具有执行代码的能力,而不管目标进程的状态如何(即使我们说它是否由于访问冲突而达到断点) ),如果我们已将所有线程的暂停数量都提高到超高的暂停数量,并且当前处于主进程线程的断点,并且处于任何其他此类假定的冻结状态,则系统仍然有可能向该进程注入另一个线程并执行一些指令。我们还可能会遇到修改或者替换内核通常调用的所有入口点的麻烦,以此类推,但是现在我们已经进入了恶意软件的竞争之列;)...

在任何情况下,使用托管接口进行调试似乎比p /调用许多本地API调用要容易得多,因为这样做会在模拟我们可能真正想做的事情上做得很差。 ;)