ti-enxame.com

Suspender Processo em C #

Como faço para suspender um processo inteiro (como o Process Explorer faz quando clico em Suspender) em C #.

Estou iniciando o Processo com Process.Start e, em um determinado evento, desejo suspender o processo para poder fazer alguma investigação em um "instantâneo" dele.

27
Thomas Danecker

Aqui está minha sugestão:

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

Graças a magnus

Depois de incluir os sinalizadores, modifiquei um pouco o código para ser um método de extensão em meu projeto. Agora eu poderia usar

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

Aqui está o código para quem possa estar interessado.

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

Eu tenho um utilitário que uso para geralmente suspender/matar/listar um processo. A fonte completa é no Git

12
Sarath

Uma solução detalhada usando Win32 p/invoke, pode ser encontrada em CodeProject .

3
Silver Dragon

Então, realmente, o que as outras respostas estão mostrando é a suspensão do thread no processo, não há como realmente suspender o processo (ou seja, em uma chamada) ....

Uma solução um pouco diferente seria depurar realmente o processo de destino que você está iniciando, consulte blog de Mike Stall para obter alguns conselhos sobre como implementar isso a partir de um contexto gerenciado.

Se você implementar um depurador, poderá varrer a memória ou qualquer outro instantâneo que desejar.

No entanto, gostaria de salientar que, tecnicamente, agora há uma maneira de realmente fazer isso. Mesmo se você fizer o debugbreak de um processo de depuração de destino, outro processo em seu sistema pode injetar um thread e terá alguma capacidade de executar o código, independentemente do estado do processo de destino (mesmo digamos que atingiu um ponto de interrupção devido a uma violação de acesso ), se você tiver todos os encadeamentos suspensos até uma contagem de suspensão superalta, estiver atualmente em um ponto de interrupção no encadeamento do processo principal e qualquer outro status presumido congelado, ainda é possível para o sistema injetar outro encadeamento nesse processo e execute algumas instruções. Você também pode ter o trabalho de modificar ou substituir todos os pontos de entrada do o kernel geralmente chama e assim por diante, mas agora você entrou na corrida viscosa de MALWARE;) ...

Em qualquer caso, usar as interfaces gerenciadas para depuração parece 'bem mais fácil do que p/invocar muitas chamadas de API nativas, o que fará um trabalho pobre de emular o que você provavelmente realmente deseja fazer ... usando a API de depuração ;)

2
RandomNickName42

Consulte este artigo CodeProject para os fundamentos do win32: http://www.codeproject.com/KB/threads/pausep.aspx . Este código de amostra usa a biblioteca ToolHelp32 do SDK, então eu recomendo transformar este código de amostra em uma biblioteca C++/CLI não gerenciada com uma interface simples como "SuspendProcess (uint processID).

Process.Start retornará a você um objeto Process, do qual você pode obter o id do processo e, em seguida, passá-lo para sua nova biblioteca com base no acima.

Dave

1
Dave Moore