在 C# 中暂停进程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/71257/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 11:08:38  来源:igfitidea点击:

Suspend Process in C#

提问by Thomas Danecker

How do I suspend a whole process (like the Process Explorer does when I click Suspend) in C#.

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

I'm starting the Process with Process.Start, and on a certain event, I want to suspend the process to be able to do some investigation on a "snapshot" of it.

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

采纳答案by Magnus Johansson

Here's my suggestion:

这是我的建议:

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

回答by Dave Moore

See this CodeProject article for the win32 basics : http://www.codeproject.com/KB/threads/pausep.aspx. This sample code makes use of the ToolHelp32 library from the SDK, so I would recommend turning this sample code into an unmanaged C++/CLI library with a simple interface like "SuspendProcess(uint processID).

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

Process.Start will return you a Process object, from which you can get the process id, and then pass this to your new library based on the above.

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

Dave

戴夫

回答by RandomNickName42

So really, what the other answer's are showing is suspending thread's in the process, there is no way to really suspend the process (i.e. in one call)....

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

A bit of a different solution would be to actually debug the target process which you are starting, see Mike Stall's blogfor some advice how to implement this from a managed context.

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

If you implement a debugger, you will be able to scan memory or what other snap-shotting you would like.

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

However, I would like to point out, that technically, there is now way to really do this. Even if you do debugbreak a target debuggee process, another process on your system may inject a thread and will be given some ability to execute code regardless of the state of the target process (even let's say if it's hit a breakpoint due to an access violation), if you have all thread's suspended up to a super high suspend count, are currently at a break point in the main process thread and any other such presumed-frozen status, it is still possible for the system to inject another thread into that process and execute some instructions. You could also go through the trouble of modifying or replacing all of the entry point's the kernel usually callsand so on, but you've now entered the viscous arm's race of MALWARE ;)...

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

In any case, using the managed interfaces for debugging seems' a fair amount easier than p/invoke'ng a lot of native API call's which will do a poor job of emulating what you probably really want to be doing... using debug api's ;)

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

回答by Sarath

Thanks to Magnus

感谢马格努斯

After including the Flags, I modified the code a bit to be an extension method in my project. I could now use

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

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

Here is the code for those who might be interested.

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

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

I have a utility done which I use to generally suspend/kill/list a process. Full source is on Git

我完成了一个实用程序,我通常用它来挂起/杀死/列出一个进程。完整的源代码在 Git 上

回答by gerrard

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