新規作成コンテキストメニューを無効化する方法に副作用が出てしまっていました。具体的には30秒~数分ごとに↓のようにアイコンがちらついてしまうというものです。レジストリへ新規作成コンテキストメニュー用の設定値を書き込む。-show)と同等のキャッシュクリア処理を行う。いうような処理を行っていると思われるので、実際にどういう事が行われているのか調べてみることにしました。これは調査したいアプリケーションがどういうAPIを呼び出しているかをモニタリングできるツールです。Portable」をダウンロードし、「apimonitor-x64.exe」を起動します。Monitoring」をクリックします。Processes欄に先ほど選択したプロセスが表示されます。Filter欄に表示されているものすべてにチェックを入れます。Processes欄のプロセスをクリックするとSummary欄にAPIの呼び出しログが表示されます。後はプロセスを切り替えながらレジストリへアクセスしているプロセスを見つけ出します。Fキーを押すか、双眼鏡アイコンで検索ダイアログを呼び出し、「.gdoc\ShellNew」を検索します。すると上から2番目のプロセスが「RegOpenKeyExW」を呼び出して新規作成コンテキストメニューのレジストリにアクセスしていることがわかりました。)という感じでAPIを呼び出して読み書きしていることがわかりました。書き込み後に呼び出されているAPIを確認してみると、「SHChangeNotify」が呼び出されていることがわかりました。)このAPIを解説してくれているサイトによると、https://www.tokovalue.jp/function/SHChangeNotify.htm第二引数に指定されている「SHCNF_FLUSH」は「システムのイベントバッファをフラッシュ」するそうなので、おそらくこれでアイコンのキャッシュをクリアしているのだと思われます。これでGoogleドライブアプリがどういう動きをしているのかがわかりました。対策検討編どういう挙動なのかわかったら次は対策を考えなければいけません。思いついた事を挙げてみました。書いたように、新規作成コンテキストメニューのレジストリキーのアクセス許可を変更してレジストリをいじらせないようにする。⇒Googleドライブアプリがレジストリへの書き込みに失敗した場合でも「SHChangeNotify」APIを呼び出してアイコンをちらつかせてしまうため、デメリットがデカいです。WindowsにGoogleドライブ専用のユーザーを作成し、Googleドライブアプリをそのユーザーで起動させる。案1の方法を行いログインユーザーがGoogleドライブ関連の新規作成コンテキストメニューのレジストリへアクセスできないようにする。するとGoogleドライブは新規作成コンテキストメニューのレジストリへ読み書きが失敗することなく行え、ログインユーザーはGoogleドライブ関連のレジストリキーを読めない状態になるので、アイコンのちらつきが起こらず、新規作成コンテキストメニューからGoogleドライブ関連のメニューが消えた状態となる。⇒別ユーザーでの起動はrunasコマンドを使うか、タスクスケジューラを使えば行えそうです。別ユーザーで起動してしまうとおそらく別ユーザーのユーザーフォルダ配下にあるマイドライブフォルダ(C:\Users\{別ユーザー}\マイドライブ)にファイルを同期してしまうのではないかと思うので、そのフォルダのアクセス許可の設定でログインユーザーが読み書きできるようにし、さらにジャンクションを作って「別ユーザーのユーザーフォルダ配下にあるマイドライブフォルダ」たどり着けるようにすれば実現できるかもしれません。Googleドライブ同期専用のパソコンを別途用意し、「マイドライブ」フォルダを共有フォルダにして別のパソコンからアクセスできるようにする。メインで使用するパソコンから↑の共有フォルダにアクセスしてファイルの閲覧・編集を行う。⇒別のパソコンを起動させないといけないため、かなりもったいないです。共有フォルダ経由で読み書きした場合に何か変な動きをしないか心配です。Googleドライブアプリを使うのを止め、自分でGoogleドライブ上のファイルをローカルに持ってくる同期アプリを作る。⇒定期的にGoogleドライブ上の全ファイルをローカルにコピーバッチ処理であれば頑張ればできなくもなさそうですが、ちょっとしんどいですね。Googleドライブのバイナリを改変し、新規作成コンテキストメニューのレジストリへの書き込み処理を動かなくさせる。⇒一番確実な方法ではありますが、Googleドライブアプリがアップデートされるたびにパッチをあてないといけなくなるので、これも少々しんどいですね。Googleドライブアプリがアイコンキャッシュクリアのために行う「SHChangeNotify」APIの呼び出しを何かしらの方法で妨害し、Windows側まで到達できないようにさせる。今度はGoogleドライブ絡みのオーバーレイアイコンがうまく表示されなくなる副作用が出てしまいそうですね。オーバーレイアイコンが表示されなくても個人的にはそこまで困らないので、個人的には許容範囲の副作用です。「SHChangeNotify」API本体を改変し、第二引数でSHCNF_FLUSHを受け取っても無視するようにする。⇒Windows全体に影響が及ぶのでデメリットがすごそうですね。「~\ShellNew\command」に書き込ませないようにする。平和に終わりそうな予感です。レジストリの読み書きをするAPI本体を改変し、GoogleDrive絡みの「~\ShellNew\command」へ書き込ませないようにする。⇒API本体を書き換えるのはちょっとアレですね。Googleドライブ側でレジストリへの書き込みができない場合は「SHChangeNotify」APIを呼び出さないようにアップデートしてもらう。⇒ダメ元で10月頭(v51.0.14.0)にフィードバックを出してみましたが、現時点(v52.0.6.0)で変化はありませんでした。思いつく限り挙げるとこんなものです。調べていくと「DLLインジェクション」(IATフック)という手法があり、これを使うとAPI呼び出しをHOOKして任意の処理に置き換えることができることがわかりました。モンキーパッチやクラスメソッドのオーバーライドと同じような感じですね。面白そうな手法なので案8のパターンで進めることにしました。DLLインジェクション(IATフック)計画編GoogleドライブとAPI、レジストリは以下のような関係性になっています。※IATの部分はもしかしたら解釈間違ってるかもしれませんが、今回やりたいことはうまく表現できてるかと思います。以下のような流れにしてしまおうと思います。DLLインジェクションを行うためには・DLLをインジェクション(注入)するためのexe・インジェクションされるDLLの2個を作る必要があります。DLLインジェクションを行うのはメモリ上だけなのでバイナリを改変する必要がなく、DLLインジェクションを行ってしまえばDLLインジェクションするためのexeは常駐する必要がありません。メモリ上でしかできないので、アプリを再起動した場合は再度DLLインジェクションを実行する必要があります。便利であるがゆえにそれを悪用したウイルスがあるらしく、DLLインジェクションを行うexeがウイルス対策ソフトに誤検知されてしまうことがあります。Defenderにウイルス判定を食らうことがありました。スキャンをかけてみてもウイルス判定されることはありませんでしたが、悪意のないコードでも「アヤシイ」と判断されやすい手法なようです。計画を立てるところまでは割とスムーズにいったんですが、実際にやってみるとなかなか難航しました。完成したものがこちらです。名前は「disable_google_drive_new_contextmenu」ですが、exeとdllの2個が必要なため別々にプロジェクトを作ってあります。2019にてC言語で開発しました。こちら側でビルドしたexeとdllのセットはhttps://github.com/forest-soft/disable_google_drive_new_contextmenu_injector/releases/の「disable_google_drive_new_contextmenu.zip」からダウンロードできます。ソースからビルドするか上記からzipをダウンロードするとフォルダ内に以下の2ファイルがある状態になります。Googleドライブアプリを起動した後に「injector.exe」をダブルクリックすると一瞬このようなコマンドプロンプトが表示されます。ちなみにもしもGoogleドライブアプリが起動されていない状態で「injector.exe」を実行するとこのようにGoogleドライブアプリが立ち上がるまで待機状態になります。成功すればコンピューター\HKEY_CLASSES_ROOT\.gdoc\ShellNewコンピューター\HKEY_CLASSES_ROOT\.gsheet\ShellNewコンピューター\HKEY_CLASSES_ROOT\.gslides\ShellNewのレジストリキーの配下から「command」が消え、「command_xxx」に置き換わります。新規作成コンテキストメニューからGoogleDrive関連のメニューが消えるハズです!肝心のちらつき問題ですが、しっかり解消できています。レジストリのアクセス許可を変更した場合です。ファイルがたくさんあった方が確認しやすかったので「C:\Windows\Cursors」にて確認しました。Googleドライブアプリの起動直後かどうかによって周期が変化するみたいですが、確認したときは5分周期でアイコンキャッシュがクリアされ、ちらつきがおこってました。次は「disable_google_drive_new_contextmenu」の完成直後(v52.0.6.0)です。この時は1分周期でアイコンキャッシュがクリアされ、ちらつきが起こっていました。↑の後に「disable_google_drive_new_contextmenu」の「injector.exe」を起動した場合です。静止画だとどうにも確認しようが無かったりはしますが、5分経ってもちらつきが起こりません!そして3日ほど使ってみましたが、ちらつきは起こっていません!ちょっと特殊なことをしなければいけませんでしたが、これでバッチリ満足いく状態になりました!ただ、DLLインジェクションの性質上Googleドライブアプリを再起動するとDLLインジェクションが無効になってしまいます。いう事はWindowsを再起動するたびに「injector.exe」を起動する必要があるわけです。スケジューラを使って自動的に「injector.exe」を立ち上げるようにしたいと思います。Rキーで「ファイル名を指定して実行」を表示し、「taskschd.msc」と入力してください。画面右側の「タスクの作成」をクリックしてください。タスクの作成ダイアログが表示されるので、わかりやすい名前を入力してください。「トリガー」タブをクリックし、「新規」ボタンをクリックしてください。「タスクの開始」項目で「ログオン時」を選び、「OK」ボタンをクリックしてください。「操作」タブをクリックし、「新規」ボタンをクリックしてください。「参照」ボタンをクリックし、「disable_google_drive_new_contextmenu」の「injector.exe」を選択してください。「引数の追加」項目に「--hide」と入力してください。この引数を指定すると「injector.exe」を起動したときにコマンドプロンプトが表示されなくなります。その後「OK」ボタンをクリックしてください。「OK」ボタンをクリックしてください。これでWindowsの起動時に「injector.exe」を自動で実行するタスクが作れました。Windowsを再起動せずに動作確認をしたい場合は画面右側の「実行」ボタンを押すとその場で試せます。ちなみに先ほどの「操作」タブのところで引数に「--hide」と入れてもらいましたが、この状態でGoogleドライブアプリが起動してない時に「実行」すると、裏でinjector.exeがGoogleドライブの起動待ち状態になってしまい、待機し続けてしまいます。終了させる場合は1回Googleドライブアプリを立ち上げるか、タスクマネージャーの詳細タブから「injector.exe」を探して「タスクの終了」で終了させてください。「disable_google_drive_new_contextmenu」のフォルダごと削除し、タスクスケジューラに登録したタスクを消せばアンインストール完了です。Googleドライブアプリが起動している間はGoogleドライブアプリが「disable_google_drive_new_contextmenu.dll」を開き続けてしまうので、ファイルの削除が行えません。Googleドライブアプリを終了させてからフォルダごと消してください。レジストリキーが気になる場合はコンピューター\HKEY_CLASSES_ROOT\.gdoc\ShellNewコンピューター\HKEY_CLASSES_ROOT\.gsheet\ShellNewコンピューター\HKEY_CLASSES_ROOT\.gslides\ShellNewの配下にある「command_xxx」を消してもらえれば痕跡残さず完全アンインストール完了です。これにて新規作成コンテキストメニューの無効化対策完了です!後々DLLインジェクションのプログラムのメモ記事を書いていこうと思います。Windows書いた人:木本コメント一覧コメントはまだありません。Reserved.Top。