👏

UAC昇格画面などのWinLogonデスクトップの画面をキャプチャする(C#)

2023/06/16に公開

WindowsでUACなどの画面をキャプチャするために仕様から調べ始めてかなり苦労したのでまとめておこうと思います。

経緯

リモートデスクトップのソフトを開発していた際に、通常の方法でWindows ServiceからUAC昇格画面や最初のサインインの画面をキャプチャしようとしても真っ黒な画面になってしまうという問題が発生し、調べてもなかなか的確な解決策が見つからなかったのですが、Ultra VNCやTeamviewer、RustDeckなどキャプチャできてるソフトが多々あり、技術的には可能であると考え調べ続けていました。

なぜキャプチャすることができないのか

Windowsにはセッションというものがあり、Serviceなどはセキュリティの観点からUIから分離されたセッション0に割り当てされています。
我々が使用しているデスクトップはセッション1以降にあり、これがServiceからキャプチャすることができない理由となります。
また、通常のプロセスでもキャプチャできない理由として、Windows(正確にはWindow Station)は内部で複数のデスクトップを扱っており、普段使用しているデスクトップはDefaultという名前のものになっています。UACやCtrl+Alt+Delの画面、サインインのパスワードを入力する画面はWinLogonという名前のデスクトップに切り替わっています。
表示されていないデスクトップは描画されないため、キャプチャしようとしても真っ黒な画面になるわけです。
詳しい解説はこの記事をご覧ください、わかりやすい図もあり非常に参考になります。
https://www.mbsd.jp/blog/20180914.html

どのようにキャプチャすればよいのか

要するに、キャプチャをするプロセスをセッション1以降かつWinlogonに切り替えれる権限(SYSTEMユーザー)の条件があれば良いわけです。
まず、SYSTEMユーザーでプロセスを起動する方法ですが、これはSYSTEMユーザーで実行されているServiceからプロセスを起動させることで実現できます。
また、CreateProcessAsUserをというWindows APIを使うことでセッション1以降でプロセスを起動することができます。
つまり、ServiceからCreateProcessAsUserを使って該当プロセスを呼び、そのプロセスでOpenDesktopを用いて表示中のデスクトップに切り替え、通常通り好きなキャプチャ方法を用いてキャプチャ画像を取得できます。
ちなみに、ここではWindow Stationについてほとんど触れませんでしたが、デスクトップを切り替える上で重要な仕様のひとつなので、調べておいた方がいいかもしれません。

実装したコードは今は公開できないのですが、一通りまとめたら載せておきます。









Discussion