
Time Travel Debugging トレースに対して YARA ルールを使用する
Time Travel Debugging のトレースに YARA ルールを使用します
calc.exe を起動する単純なバイナリで、UPX でパックされています。
yara-ttd はスレッド作成中に、モジュールメモリ内の calc.exe 文字列を見つけ出します。
calc.exe を実行する単純な難読化シェルコードテスト対象のバイナリはシェルコードを復号し、新しいスレッドで実行します。
yara-ttd は ntdll!NtCreateThreadEx 関数にフックすると、ヒープ上の calc.exe 文字列を見つけ出すことに成功します。
YARA はバイナリ向けの強力なパターンマッチングツールです。
YARA は、マルウェア研究者がマルウェアサンプルを識別・分類することを支援することを目的とした(ただしそれに限定されない)ツールです。YARA を使えば、テキストパターンやバイナリパターンに基づいて、マルウェアファミリー(または説明したい任意のもの)の記述を作成できます。
-- YARA ドキュメント
YARA のおかげで、分析前にパイプラインでマルウェアサンプルを自動分類することで、多くの時間を節約できます。
残念ながら、ほとんどのマルウェアサンプルはさまざまな種類のパッカーで保護されています。UPX や VMProtect のような古典的なランタイムパッカーの仕組みは、難読化され、場合によっては暗号化されたコードを自己展開して実行するものです。 そのため、YARA はパックされたコード内でマッチを見つけられず、パックされたバイナリを処理できません。
Time Travel Debugging(略して TTD)は、Windows 標準のデバッガーである WinDbg の機能です。
Time Travel Debugging は、プロセスの実行中のトレースをキャプチャし、後で前後にリプレイできるツールです。Time Travel Debugging (TTD) は、デバッガーセッションを「巻き戻す」ことを可能にすることで、バグを見つけるまで問題を再現し続ける代わりに、問題のデバッグを容易にします。
マルウェア分析において、TTD はサンドボックス内でマルウェアのトレースを記録できるため、強力なツールです。したがって、記録したファイルをサンドボックスの外で安全にリプレイして共有し、マルウェアを分析することができます。
また、TTD はデバッガーではないため、PEB.BeingDebugged のような古典的なアンチデバッグ技術によって検出されることはありません。
セキュリティの観点から TTD をより深く分析するには、こちらの記事を参照してください: TTD エコシステムの詳細な分析
もちろん、TTD はプロプライエタリソフトウェアであり、この成果は commial が開発した ttd-bindings なしには存在し得ません。
yara-ttd の背後にあるアイデアは、TTD で記録したトレースファイルを yara 自体で使用し、パッカーを打ち負かすことです。
yara はパックされたバイナリ自体をスキャンできないため、yara-ttd はアンパック処理を含むすべてのランタイム情報を含むトレースファイルを分析する方法を提供します。
yara-ttd を使うと、トレースファイル内の一連の位置を選択し、その位置で yara ルールを使ってメモリをスキャンできます。
つまり、パックされたバイナリのどこにでも、yara ルールでフックできるのです!
yara-ttd は、モジュールがロードされたときや仮想メモリが割り当てられたときなど、アンパック後にマルウェアコードを格納するためによく使われる複数のメモリスキャン戦略を提供します。
現時点では、yara-ttd は TTD API とやり取りする必要があるため、Windows のみをサポートしています。
まずプロジェクトをビルドします:
mkdir build
cd build
cmake ..
cmake --build .
次に、TTDReplay.dll と TTDReplayCPU.dll ファイルを実行可能ファイルと同じディレクトリに配置します。
これらの DLL ファイルは %LocalAppData%\Microsoft\WindowsApps\Microsoft.WinDbg_X\TTD にあります。
まず、プログラムのトレース (.run ファイル) を記録する必要があります。
TTD トレースの記録方法の詳細については、このチュートリアル を参照してください。
その後、次のように実行します:
.\yara-ttd path\to\rule path\to\trace\file
メモリをスキャンするモードは 3 つあります:
-m でモードを選択できます:
.\yara-ttd -m 1 path\to\rule path\to\trace\file
公式の yara CLI と同様に、-s フラグを使用すると、メモリアドレスや一致した正確なサブルールなど、マッチの詳細を表示できます。
TTD はメモリ構造を保存しないため、yara-ttd はスキャン前に各タイムポジションのヒープアドレス構造を計算します。
ヒープ構造を保存するために、トレースファイルと同じパスに .tmp 拡張子のキャッシュファイルを作成します。
トレース上で yara-ttd を再実行し、生成されたキャッシュファイルからヒープ構造を読み込みたい場合は、次のようにするだけです:
.\yara-ttd -m 1 --cache=path\to\cache\file path\to\rule path\to\trace\file
TTD を使用すると、プロセスの全メモリ範囲(GetSystemInfo が返す最小アドレスと最大アドレスに相当)にアクセスできます。それでも、ほとんどの場合、この範囲は大きすぎて、最適化なしではスキャンできません。
スキャンされるデフォルトのタイムポジションは次のとおりです:
-t フラグと -f フラグを使用すると、スキャンする他のポジションや関数呼び出しを選択できます:
.\yara-ttd -m 1 -t 3C1:A -t 5FF:22 -f ntdll!FreeVirtualMemory -f ntdll!NtCreateThreadEx path\to\rule path\to\trace\file
-t フラグは、major:minor 形式の TTD ポジションを期待します (両方とも 16 進数で、0x は付けません)。
-f フラグは、module_name!function_name 形式の文字列を期待します。
フックしたいすべての関数をファイルに追加することもできます:
> cat .\functions.txt
ntdll!FreeVirtualMemory
ntdll!NtCreateThreadEx
> .\yara-ttd -m 1 -F functions.txt path\to\rule path\to\trace\file
yara-ttd でスキャンするファイルが複数ある場合は、ディレクトリ全体をスキャンすることもできます。
yara-ttd はフォルダ内の次の拡張子をすべて無視します:
.tmp (yara-ttd によって生成されるキャッシュファイル).idx (ttd によって生成されるインデックスファイル).err (ttd によって生成されるエラーファイル).out (ttd によって生成されるログファイル)次の例では、yara-ttd は trace01.run と trace02.run ファイルのみをスキャンします。
> dir .\traces
trace01.run
trace01.out
trace01.idx
trace02.run
trace01.run.err
trace01.tmp
> .\yara-ttd path\to\rule .\traces
あるいは、スキャンしたいすべてのトレースをファイルに指定し、--scan-list または -l フラグを使用することもできます。1 行に 1 ファイルずつリストされたファイルをスキャンします:
> cat .\scan_me.txt
.\traces\trace01.run
.\traces\trace02.run
> .\yara-ttd -l path\to\rule .\scan_me.txt
複数のファイルをスキャンする場合、
yara-ttdはスキャンを 1 つずつ順番に実行し、元のyaraCLI のようにスレッドを使用して同時には実行しません。