1. ホーム
  2. windows

[解決済み] Windowsでアプリケーションにctrl-C(SIGINT)を送ることはできますか?

2022-12-10 10:12:19

質問

私は (過去に) クロスプラットフォーム (Windows/Unix) のアプリケーションを書いたことがありますが、それはコマンドラインから起動したときに、ユーザが入力した Ctrl - C の組み合わせで、同じように(つまり、アプリケーションをきれいに終了させるために)実行することができます。

Windows で Ctrl - C /SIGINT/他の(無関係な)プロセスから、プロセスをきれいに終了するように要求する(リソースを整理する機会を与えるなど)ことに相当するのでしょうか?

どのように解決するのですか?

解決策に最も近いのは SendSignal サード パーティ製アプリです。 作者はソース コードと実行ファイルをリストアップしています。 64 ビット Windows で動作することは確認しましたが (32 ビット プログラムとして実行し、別の 32 ビット プログラムを殺す)、Windows プログラム (32 ビットまたは 64 ビットのいずれか) にコードを埋め込む方法は分かっていません。

どのように動作するか。

デバッガでいろいろ調べた結果、ctrl-break のようなシグナルに関連する動作を実際に行うエントリ ポイントは kernel32!CtrlRoutine であることを発見しました。この関数は ThreadProc と同じプロトタイプを持っていたので、コードを注入することなく CreateRemoteThread で直接使用することができます。しかし、これはエクスポートされたシンボルではありません! Windowsのバージョンによって、アドレスが違う(名前も違う)のです。どうしたらいいでしょうか?

私が最終的に思いついた解決策は次のとおりです。私のアプリにコンソール ctrl ハンドラーをインストールし、私のアプリに ctrl-ブレーク シグナルを生成します。ハンドラーが呼び出されたとき、スタックの先頭を振り返り、kernel32!BaseThreadStart に渡されたパラメータを見つけます。最初のパラメータはスレッドの開始アドレスで、これはkernel32!CtrlRoutineのアドレスです。そして、シグナルを処理したことを示すハンドラから戻り、私のアプリを終了させないようにしました。メインスレッドに戻り、kernel32!CtrlRoutineのアドレスが取得されるまで待ちます。このアドレスが見つかったら、ターゲット・プロセスでリモート・スレッドを作成し、その開始アドレスを取得する。これにより、ターゲット プロセスの ctrl ハンドラは、ctrl-break が押されたかのように評価されるようになります!

良い点は、ターゲット プロセスのみが影響を受け、任意のプロセス (ウィンドウ プロセスでさえ) をターゲットにできることです。1 つの欠点は、私の小さなアプリはバッチ ファイルで使用できないことです。なぜなら、kernel32!CtrlRoutine のアドレスを発見するために ctrl-key イベントを送信すると、バッチ ファイルが停止してしまうからです。

(その前に start を付けてください。)