Christophe Alladoum

TTDエコシステムの深堀り

これは、マイクロソフトが開発したタイム トラベル デバッグ (TTD) テクノロジに焦点を当てたシリーズの第 1 回で、最近の独立した調査期間中に詳細に調査されました。

20分で読めますセキュリティ調査
TTDエコシステムの深堀り

年に数回、Elasticセキュリティラボのリサーチャーは、1人でもチームでも、自分の好きなプロジェクトを自由に選択して掘り下げることができます。 この時間は、内部的には「オンウィーク」プロジェクトと呼ばれます。 これは、Microsoft が開発した タイム トラベル デバッグ (TTD) テクノロジに焦点を当てたシリーズの第 1 回であり、最近の On-Week セッションで詳細に説明されました。

数年前から公開されていたにもかかわらず、TTDとその可能性に対する認識は、情報セキュリティコミュニティ内で非常に過小評価されています。 この 2 部構成のシリーズが、TTD がプログラムのデバッグ、脆弱性の調査と悪用、マルウェア分析にどのように役立つかを明らかにするのに役立つことを願っています。

この研究では、まずTTDの内部構造を理解し、次にTTDから得られる興味深い適用可能な使用法を評価しました。 この記事では、研究者がどのようにTTDを深く掘り下げているかに焦点を当て、その方法論といくつかの興味深い発見を共有します。 第2部では、マルウェア分析とElasticセキュリティとの統合を目的としたTTDの適用可能な使用について詳しく説明します。

背景

Time Travel Debugging は、Microsoft Research によって開発されたツールで、ユーザーは実行を記録し、バイナリのユーザー モード ランタイムに自由に移動できます。 TTD自体は、バイナリ変換にNirvana、トレースの読み取り/書き込みプロセスにiDNAという2つのテクノロジーに依存しています。 Windows 7 以降で使用可能になった TTD の内部構造は、 公開された論文で最初に詳しく説明されました。 それ以来、 マイクロソフト独立した研究者 の両方がそれを非常に詳細に取り上げてきました。 このため、両方のテクノロジの内部については詳しく説明しません。 そこで、Elasticのリサーチャーは、TTDの実装を機能させるエコシステム、つまり実行可能ファイル、DLL、ドライバーを調査しました。 これにより、TTD だけでなく、Windows 自体についても興味深い発見があり、TTD は一部の (文書化されていない) 手法を利用して 、保護されたプロセスなどの特殊なケースで意図したとおりに機能します。

しかし、なぜTTDを調査するのでしょうか? 純粋な好奇心は別として、このテクノロジーの意図された用途の1つは、本番環境でのバグの発見である可能性があります。 バグのトリガーや再現が難しい場合、"一度再生する" タイプの環境を持つことで、その困難を補うことができます。これは、TTD が WinDbg と組み合わせたときに実装するものです。

WinDbg などのデバッグ ツールは、Windows コンポーネントを反転するときに、通常はプレーン テキストで追加のわかりやすい情報を提供するため、常に膨大な情報源となっています。デバッグ ツール (特にデバッガー) は、基になるオペレーティング システムと連携する必要があり、これにはデバッグ インターフェイスや OS の未公開の機能が含まれる場合があります。 TTD はそのパターンに準拠しています。

概要

TTD は、最初にアプリケーションによって実行されたすべての命令を追跡し、それをデータベース (.run の接尾辞付き) に格納する記録を作成することで機能します。 記録されたトレースは、WinDbg デバッガーを使用して自由に再生でき、最初のアクセス時に .run のインデックスが作成されます ファイルを使用して、データベース内のナビゲーションを高速化できます。 任意のプロセスの実行を追跡できるようにするために、TTD はオンデマンドでアクティビティを記録する DLL を挿入し、プロセスを生成して記録できるようにしますが、すでに実行中のプロセスにアタッチすることもできます。

TTD は、MS ストアの WinDbg プレビュー パッケージの一部として無料でダウンロード できます 。 WinDbg Preview (別名 WinDbgX) から直接使用できますが、この投稿で焦点を当てる x64 アーキテクチャの C:\Program Files\WindowsApps\Microsoft.WinDbg_<version></version>_<arch>__8wekyb3d8bbwe\amd64\ttd に位置するスタンドアロン コンポーネントです。 x86 バージョンと arm64 バージョンは、MS Store からもダウンロードできます。

パッケージは、2 つの EXE ファイル (TTD.exe と TTDInject.exe) で構成されています そして一握りのDLL。 この研究は、ニルヴァーナ/iDNAに関連しないすべてのもの(すなわち、 セッション管理、ドライバー通信、DLLインジェクションなどを担当):ttdrecord.dll

_Note: この研究のほとんどは、ttdrecord DLL の 2 つのバージョンを使用して行われました: 主に 1.9.106.0 2018 バージョン (1.9.106.0 SHA256=aca1786a1f9c96bbe1ea9cef0810c4d164abbf2c80c9ecaf0a1ab91600da6630)、および初期の 2022 バージョン(10.0.19041.1 SHA256=1FF7F54A4C865E4FBD63057D5127A73DA30248C1FF28B99FF1A43238071CBB5C)です。 古いバージョンにはより多くの記号があることが判明し、リバースエンジニアリングプロセスをスピードアップするのに役立ちました。 その後、構造体と関数名を最新バージョンに再適合させました。 したがって、ここで説明する構造の一部は、新しいバージョンで再現しようとしている場合、同じではない可能性があります。 _

TTD 機能の調査

コマンドラインパラメータ

読者は、TTD.exe が基本的に ttdrecord のラッパーとして機能することに注意する必要があります。ExecuteTTTracerCommandLine を実行します。

HRESULT wmain()
{
v28 = 0xFFFFFFFFFFFFFFFEui64;
hRes = CoInitializeEx(0i64, 0);
if ( hRes >= 0 )
{
ModuleHandleW = GetModuleHandleW(L"TTDRecord.dll");
[...]
TTD::DiagnosticsSink::DiagnosticsSink(DiagnosticsSink, &v22);
CommandLineW = GetCommandLineW();
lpDiagnosticsSink = Microsoft::WRL::Details::Make<TTD::CppToComDiagnosticsSink,TTD::DiagnosticsSink>(&v31, DiagnosticsSink);
hRes = ExecuteTTTracerCommandLine(*lpDiagnosticsSink, CommandLineW, 2i64);
[...]

上記のコード抜粋の最後の行は、最後の引数として整数を取る ExecuteTTTracerCommandLine の呼び出しを示しています。 この引数は、目的のトレース モード ( 0 -> FullTracingMode、 1 -> UnrestrictedTracing)、 2 -> スタンドアロン (パブリック バージョンの TTD.exe Windows のハードコードされたモード) に対応します

TTD をフルトレースモードで強制的に実行すると、プロセスの再親化 (-parent) やプログラムやサービスの再起動までの自動トレース (-onLaunch) などの隠れた機能を含む、使用可能なオプションが表示されます。

TTDRecord.dllの完全なオプションセットをダンプすると、次のような興味深い隠されたコマンドラインオプションが明らかになりました。

-persistent Trace programs or services each time they are started (forever). You must specify a full path to the output location with -out.
-delete Stop future tracing of a program previously specified with -onLaunch or -persistent. Does not stop current tracing. For -plm apps you can only specify the package (-delete <package>) and all apps within that package will be removed from future tracing
-initialize Manually initialize your system for tracing. You can trace without administrator privileges after the system is initialized.

Nirvana を設定するプロセスでは、TTD がターゲット _EPROCESSの InstrumentationCallback フィールドを設定する必要があります。 これは、(文書化されていないが 既知の) NtSetInformationProcess(ProcessInstrumentationCallback) システムコール (ProcessInstrumentationCallback、値は 40) によって実現されます。 セキュリティ上の影響が及ぶ可能性があるため、このシステムコールを呼び出すには昇格された特権が必要です。 興味深いことに、-initialize フラグは、TTD を Windows サービスとしてデプロイできることも示唆していました。 このようなサービスは、トレース要求を任意のプロセスにプロキシする役割を担います。 これは、実行して結果のエラーメッセージを確認することで確認できます。

TTDService.exeの存在を確認する証拠を見つける のは簡単ですが、ファイルは公開パッケージの一部として提供されていないため、TTDがサービスとして実行できることに注意する以外は、この投稿では取り上げません。

TTDプロセスインジェクション

説明したように、TTD トレース ファイルは、スタンドアロン バイナリ TTD.exeから作成するか、サービス TTDService.exeバイナリ (プライベート) を使用して作成でき、どちらも特権コンテキストで実行する必要があります。 ただし、これらは単なるランチャーであり、記録DLL(TTDRecordCPU.dllという名前)の挿入は、別のプロセスであるTTDInject.exeの仕事です。

TTDInject.exe は、TTD.exe よりも明らかに大きい別の実行可能ファイルですが、トレース セッションを準備するという非常に単純な目的があります。 過度に単純化されたビューでは、TTD.exe最初に中断状態で記録されるプロセスを開始します。 その後、TTDInject.exeスポーンします。 セッションを準備するために必要なすべての引数を渡します。 TTDInject は、前述のトレース モードに応じてプロセスを直接生成することもできることに注意してください — したがって、最も一般的な動作 (つまり、TTD.exeから生成された場合) について説明しています。

TTDInjectは、TTDLoaderを実行するためのスレッドを作成します。InjectThread を記録されたプロセスに含め、さまざまな検証の後、すべてのプロセス アクティビティの記録を担当するライブラリを読み込みます (TTDRecordCPU.dll)。

その時点から、実行中に発生したすべての命令、メモリアクセス、トリガーされた例外、またはCPUの状態が記録されます。

TTDの一般的なワークフローが理解されると、セッションの初期化後にはほとんどまたはまったく操作できないことが明らかになりました。 したがって、ttdrecord.dllによって支持された議論にさらに注意が払われました。 C++ マングリング関数形式のおかげで、関数名自体から多くの重要な情報を取得できるため、コマンド ライン引数パーサーの分析が比較的簡単になります。 発見された興味深いフラグの 1 つは PplDebuggingToken でした。 このフラグは非表示で、制限なしモードでのみ使用できます。

このフラグの存在はすぐに疑問を投げかけました: TTD は最初に Windows 7 と 8 を中心に設計され、Windows 8.1+ で設計されました。 保護レベルの概念がプロセスに追加され、保護 レベル が同等またはそれ以下のプロセスに対してのみ、プロセスがハンドルを開くことができるようになりました。 これはカーネルの _EPROCESS 構造体の単純なバイトであるため、ユーザーモードから直接変更することはできません。

Protection Level バイトの値はよく知られており、次の表にまとめられています。

Local Security Authority サブシステム (lsass.exe) は、ホスト上で最大の権限を取得する侵入者の到達範囲を制限することを目的とした Protected Process Light として実行するように設定 できます 。 カーネル レベルで動作することで、ユーザー モード プロセスは、特権がどれほどあっても lsass へのハンドルを開くことができません。

しかし、PplDebuggingToken フラグはそうではないことを示唆しているように見えます。 もしそのようなフラグが存在するとしたら、それはペンテスター/レッドチーム選手の夢でしょう:保護されたプロセスに注入して記録したり、メモリをダンプしたりできる(魔法の)トークンです。 コマンドラインパーサーは、コマンドフラグの内容が単なるワイド文字列であることを暗示しているようです。 これはPPLのバックドアでしょうか?

PPL デバッグ トークンの追跡

ttdrecord.dllに戻ると、 PplDebuggingToken コマンド ライン オプションは解析され、TTD セッションの作成に必要なすべてのオプションと共にコンテキスト構造に格納されます。 値はいくつかの場所にさかのぼることができますが、興味深いのは TTD::InitializeForAttach 内にあり、その動作は次の擬似コードで簡略化されています。

ErrorCode TTD::InitializeForAttach(TtdSession *ctx)
{
  [...]
  EnableDebugPrivilege(GetCurrentProcess()); // [1]
  HANDLE hProcess = OpenProcess(0x101040u, 0, ctx->dwProcessId);
  if(hProcess == INVALID_HANDLE_VALUE)
 {
    goto Exit;
  }
  [...]
  HMODULE ModuleHandleW = GetModuleHandleW(L"crypt32.dll");
  if ( ModuleHandleW )
  pfnCryptStringToBinaryW = GetProcAddress(ModuleHandleW, "CryptStringToBinaryW"); // [2]

  if ( ctx->ProcessDebugInformationLength ) // [3]
  {
DecodedProcessInformationLength = ctx->ProcessDebugInformationLength;
DecodedProcessInformation = std::vector<unsigned char>(DecodedProcessInformationLength);
wchar_t* b64PplDebuggingTokenArg = ctx->CmdLine_PplDebugToken;
if ( *pfnCryptStringToBinaryW )
{
  if( ERROR_SUCCESS == pfnCryptStringToBinaryW( // [4]
                      b64PplDebuggingTokenArg,
                      DecodedProcessInformationLength,
                      CRYPT_STRING_BASE64,
                      DecodedProcessInformation.get(),
                      &DecodedProcessInformationLength,
                      0, 0))
  {
    Status = NtSetInformationProcess( // [5]
               NtGetCurrentProcess(),
               ProcessDebugAuthInformation,
               DecodedProcessInformation.get(),
               DecodedProcessInformationLength);
  }
[...]

現在のプロセス ([1]) の SeDebugPrivilege フラグを有効にし、アタッチするプロセス ([2]) へのハンドルを取得した後、この関数は文字列操作の実行に使用されるエクスポートされたジェネリック関数 crypt32!CryptStringToBinaryW です。 この例では、コマンド ライン ( [3], [4]) によって指定されている場合、PplDebuggingToken コンテキスト オプションの base64 でエンコードされた値をデコードするために使用されます。 デコードされた値は、syscall NtSetInformationProcess(ProcessDebugAuthInformation) ([5]) を呼び出すために使用されます。 このトークンは他の場所では使用されていないようで、そのシステムコールを精査する必要がありました。

プロセス情報クラス ProcessDebugAuthInformation が RS4 に追加されました。 ntoskrnl をざっと見ると、このシステム呼び出しは、コード整合性ドライバー DLL である ci.dll にある CiSetInformationProcess にバッファーを渡すだけであることがわかります。 その後、バッファーは、完全に制御された引数を使用して ci!CiSetDebugAuthInformation に渡されます。

次の図は、TTD の実行フローでこれが発生する場所を大まかにまとめたものです。

CiSetDebugAuthInformation の実行フローは非常に単純です: base64 でデコードされた PplDebuggingToken とその長さを持つバッファーは、解析と検証の引数として ci!SbValidateAndParseDebugAuthToken に渡されます。 検証が成功し、追加の検証が行われた後、システムコールを実行するプロセスへのハンドル (システムコール nt をまだ処理していることに注意してください)。NtSetInformationProcess) は、プロセス デバッグ情報オブジェクトに挿入され、グローバル リスト エントリに格納されます。

しかし、それはどのように興味深いのでしょうか? このリストは ci!CiCheckProcessDebugAccessPolicy の 1 つの場所でのみアクセスされ、この関数は NtOpenProcess システム呼び出し中に到達するためです。 また、新しく検出されたフラグの名前が前に示したように、PID がそのリストにあるプロセスは、保護レベルの強制をバイパスします。 これは、そのリストにアクセス ブレークポイントを設定することで、 KD セッションで実際に確認されました (ci.dll のバージョンでは、これは ci+364d8 に配置されていました)。 また、 LSASS で PPL を有効にし 、NtOpenProcess システムコールをトリガーする簡単な PowerShell スクリプトを作成しました。

nt!nt!PspProcessOpenを使用すると、PowerShellプロセスがlsass.exeをターゲットにしようとしていることを確認できます。 これはPPLプロセスです。

ここで、PplDebuggingToken 引数が呼び出しの戻り値を nt に強制することによって何を行うかについての最初の理論を確認します。PsTestProtectedProcess非互換性:

nt!PsTestProtectedProcessIncompatibility (CI!CiCheckProcessDebugAccessPolicy のみを呼び出す) し、戻り値を強制的に 0 にします (前述のように、値 1 は互換性がないことを意味します)。

成功! PPLであるにもかかわらず、LSASSのハンドルを取得し、私たちの理論を裏付けました。 要約すると、「有効な値」を見つけることができれば (これについてはすぐに詳しく説明します)、ci!CiSetDebugAuthInformation() の SbValidateAndParseDebugAuthToken() のチェックに合格し、ユニバーサル PPL バイパスが得られます。 これがあまりにも良すぎるように聞こえるなら、それは主にそうだからですが、それを確認するには、CI.dll何をしているのかをよりよく理解する必要があります。

コード整合性ポリシーの理解

AppLocker で使用されるようなコードの整合性に基づく制限は、人間が判読できる形式では XML ファイルであるポリシーを通じて適用できます。 ポリシーには、基本ポリシーと補足ポリシーの 2 種類があります。 基本ポリシーの例は、"C:\Windows\schemas\CodeIntegrity\ExamplePolicies" の XML 形式にあります。 これは、基本ポリシーが XML 形式 ("C:\Windows\schemas\CodeIntegrity\ExamplePolicies\AllowAll.xml" から取得) でどのように表示されるかであり、関心のある詳細のほとんどをプレーンテキストで明確に示しています。

<?xml version="1.0" encoding="utf-8"?>
<SiPolicy xmlns="urn:schemas-microsoft-com:sipolicy">
<VersionEx>1.0.1.0</VersionEx>
<PolicyID>{A244370E-44C9-4C06-B551-F6016E563076}</PolicyID>
<BasePolicyID>{A244370E-44C9-4C06-B551-F6016E563076}</BasePolicyID>
<PlatformID>{2E07F7E4-194C-4D20-B7C9-6F44A6C5A234}</PlatformID>
<Rules>
<Rule><Option>Enabled:Unsigned System Integrity Policy</Option></Rule>
<Rule><Option>Enabled:Advanced Boot Options Menu</Option></Rule>
<Rule><Option>Enabled:UMCI</Option></Rule>
<Rule><Option>Enabled:Update Policy No Reboot</Option></Rule>
</Rules>
<!--EKUS-- >
<EKUs />
<!--File Rules-- >
<FileRules>
<Allow ID="ID_ALLOW_A_1" FileName="*" />
<Allow ID="ID_ALLOW_A_2" FileName="*" />
</FileRules>
<!--Signers-- >
<Signers />
<!--Driver Signing Scenarios-- >
<SigningScenarios>
<SigningScenario Value="131" ID="ID_SIGNINGSCENARIO_DRIVERS_1" FriendlyName="Auto generated policy on 08-17-2015">
  <ProductSigners>
    <FileRulesRef><FileRuleRef RuleID="ID_ALLOW_A_1" /></FileRulesRef>
  </ProductSigners>
</SigningScenario>
<SigningScenario Value="12" ID="ID_SIGNINGSCENARIO_WINDOWS" FriendlyName="Auto generated policy on 08-17-2015">
  <ProductSigners>
    <FileRulesRef><FileRuleRef RuleID="ID_ALLOW_A_2" /></FileRulesRef>
  </ProductSigners>
</SigningScenario>
</SigningScenarios>
<UpdatePolicySigners />
<CiSigners />
<HvciOptions>0</HvciOptions>
<Settings>
<Setting Provider="PolicyInfo" Key="Information" ValueName="Name">
  <Value><String>AllowAll</String></Value>
</Setting>
<Setting Provider="PolicyInfo" Key="Information" ValueName="Id">
  <Value><String>041417</String></Value>
</Setting>
</Settings>
</SiPolicy>

XML 形式のポリシーは、ConvertFrom-CiPolicy PowerShell コマンドレットを使用してバイナリ形式にコンパイルできます。

基本ポリシーでは、名前、パス、ハッシュ、または署名者(特定の EKUの有無にかかわらず)で制限できる細かい粒度が可能です。だけでなく、アクションモード(監査または強制)でも。

補足ポリシーは、基本ポリシーの拡張として設計され、たとえば、特定のワークステーションまたはサーバーのグループにポリシーを適用する(または適用しない)など、より柔軟性を提供します。 したがって、それらはより具体的ですが、基本ポリシーよりも寛容である可能性もあります。 興味深いことに、2016年以前は、補足ポリシーは 特定のデバイスにバインドされておらず 、メディアで 広く取り上げ られていた MS16-094 および MS16-100 によって修正された他の方法では緩和されたバイパスが許可されていました。

その情報を念頭に置くと、ci!SbValidateAndParseDebugAuthToken により明確に戻ることができます: この関数は基本的に 3 つのステップに従います: 1. ci!SbParseAndVerifySignedSupplementalPolicy を呼び出して、システム呼び出しから入力バッファーを解析し、それが有効に署名された補足ポリシー 2 であるかどうかを判断します。ci!SbIsSupplementalPolicyBoundToDevice を呼び出して、補足ポリシーの DeviceUnlockId を現在のシステムの DeviceUnlockId と比較します。このような値は、GUID {EAEC226F-C9A3-477A-A826-DDC716CDC0E3}3 の syscall NtQuerySystemEnvironmentValueEx を使用して簡単に取得できます。最後に、ポリシーから 2 つの変数 (保護レベルに対応する整数 (DWORD) と (UNICODE_STRING) デバッグ承認) を抽出します。

ポリシーファイルを作成する(XMLまたはPowerShellスクリプトを使用)ため、ステップ 3 は問題ありません。 SeSystemEnvironmentPrivilege 特権を持っている限り、DeviceUnlockId は syscall NtSetSystemEnvironmentValueEx({EAEC226F-C9A3-477A-A826-DDC716CDC0E3}) で偽造できるため、ステップ 2 も同様です。 ただし、UnlockId は、再起動時に復元される揮発性の値であることに注意してください。

ただし、ステップ 1 をバイパスすることは、次の必要があるため、事実上不可能です。- 特定の OID 1.3.6.1.4.1.311.10.3.6(つまり、MS NT5 Lab(szOID_NT5_CRYPTO))を持つMicrosoft所有の証明書の秘密鍵を所有すること、および前述の証明書を失効させたり期限切れにしたりしてはなりません

では、私たちはどうなるのでしょうか? 従来の常識に反して、カーネルドライバーをロードする追加の手順を踏まなくても、PPLプロセスを別のプロセスで開くことができることを確認しました。 ただし、このようなユースケースはニッチであることも強調する必要があります。なぜなら、Microsoftだけが(文字通り)この手法を非常にターゲットを絞ったマシンに使用するための鍵を握っているからです。 それにもかかわらず、このようなケースは、デバッグ目的での CI のエアギャップ使用の好例です。

オフェンシブTTD

注: TTD.exeには昇格された権限が必要であり、以下で説明するすべての手法が想定しています。

この調査を通じて、TTDの潜在的に興味深い攻撃的および防御的な使用例を発見しました。

トレース != デバッグ

TTD はデバッガーではありません。 したがって、IsDebuggerPresent() (または PEB に依存するその他の方法) を使用するなど、基本的なアンチデバッグ チェックを実行するプロセスでは、完全に検出されずに機能します。BeingDebugged) です。 次のスクリーンショットは、TTD を単純なメモ帳プロセスにアタッチすることで、この詳細を示しています。

デバッガーから、フラグが設定されていないことを示すメモ帳 PEB にある BeingDebugged フィールドを確認できます。

ProcLaunchMonの奇妙なケース

TTDが提供するもう1つの興味深いトリックは、組み込みのWindowsドライバー ProcLaunchMon.sysを悪用することです。 サービスとして実行している場合 (つまり、 TTDService.exe)、ttdrecord.dll はサービス インスタンスを作成し、ドライバーを読み込み、.\com_microsoft_idna_ProcLaunchMon で使用可能なデバイスと通信して、新しくトレースされたクライアントを登録します。

ドライバー自体は、TTD サービスによって作成された新しいプロセスを監視し、カーネルから直接それらのプロセスを一時停止するために使用され、作成フラグが CREATE_SUSPENDED でプロセスの作成のみを監視する保護 (たとえば 、ここで 説明したように) をバイパスします。 この研究のために、基本的なデバイスドライバクライアントを開発しました。

CreateDump.exe

もう 1 つの興味深い事実は、厳密には TTD の一部ではありませんが、WinDbgX パッケージは、その機能を完全に要約した名前の .NET 署名付きバイナリ (createdump.exe) を提供します。 このバイナリは "C:\Program Files\WindowsApps\Microsoft.WinDbg_*\createdump.exe" にあります。

このバイナリは、引数として指定されたプロセスのコンテキストを、他の LOLBA の直接の系統でスナップショットおよびダンプするために使用できます。

このことは、クレデンシャルダンピングなどの攻撃から保護するために静的な署名やファイル名のブロックリストエントリに依存することを避け、 RunAsPPLCredential GuardElastic EndpointのCredential Hardeningなどのより堅牢なアプローチを好む必要性を改めて浮き彫りにしています。

ディフェンシブTTD

TTD のブロック

TTD は非常に便利な機能ですが、開発マシンやテストマシン以外のマシン (運用サーバーやワークステーションなど) で有効にする必要があるケースはまれです。 この記事の執筆時点では、これはほとんど文書化されていないように見えますが、ttdrecord.dll では、"HKEY_LOCAL_MACHINE\Software\Microsoft\TTD" の下にあるレジストリ キーを作成または更新し、DWORD32値 RecordingPolicy を 2 に更新するだけで、早期終了シナリオが可能になります。TTDサービスの使用をさらに試みる(TTD.exe TTDInject.exe、 TTDService.exe) は停止し、試行を追跡するための ETW イベントが生成されます。

TTD の検出

TTDの使用を防ぐことは、すべての環境にとって極端すぎるかもしれませんが、TTDの使用を検出するためのいくつかの指標が存在します。 トレースされるプロセスには、次のプロパティがあります。

  • 1つのスレッドはTTDRecordCPU.dllからコードを実行します。 これは、単純な組み込みWindowsコマンド(tasklist /m TTDRecordCPU.dll
  • これをバイパスすることもできますが、記録されたプロセスの親 PID (または再帰的トレースが有効になっている場合は最初の PID) はそれ自体TTD.exeになります。

  • また、_KPROCESS。InstrumentationCallback ポインタは、実行可能ファイルの TTDRecordCPU.dll BSS セクションに着地するように設定されます。

したがって、TTD からのトレースの検出は、User-Mode メソッドと Kernel-Mode メソッドの両方で実現できます。

まとめ

これで、TTDに焦点を当てたこの「On-Week」研究の最初の部分は終わりです。 TTD エコシステムの内部を掘り下げると、Windows に組み込まれている非常に興味深い、あまり知られていないメカニズムがいくつか明らかになりました。これは、PPL プロセスのトレースなど、特定のエッジ ケースで TTD を機能させるために必要です。

この調査では、PPLプロセスを標的とする新しい秘密のバックドアは明らかにされませんでしたが、そのためのWindowsに組み込まれた未踏の手法が示されました。 どちらかといえば、この調査では、強力な暗号化に基づくモデル(ここではCI.dllまで)の重要性と、適切に実装すれば、高いレベルのセキュリティを維持しながら多くの柔軟性をもたらすことができることを強調しています。

このシリーズの第2部は、研究志向ではなく、On-Weekの一部として開発した小さなツールのリリースにより、より実践的なものになります。 これは、Windows サンドボックスを使用した TTD によるバイナリ分析のプロセスを支援します。

承認

この研究はすでに終了しており、記事が進行中であるため、著者は、同様の主題を扱った研究と、まったく同じ手法 (PPL デバッグ トークン) に関する調査結果に気付きました。 この研究は、 SSTIC 2022で調査結果を発表したLucas George氏(Synacktiv社)によって行われました。

この記事を共有する