2008-09-16 67 views
22

如何在C#中暂停整个进程(如Process Explorer在单击暂停时执行的操作)。在C#中挂起进程#

我开始使用Process.Start进程,并且在某个事件上,我想暂停进程以便能够对其“快照”进行一些调查。

回答

27

这是我的建议:

[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

我不认为pOpenThread.Equals(null)将永远返回true。 它应该是pOpenThread == IntPtr.Zero IMO。其余的作品都很不错!谢谢! – 2008-09-16 13:49:58

+0

当然可以! 我将编辑代码。 谢谢。 – 2008-09-16 13:56:04

3

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

1

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

Process.Start将返回您一个Process对象,从中可以获取进程ID,然后传递给你的新库基于上述

戴夫

2

所以真的,有什么其他答案正在显示正在挂起线程的过程中,没有办法真正暂停过程(即在一次调用中)。...

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

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

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

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

10

谢谢给马格努斯

包括标志之后,我修改了一下代码,使其成为我项目中的扩展方法。我现在可以使用

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