
間接システムコールをクリーンにし、システムコール改ざんを行う。
SyscallRevenantは、クリーンな間接システムコールを実行する新しい手法です。
主要コンポーネントは、System Service Numbers(SSN)とsyscall命令のアドレスを動的に解決します。
これは、実行中にトラップフラグを有効にすることで行われます。
副次的なコンポーネントは、syscallの前のパラメータ置換による改ざんです。
この組み合わせは、後続のシステムコール呼び出し中にユーザーランドフックをバイパスしつつ、最初に提示されたパラメータを置き換えるように設計されています。
免責事項: これは教育およびテストのみを目的としています。 使用許可のないマシンでこれを使用しないでください。 使用権限のないマシンへの侵入や通信にこれを利用しないでください。
間接システムコールは、信頼されたユーザーランド空間でsyscall命令を実行する手法です。
ユーザーがsyscall命令を見つけた場合、間接的にそこへジャンプできます。
トレースセッション中に有効化されたイベントは、命令直後の戻りアドレスを明らかにできます。
これはEndpoint Detection & Response(EDR)のユーザーランドフックを考慮していません。
EDRはntdll.dllにフックを挿入する可能性があり、そのためSSNとsyscall命令の検索プロセスが無効化されます。
フックに入ることは、所有スレッドに利益をもたらし、悪意のあるスコアを上げることはありません。
関数への進入を観察することと、結果として生じる操作を観察することは別のものです。
RevenantSyscallsはそのギャップを調査します。
以下のセクションでは、プロジェクトの2つの主要コンポーネントの概要を説明します。
最初のコンポーネントは、プロセスによってロードされたntdll.dllから関数アドレスを解決します。
システムコール情報が必要な場合は、その後トラップウォークを実行できます。
2番目のコンポーネントは、保存された関数情報への間接ジャンプを実行します。
セグメントレジスタから読み取ることで、Process Environment Block(PEB)を取得できます。
LoaderDataはPEB内のフィールドで、各プロセスとともにロードされたデータを含みます。
LoaderDataには、各プロセスとともにロードされたモジュールに関する情報が含まれます。
モジュール名とベースアドレスはモジュールエントリ内に存在します。
Dynamically Linked Library(DLL)のエクスポート情報は、エクスポートするシンボルを記述します。 エクスポートメタデータは、エクスポートされたシンボルの特定をサポートします。 関数のインデックスは、名前と名前序数にのみ適用されます。 関数名のハッシュ化は、低メモリ環境に最適です。
ベクタード例外ハンドラは、プロセス内のどこからでも例外をキャッチする例外処理メカニズムです。
トラップフラグを有効にすると、次に実行される命令でEXCEPTION_SINGLE_STEP例外が発生します。
カスタムベクタード例外ハンドラはRIPを検査し、syscallをチェックできます。
トラップフラグを繰り返しリセットすることで、syscallアドレスが発見され、SSNが保存されます。
システムコール検索
|
システムコール実行
|
各システムコールには、最初のシステムコール情報の検索があります。 システムコール情報を取得するためにフックに入ります。 続いて、システムコールへの間接ジャンプが行われます。 (元のエントリからの)関連するRIPスプーフが存在します。 再エントリにより、初期パラメータは改ざんされています。
Event Tracing for Windows(ETW)の観点からは、発行される可能性のあるイベントはSysEnter、SysExit、およびいずれかのStackWalkです。
EDRが同様の、比較可能なイベントを構築する場合、これらはほぼ同一に見えます。
唯一の違いは、劇的に異なるQuery Performance Counter(QPC)タイムスタンプにあります。
src/AsmRevenant.asmを参照してください REAL_RTN: DQ 0
FAKE_RTN: DQ 0
; If a syscall information lookup is in progress, the
; initial entry return address needs to be preserved.
MOV RAX, QWORD PTR [RSP]
MOV QWORD PTR [FAKE_RTN], RAX
; Once the re-entry is made, the real return is saved,
; and the current is spoofed with initial return.
MOV RAX, QWORD PTR [RSP]
MOV QWORD PTR [REAL_RTN], RAX
MOV RAX, QWORD PTR [FAKE_RTN]
MOV QWORD PTR [RSP], RAX
src/Revenant.c を追跡するLONG VectoredExceptionHandler(EXCEPTION_POINTERS *BreakPoint) {
...
// If a syscall information lookup is being made, the
// syscall instruction address is saved, the SSN is
// saved, and the return is rerouted.
if (LookupInProgress && *(USHORT*)BreakPoint->Address == 0x050F) {
SyscallInstruction = BreakPoint->Address;
SyscallSSN = BreakPoint->Context->Rax;
BreakPoint->Context->Rip = SyscallExit;
}
// When re-entered, if the previous instruction was
// a syscall, reset return address, and exit.
if (!LookupInProgress && *(USHORT*)(BreakPoint->Address - 2) == 0x050F) {
*(VOID**)BreakPoint->Context->Rsp = REAL_RTN;
BreakPoint->Context->Rip = SyscallExit;
}
...
}