【问题标题】:Suspend Process in C#C#中的暂停进程
【发布时间】:2008-09-16 11:07:34
【问题描述】:

如何在 C# 中暂停整个进程(就像我单击暂停时进程资源管理器所做的那样)。

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

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    这是我的建议:

     [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); // throws exception if process does not exist
    
      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);
      }
    }
    

    【讨论】:

    • 我认为 pOpenThread.Equals(null) 永远不会返回 true。它应该是 pOpenThread == IntPtr.Zero IMO。其余的工作正常!谢谢!
    • 为什么要破解;并且不继续; ?
    • From MSDN: 当你使用完句柄后,一定要使用CloseHandle函数关闭它。
    • 如果出现错误,此代码将忽略它们并继续。这是相当危险的。它可以在没有任何警告的情况下半挂起进程,并且可能导致在测试期间未检测到错误。只是让你知道。
    • 另外,恢复循环意味着已经挂起的线程将被唤醒。这会扰乱目标进程的内部状态,并可能会破坏它。正确的方法是存储被挂起的 ID 列表并恢复它们一次。
    【解决方案2】:

    感谢马格努斯

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

    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

    【讨论】:

    【解决方案3】:

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

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

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

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

    在任何情况下,使用托管接口进行调试似乎比 p/invoke'ng 很多本机 API 调用要容易得多,这将在模拟您可能真正想做的事情方面做得很差......使用调试 api 的 ;)

    【讨论】:

      【解决方案4】:

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

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

      戴夫

      【讨论】:

        【解决方案5】:
        [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");
        

        【讨论】:

        • 添加更多细节并解释你的答案
        猜你喜欢
        • 2011-02-17
        • 2012-02-26
        • 2010-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-30
        相关资源
        最近更新 更多