- ソウル旅行中に作った defendnot は、Windows Security Center(WSC)サービス API を直接呼び出して Windows Defender を無効化しようとするツールで、数日間にわたるリバースエンジニアリングへとつながった
- 以前のツール no-defender は、既存のアンチウイルスコードを使って WSC に別のアンチウイルスが存在すると登録する方式で、約 1.5k GitHub stars を獲得した後、アンチウイルス開発元の DMCA 要請で削除された
- 当初は WSC の COM API 呼び出しを約 1 時間で再現したが、WSC が呼び出しプロセスを検証していたため、通常のプロセスではアクセスが拒否された
- 分析の結果、WSC は WinDefend SID、管理者権限、署名、PE の
DllCharacteristics 内の ForceIntegrity フラグを確認しており、最終実装では Taskmgr.exe が使われた
- arm64 MacBook、米国のリモート PC、Parsec の 210ms 遅延、Shadow.tech VM まで絡む環境の中で、
ctx.bin のパスエラーと autorun の電源条件の問題を修正して実装を完了した
defendnot を作ることになった背景
- defendnot は、Windows Security Center サービス API を直接使って Windows Defender を無効化するツールである
- 実装過程の核心は WSC 呼び出しそのものよりも、それを防ぐ検証条件や不便な作業環境をひとつずつ回避していくことにあった
- より詳しい WSC の技術文書は後日別の人が公開する予定である
1 年前の no-defender と DMCA
- 約 1 年前に公開した no-defender は、Windows Defender を止めるためにアンチウイルス向けの Windows API を使っていた
- この API は、システムに「別のアンチウイルスがあるため、Defender のスキャンを実行する必要はない」と伝える用途だった
- この領域を管理しているシステムコンポーネントが Windows Security Center(WSC) である
- no-defender は既存アンチウイルスのサードパーティコードを利用し、そのアンチウイルスが WSC に登録されるよう強制する方式で動作していた
- 公開後数週間で約 1.5k stars を獲得し、使用されたアンチウイルス開発元が DMCA takedown 要請を提出すると、リポジトリの内容を削除して終わらせた
ソウル旅行中に再開した WSC 分析
- ソウルの Airbnb に滞在していたところ、MrBruh が no-defender を調べていて、アンチウイルスのバイナリなしで「クリーン」な実装が可能か調査しているとメッセージを送ってきた
- 普段は CTF や x86 リバース用途に別の x86 ノート PC を持っていくが、今回の旅行では M4Pro MacBook しか持っていなかった
- x86 リバース用の機材がない不利な条件でも、友人たちが起きる前の時間を使って WSC の分析を始めた
Day 1: WSC COM API の再現と最初のアクセス拒否
- MrBruh が最新の WSC バイナリを提供し、以前使っていたアンチウイルスの WSC 登録実装を参考実装とした
- WSC にはアンチウイルスが使う COM API があり、既存アンチウイルスが行っていた呼び出しを約 1 時間で再現した
- arm64 Windows を Parallels で起動してテストしたが、結果は access denied だった
- 以前の経験から WSC が API 呼び出し元プロセスを検証することは分かっており、最初は署名検証の可能性を疑った
- 既存アンチウイルスが WSC 作業に使っていたプロセスへコードを注入すると、新しいアンチウイルス登録と状態更新の COM 呼び出しは正常に動作した
アンチウイルスバイナリを排除しようとした試み
- 新しいプロジェクトが既存アンチウイルス企業から再び問題提起されないよう、アンチウイルスのバイナリではなくシステム提供バイナリを使おうとした
- 最初の対象プロセスとして
cmd.exe を選んだが、WSC API 呼び出しは拒否された
wscsvc.dll を調べると、呼び出し元プロセスが PPL かどうかを確認するコードがあった
- 単純に
CreateProcessA で作成したプロセスは PPL 保護プロセスではなく、その日の未明にはそれ以上進めなかった
Day 2: 不便なリモートデバッグ環境の構築
- arm64 MacBook では x86 Windows をまともに扱いづらく、arm64 環境で作業したり x64dbg を使えなかったりする状況を避けたかった
- 友人の pindos が PC へのアクセスを許可してくれ、Parsec でリモート接続した
- 韓国から米国にある PC へ接続していたため、平均遅延は約 210ms だった
- 当時の作業フローは非常に煩雑だった
- Parallels 上の Windows arm64 で MSVC によりモジュールをビルド
- 共有フォルダでビルド成果物をホストと共有
- AnyDesk で pindos の PC 上の VM に成果物をコピー
- Parsec で 210ms の遅延がある環境から WSC サービスをデバッグ
- 開発と分析の速度が大きく落ちるほど環境が不便だった
WSC サービスのデバッグと WinDefend SID
- WSC サービスは
svchost が実行する DLL であり、デバッガ接続を阻む主な要因は PPL 保護 だった
- VM でテストモードを有効にし、カーネルモードで数行のコードにより対象プロセスの PPL を外すドライバを使った
cmd.exe が WSC にアンチウイルス登録を要求した際に失敗する箇所は WscServiceUtils::CreateExternalBaseFromCaller だった
- この関数は RPC クライアントを装った後、呼び出し元プロセストークンに
WinDefend SID があるかどうかを確認していた
- 当時は Windows トークンの挙動をよく理解していなかったため、
WinDefend を装えば検査を通過できると判断した
- 睡眠不足の状態で、既存アンチウイルスのバイナリもこの
IsMember 検査を通過すると誤って解釈していた
WinDefend の偽装の試みと失敗
- Windows トークンを数時間学んだ後、WinDefend SID を含むトークンで実行すれば WSC の検査を通過できるという方向で実装した
cmd に WinDefend SID を付与した状態でコードを実行してみたが、COM 呼び出しが STATUS_SUCCESS を返しても実際には新しいアンチウイルス登録は行われなかった
- このアプローチは結果的に役に立たず、翌日に再検証する必要があった
Day 3: 実際の検証アルゴリズムの再構成
- 再確認すると、既存アンチウイルスのバイナリは WinDefend SID 検査 を通過していなかった
- その検査を通過すると Windows Defender の WSC オブジェクトを扱うことになるが、WSC 呼び出しだけで Defender を直接無効化することはできず、役に立たなかった
- WinDefend 偽装コードを削除し、条件分岐の別のブランチを分析した
- そのブランチでは、呼び出し元バイナリについて次の点を確認していた
- プロセスが elevated 状態か
- バイナリ署名が有効か
- PE の
DllCharacteristics に特定のフラグがあるか
CSecurityVerificationManager::CreateExternalBaseFromPESettings で確認していた DllCharacteristics フラグは ForceIntegrity だった
- WSC が行うバイナリ検査を再現したコードを defendnot リポジトリの
wsc-binary-check フォルダに作成し、System32 バイナリを対象にテストした
Taskmgr.exe の使用と ctx.bin バグ
- 友人が再び PC を使う必要が出たため、VM に直接 Parsec で接続したが、ソフトウェアエンコードまで重なって環境はさらに遅くなった
cmd.exe の代わりに Taskmgr.exe を使ったが、それでも RPC エラーが発生した
- 遅延と入力の問題で同じ VM 上でデバッグするのが難しくなり、勧められるまま shadow.tech の契約に $30 を支払った
- Shadow.tech の VM は Windows のバージョンがより古く、
wscsvc のコードが最新バージョンのように 1 つの関数へ大量にインライン化されておらず、逆コンパイル結果も読みやすかった
- 実際のエラー原因は、WSC に渡した AV 名が間違っていたこと だった
defendnot-loader から defendnot.dll へデータを渡すため、シリアライズ済みパラメータを格納した ctx.bin を使っていた
- 状態追跡用の IPC は別途実装していたが、設定の受け渡しには古い no-defender コードの名残である
ctx.bin 方式が残っていた
ctx.bin のパスを探す関数が nodefend.dll ではなく Taskmgr.exe モジュールのベースフォルダを基準にしていた
- その結果、ヌルバイトを AV 名として渡してしまい、WSC がそのバッファを拒否した
- パスの問題を修正した後、テストは成功した
コード整理と autorun の問題
- その日のうちに終わらせるため、午前 8 時までコード整理と追加機能の実装を進めた
- 追加機能には、自身を autorun に追加する機能が含まれていた
- 午前 8 時の時点では autorun だけが正しく動作せず、いくつもの方法を試して失敗した後に眠った
- 翌日あらためて確認すると、タスクスケジューラのタスク作成時にある電源関連のチェックボックス 2 つが原因だった
- ノート PC が AC 電源に接続されていなかったためタスクが実行されず、そのフラグを解除すると autorun は動作した
- その後さらに数時間コードを整理して作業を終えた
まとめ
- 作業そのものは楽しかったが、数日間繰り返した環境トラブルとリモートデバッグの流れは二度と経験したくないものだった
- 特に arm64 MacBook、リモート x86 VM、高遅延、遅いエンコード、そして後になって判明したファイルパスのバグが、実装の難易度を大きく高めていた
- より技術的な WSC 文書は今後別途公開される予定である
1件のコメント
Hacker News のコメント
Defender を無効化する方法の中で、最も侵襲的だが効果があったのは、ライブ Linux USB で起動して
C:\ProgramData\Microsoft\Windows Defenderをリネームし、その場所に空のファイルを作っておくやり方だった参考までに、WSC は Windows Security Center の略
the antivirus I was usingという表現のせいでかなり混乱した。そのウイルス対策ベンダーが、なぜ筆者に DMCA 削除要請を送る理由があるのか理解できなかったおそらく筆者が別のウイルス対策ソフトをリバースエンジニアリングして、その一部をオープンソースプロジェクトに入れたという意味なのだと思う。ただ
Impersonating WinDefendのようなタイトルも見えるので、結局のところ筆者が何らかの形で著作権法に違反したのかが気になる引用された段落のすぐ前に、「プロジェクトは既存のウイルス対策ソフトのサードパーティコードを使用し、そのウイルス対策ソフトが WSC にウイルス対策として登録されるよう強制した」と説明されている
このコードは呪われている感じがする:
https://github.com/es3n1n/defendnot/blob/master/defendnot-lo...
実際に何が起きているのか気になるならここ:
https://github.com/es3n1n/defendnot/blob/master/cxx-shared/s...
例えば D 言語には、スコープ終了時に実行される文(statement)の概念が言語に組み込まれている
要約すると、AI が書いたものではない。このコードは、オブジェクトがスコープを抜ける時点まで関数呼び出しを遅延させる。実装は C マクロで、必要な C ラムダ/匿名関数定義の一部を省略する短い構文を作り、遅延呼び出しを管理する一意な変数名を生成している
ただし、結果としての構文は、C マクロを示す一般的な慣例である大文字表記を避けており、一見するとオブジェクトポインタの関数呼び出しのように見える。このパターンに慣れていない人や、マクロは違う形で表示されるはずだと期待している人には混乱を招く可能性がある
人によっては十分に一般的で有用なため、特定の文脈ではほとんどイディオムのように見なせる。技術的な説明は https://news.ycombinator.com/item?id=43959403#43960905 がマクロの動作をうまく解説している
休暇中に Windows の仮想デスクトップをリバースエンジニアリングしたおかげで、休暇がずっと良いものになった。去年一番の思い出は、リバースエンジニアリングが本当に楽しいと感じたこと
興味深いこともたくさん学んだ。Windows の RPC の下には、文書化されていないメッセージング層がある: https://csandker.io/2022/05/24/Offensive-Windows-IPC-3-ALPC....
プロフィール画像がアニメキャラなら、その記事は良いものだと毎回分かる。あとでひどい Windows 環境に戻ることになったときのために保存しておく
気になる人のために: WSC は Windows Security Center の略。自分も調べる必要があった
なぜ WSC を無効化したいのだろう?
EDR ベンダーなら、これは Windows Firewall を抑制または無効化するために使える難読化された API 呼び出しだ。例えば CrowdStrike は Windows Firewall を使うことも、自前実装を使うこともどちらも可能だと思う
netcat.exeはダメだとベビーシッターのように干渉してくることなど気にしたくない最近 https://nostarch.com/windows-security-internals を読んだところで、この記事のおかげではるかに実感を持って理解できた
Windows でこうした裏側の動作が大まかにどう回っているのかは少し知っていたが、タイミングがよかった。その本の最終章も、この記事の筆者が扱っているようにトークンと SIDをかなり詳しく掘り下げている