¿Cómo puedo suspender un proceso completo (como lo hace el Explorador de procesos cuando hago clic en Suspender) en C #.
Estoy comenzando el proceso con Process.Start, y en un evento determinado, quiero suspender el proceso para poder investigar un poco sobre una "instantánea" del mismo.
Aquí está mi sugerencia:
[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);
}
}
Gracias a Magnus
Después de incluir las Banderas, modifiqué un poco el código para que fuera un método de extensión en mi proyecto. Ahora podría usar
var process = Process.GetProcessById(param.PId);
process.Suspend();
Aquí está el código para aquellos que puedan estar interesados.
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);
}
}
}
Tengo una utilidad que utilizo generalmente para suspender/eliminar/enumerar un proceso. La fuente completa es en Git
Puede encontrar una solución detallada con Win32 p/invoke en CodeProject .
Entonces, realmente, lo que muestran las otras respuestas es suspender hilos en el proceso, no hay forma de suspender realmente el proceso (es decir, en una llamada) ...
Una solución un poco diferente sería depurar el proceso de destino que está comenzando, consulte blog de Mike Stall para obtener algunos consejos sobre cómo implementar esto desde un contexto administrado.
Si implementa un depurador, podrá escanear la memoria o cualquier otra instantánea que desee.
Sin embargo, me gustaría señalar que, técnicamente, ahora hay una manera de hacer esto realmente. Incluso si depura un proceso de depuración objetivo, otro proceso en su sistema puede inyectar un hilo y se le dará cierta capacidad para ejecutar código independientemente del estado del proceso objetivo (incluso digamos si ha alcanzado un punto de interrupción debido a una violación de acceso ), si tiene todos los subprocesos suspendidos hasta un recuento de suspensión súper alto, se encuentra actualmente en un punto de interrupción en el subproceso principal del proceso y en cualquier otro estado presumiblemente congelado, aún es posible que el sistema inyecte otro subproceso en ese proceso y ejecutar algunas instrucciones También podría pasar por la molestia de modificar o reemplazar todos los puntos de entrada: el núcleo generalmente llama y así sucesivamente, pero ahora ha entrado en la carrera de armas viscosas de MALWARE;) ...
En cualquier caso, usar las interfaces administradas para la depuración parece 'bastante más fácil que invocar muchas llamadas API nativas, lo que hará un mal trabajo al emular lo que probablemente quieras hacer ... usar la API de depuración ;)
Consulte este artículo de CodeProject para obtener información básica sobre win32: http://www.codeproject.com/KB/threads/pausep.aspx . Este código de muestra utiliza la biblioteca ToolHelp32 del SDK, por lo que recomendaría convertir este código de muestra en una biblioteca C++/CLI no administrada con una interfaz simple como "SuspendProcess (uint processID).
Process.Start le devolverá un objeto Process, desde el cual puede obtener la identificación del proceso, y luego pasarlo a su nueva biblioteca según lo anterior.
Dave