【发布时间】:2008-09-16 11:07:34
【问题描述】:
如何在 C# 中暂停整个进程(就像我单击暂停时进程资源管理器所做的那样)。
我正在使用 Process.Start 启动流程,并且在某个事件上,我想暂停该流程以便能够对其“快照”进行一些调查。
【问题讨论】:
如何在 C# 中暂停整个进程(就像我单击暂停时进程资源管理器所做的那样)。
我正在使用 Process.Start 启动流程,并且在某个事件上,我想暂停该流程以便能够对其“快照”进行一些调查。
【问题讨论】:
这是我的建议:
[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);
}
}
【讨论】:
CloseHandle函数关闭它。
感谢马格努斯
在包含标志之后,我稍微修改了代码,使其成为我项目中的扩展方法。我现在可以使用
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
【讨论】:
CloseHandle
所以说真的,其他答案显示的是暂停进程中的线程,没有办法真正暂停进程(即在一次调用中)......
另一种解决方案是实际调试您正在启动的目标进程,请参阅Mike Stall's blog 以获取有关如何从托管上下文实现此功能的一些建议。
如果您实现调试器,您将能够扫描内存或您想要的其他快照。
但是,我想指出,从技术上讲,现在有办法真正做到这一点。即使您对目标被调试进程进行调试,系统上的另一个进程也可能会注入一个线程,并且无论目标进程的状态如何,都将获得执行代码的能力(甚至假设它是否由于访问冲突而遇到断点) ),如果您将所有线程挂起到超高挂起计数,当前处于主进程线程中的断点以及任何其他此类假定冻结状态,则系统仍然可以将另一个线程注入该进程并执行一些指令。您还可以修改或替换所有入口点的kernel usually calls 等等,但您现在已经进入了 MALWARE 的粘性军备竞赛;)...
在任何情况下,使用托管接口进行调试似乎比 p/invoke'ng 很多本机 API 调用要容易得多,这将在模拟您可能真正想做的事情方面做得很差......使用调试 api 的 ;)
【讨论】:
有关 win32 基础知识,请参阅此 CodeProject 文章:http://www.codeproject.com/KB/threads/pausep.aspx。此示例代码使用 SDK 中的 ToolHelp32 库,因此我建议将此示例代码转换为具有简单接口的非托管 C++/CLI 库,例如“SuspendProcess(uint processID)。
Process.Start 将返回一个 Process 对象,您可以从中获取进程 ID,然后根据上述内容将其传递给您的新库。
戴夫
【讨论】:
[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");
【讨论】: