
Rusty Hell's Gate / Halo's Gate / Tartarus' Gate / FreshyCalls / Syswhispers2 ライブラリ
このプロジェクトをMordorと名付けたのは、Hell's Gate / Halo's Gate / Tartarus' Gateがなぜか指輪物語のモルドールの黒門を思い出させるからです。笑 しかもプロジェクトにはかっこいい名前が必要ですから、そうしない手はないでしょう?
クレジット: Middle-earth: Shadow of War Wiki
フッキングとは、既存の関数への呼び出しを傍受したり、正規のAPIの実行フローをメモリ内の別の場所へリダイレクトしたりするために使われる手法です。このメモリ上の場所は、攻撃者、アンチウイルス (AV)、エンドポイント検知・対応 (EDR)、またはアンチチート (AC) によって制御されている可能性があります。
インラインフッキング: これにより、対象関数の先頭数バイト (アセンブリ命令) をジャンプ命令に置き換え、実行フローをメモリ内の別の場所へリダイレクトすることができます。
インポートアドレステーブルフッキング (IATフッキング): インポートアドレステーブルは、DLLや実行ファイルからインポートされた関数の関数ポインタのルックアップテーブルです。IATフッキングにより、インポートアドレステーブル内の関数アドレスを別のものに置き換え、プログラムの実行フローをリダイレクトすることができます。
クレジット: Kyle Mistele
Hell's Gateは、ntdll.dllモジュールからシステムコールスタブと呼ばれる一連のバイト列を検索してシステムコール番号を抽出し、専用のメモリテーブルに保存するプロセスインジェクション手法です。このテーブルはその後、システムAPIを直接呼び出すために使用されます。しかし、Hell's Gateの制限は、関数がフックされている場合、クリーンなntdll.dllモジュールへのアクセスが必要であるという点です。そうでなければ、必要なシステムコール番号を埋めることができず、最終的にネイティブAPI呼び出しを実行できません。この問題に対処するため、Halo's Gateと呼ばれる双子の姉妹が誕生しました。これは非常に単純な観察に基づくHell's Gateへのパッチにすぎません。
関数にフック (jmp <address>) が仕掛けられると、システムコール番号を動的に取得できなくなります。この問題に対処するため、隣接する関数のシステムコール番号を調べ、それに応じて計算を調整して目的のシステムコール番号を取得することができます。なぜなら、システムコールスタブ内のシステムコールIDは連続してインクリメントされているからです。
Hell's Gateは、次の順序でバイト列4c8bd1b8のみをチェックします。これはアセンブリでは次のように見えます:
mov r10, rcx
mov eax, <syscall>
Halo's GateはHell's Gateと同じことを行いますが、エクスポートの最初のバイトがe9(jmp)であるかどうかをチェックしてフックが仕掛けられているかどうかを確認する追加のチェックがあり、フックが仕掛けられている場合、Halo's Gateは隣接する関数を調べて計算を調整し、システムコール番号を取得します。これは、システムコールスタブ内のsyscall IDが互いに増分的に続いているためです。
しかし、すべてのEDRが同じ場所(関数の先頭)にフックを仕掛けるわけではありません。EDRがmov r10, rcx(4c8bd1)の直後にフックを仕掛けたらどうなるでしょうか?これにより私たちのコードは壊れてしまいます。
Tartarus' Gateは、Halo's Gateに4c8bd1e9というバイト列も順次検索する追加のチェックを加えることでこの問題を解決します。これはアセンブリでは次のようになります。
mov r10, rcx
jmp <address>
ただし、すべての関数がフックされている場合は、最初の関数を見つけて、呼び出しID 0から順にすべてのフックを1つずつ解除することができます。この手法はSEKTOR7でVeles' Reekと呼ばれています。
FreshyCalls手法は、Export Directory内でNtで始まる関数(Ntdllを除く)を検索し、アドレス順に並べ替えます。驚くべきことに、最も低いアドレスがシステムコール番号0であり、次のものがシステムコール番号1、2、3…となります。これはx64 dbgやWindbgでご自身で確認できます。
Syswhispers2も同じことを行いますが、ntdll.dllのエクスポートディレクトリ内でNt関数を検索する代わりに、Zwで始まる関数を検索します。驚くべきことに、Zw関数とNt関数は同じシステムコールスタブを指しており、同じシステムコール番号を持ちます。
ここで確認できます:
Zw関数とNt関数の違いは、Microsoftのこちらで説明されています:
「*WindowsネイティブオペレーティングシステムサービスAPIは、カーネルモードで実行される一連のルーチンとして実装されています。これらのルーチンは、NtまたはZwというプレフィックスで始まる名前を持っています。カーネルモードドライバーはこれらのルーチンを直接呼び出すことができます。ユーザーモードアプリケーションは、システムコールを使用してこれらのルーチンにアクセスできます。
いくつかの例外を除き、各ネイティブシステムサービスルーチンには、似た名前で異なるプレフィックスを持つ2つのわずかに異なるバージョンがあります。たとえば、NtCreateFileとZwCreateFileの呼び出しは同様の操作を実行し、実際には同じカーネルモードシステムルーチンによって処理されます。
ユーザーモードからのシステムコールの場合、ルーチンのNtバージョンとZwバージョンは同じように動作します。カーネルモードドライバーからの呼び出しの場合、ルーチンのNtバージョンとZwバージョンは、呼び出し元がルーチンに渡すパラメーター値をどのように処理するかが異なります。
カーネルモードドライバーは、ネイティブシステムサービスルーチンのZwバージョンを呼び出して、パラメーターが信頼されたカーネルモードのソースからのものであることをルーチンに通知します。この場合、ルーチンはパラメーターを最初に検証することなく安全に使用できると想定します。ただし、パラメーターがユーザーモードのソースまたはカーネルモードのソースのいずれかからのものである可能性がある場合、ドライバーは代わりにルーチンのNtバージョンを呼び出します。これは、呼び出しスレッドの履歴に基づいて、パラメーターがユーザーモードまたはカーネルモードのどちらで発生したかを判断します*」
Hell's Gate: ntdll.dllを解析してシステムコールスタブの開始位置(4c8bd1b8)を見つけ、システムコールIDを取得します。ただし、システムコールスタブがフックされている場合、コードは壊れてしまいます。
Halo's Gate: Hell's Gateと同じですが、最初のバイトがe9(jmp)であるかどうかをチェックしてフックが存在するかどうかを確認する追加のチェックを加えます。フックが存在する場合、Halo's Gateは隣接する関数を調べ始め、システムコールスタブ内のシステムコールIDが連続して増加するため、それに応じて計算を調整してシステムコール番号を取得します。
Tartarus' Gate: Halo's Gateと同じですが、アセンブリ命令mov r10, rcxの後の2行目でシステムコールスタブがフックされているかどうかを、次のバイトシーケンス4c8bd1e9を検索して確認する追加のチェックを加えます。
FreshyCalls: Export Directory内でNtで始まる関数を検索し、アドレス順に並べ替えます。最も低いアドレスがシステムコール識別子0です。
SysWhispers1: OSのバージョン情報を使用して、正しいシステムコール番号を選択します。
Syswhispers2: FreshyCallsと同じですが、Export Directory内でZw関数を検索し、ZwをNtに置き換えて名前を保存します。
SysWhispers3 これは SysWhispers2 と非常によく似ていますが、x86/WoW64 のサポート、EGG による syscalls 命令の置換(動的に置換される)、x86/x64 モードでの syscalls への直接ジャンプ(WOW64 ではほぼ標準)、ランダムな syscalls への直接ジャンプ(@ElephantSeal のアイデアを借用)もサポートしている点が異なります。
読者向けの演習: Alice Climent-Pommeret と Kelzvirus による優れたブログ
https://github.com/am0nsec/HellsGate - smelly__vx (@RtlMateusz) と Paul Laîné (@am0nsec)
https://vxug.fakedoma.in/papers/VXUG/Exclusive/HellsGate.pdf
https://blog.sektor7.net/#!res/2021/halosgate.md - @Reenz0h / @SEKTOR7net
https://github.com/trickster0/TartarusGate (trickster0 / @trickster012)
https://klezvirus.github.io/RedTeaming/AV_Evasion/NoSysWhisper/
https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams/ - @modexpblog
https://kylemistele.medium.com/a-beginners-guide-to-edr-evasion-b98cc076eb9a
https://alice.climent-pommeret.red/posts/direct-syscalls-hells-halos-syswhispers2/
https://github.com/crummie5/FreshyCalls - crummie5
https://github.com/jthuraisamy/SysWhispers - jthuraisamy
https://github.com/jthuraisamy/SysWhispers2 - jthuraisamy