在C#中暂停进程

时间:2008-09-16 11:07:34

标签: c# .net

如何在C#中暂停整个过程(就像我点击暂停时的Process Explorer一样)。

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

6 个答案:

答案 0 :(得分:33)

这是我的建议:

 [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);
  }
}

答案 1 :(得分:11)

感谢Magnus

在包含Flags之后,我将代码修改为我项目中的扩展方法。我现在可以使用

var process = Process.GetProcessById(param.PId);
process.Suspend();

以下是可能感兴趣的人的代码。

public static class ProcessExtension
{
    [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);

    public static void Suspend(this Process process)
    {
        foreach (ProcessThread thread in process.Threads)
        {
            var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
            if (pOpenThread == IntPtr.Zero)
            {
                break;
            }
            SuspendThread(pOpenThread);
        }
    }
    public static void Resume(this Process process)
    {
        foreach (ProcessThread thread in process.Threads)
        {
            var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
            if (pOpenThread == IntPtr.Zero)
            {
                break;
            }
            ResumeThread(pOpenThread);
        }
    }
}

我已经完成了一个实用程序,我通常用它来暂停/终止/列出进程。完整来源是on Git

答案 2 :(得分:3)

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

答案 3 :(得分:2)

所以真的,其他答案显示的是暂停线程的过程,没有办法真正暂停进程(即在一次通话中)....

一个不同的解决方案是实际调试您正在启动的目标进程,请参阅Mike Stall's blog以获取有关如何从托管上下文实现此目的的一些建议。

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

但是,我想指出,从技术上讲,现在有办法真正做到这一点。即使你执行debugbreak一个目标调试对象进程,你的系统上的另一个进程可能会注入一个线程,并且无论目标进程的状态如何,都会给它一些执行代码的能力(甚至让我们说它是否因为访问冲突而遇到了断点) ),如果你所有的线程被挂起到超高挂起计数,当前处于主进程线程的断点和任何其他这样的假定冻结状态,系统仍然可以将另一个线程注入该进程并执行一些指令。您也可能会遇到修改或替换所有入口点kernel usually calls等等的麻烦,但您现在已进入粘性臂的MALWARE竞赛;)...

在任何情况下,使用托管接口进行调试似乎“比p / invoke”更多的本地API调用更容易,这将很难模拟你可能真正想做的事情......使用debug api的;)

答案 4 :(得分:1)

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

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

戴夫

答案 5 :(得分:0)

[DllImport("ntdll.dll", PreserveSig = false)]
    public static extern void NtSuspendProcess(IntPtr processHandle);
    static IntPtr handle;

        string p = "";
        foreach (Process item in Process.GetProcesses())
        {
            if (item.ProcessName == "GammaVPN")
            {
                p = item.ProcessName;
                handle = item.Handle;
                NtSuspendProcess(handle);
            }
        }
        Console.WriteLine(p);
        Console.WriteLine("done");