web-dev-qa-db-ja.com

C#でプロセスを一時停止します

C#でプロセス全体を一時停止するにはどうすればよいですか([一時停止]をクリックしたときにProcess Explorerが行うように)。

Process.Startを使用してプロセスを開始していますが、特定のイベントで、プロセスを一時停止して、その「スナップショット」を調査できるようにします。

27
Thomas Danecker

これが私の提案です:

 [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

マグナスに感謝します

フラグを含めた後、プロジェクトの拡張メソッドになるようにコードを少し変更しました。私は今使うことができました

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

私は、一般的にプロセスを一時停止/キル/リストするために使用するユーティリティを実行しました。完全なソースは Git上

12
Sarath

Win32 p/invokeを使用した詳細なソリューションは、 CodeProject にあります。

3
Silver Dragon

つまり、実際には、他の回答が示しているのは、プロセス内のスレッドを一時停止していることです。プロセスを実際に一時停止する方法はありません(つまり、1回の呼び出しで)。

少し異なる解決策は、開始しているターゲットプロセスを実際にデバッグすることです。管理されたコンテキストからこれを実装する方法については、 Mike Stallのブログ を参照してください。

デバッガーを実装すると、メモリやその他のスナップショットをスキャンできるようになります。

ただし、技術的には、これを実際に行う方法があることを指摘したいと思います。ターゲットdebuggeeプロセスをdebugbreakした場合でも、システム上の別のプロセスがスレッドを挿入し、ターゲットプロセスの状態に関係なく、コードを実行する機能が与えられます(たとえば、アクセス違反が原因でブレークポイントに達した場合でも) )、すべてのスレッドが非常に高いサスペンドカウントまでサスペンドされていて、現在メインプロセススレッドのブレークポイントにあり、他のそのような推定凍結ステータスにある場合でも、システムがそのプロセスに別のスレッドを挿入する可能性がありますいくつかの命令を実行します。また、すべてのエントリポイントの カーネルは通常呼び出す などを変更または置換するという問題を経験することもできますが、これで粘性のある軍拡競争のマルウェアに参加しました;)...

いずれにせよ、デバッグにマネージドインターフェイスを使用することは、多くのネイティブAPI呼び出しを呼び出して呼び出すよりもかなり簡単なようです。これは、おそらく本当にやりたいことをエミュレートするのに不十分です...デバッグAPIを使用する;)

2

Win32の基本については、このCodeProjectの記事を参照してください: http://www.codeproject.com/KB/threads/pausep.aspx 。このサンプルコードはSDKのToolHelp32ライブラリを利用しているため、このサンプルコードを「SuspendProcess(uintprocessID)」のような単純なインターフェイスを備えたアンマネージC++/CLIライブラリに変換することをお勧めします。

Process.Startは、プロセスIDを取得できるProcessオブジェクトを返し、これを上記に基づいて新しいライブラリに渡します。

デイブ

1
Dave Moore