MassLogger アンチ分析のバイパス — 中間者アプローチ

dnSpy showing empty methods news

FireEye Front Line Applied Research & Expertise (FLARE) チームは、最新および新たな脅威を常に把握するよう努めています。 FLARE リバース エンジニア チームのメンバーとして、私は最近、MassLogger として特定されたかなり新しい資格情報窃盗プログラムの分析を依頼されました。新しい機能や機能が不足しているにもかかわらず、このサンプルでは、実行時に Microsoft Intermediate Language (MSIL) を置き換える高度な手法を採用して、静的分析を妨げています。この記事の執筆時点では、MassLogger の難読化手法について詳細に説明している出版物は 1 つだけです。そのため、同様の手法を使用して MassLogger やその他のマルウェアを分析するのに役立つ調査とツールを共有することにしました。 MassLogger クレデンシャル スティーラーと .NET ランタイムについて、技術的に深く掘り下げてみましょう。

トリアージ

MassLogger は、.NET クレデンシャル スティーラーです。これはランチャー ( 6b975fd7e3eb0d30b6dbe71b8004b06de6bba4d0870e165de4bde7ab82154871 ) で始まり、特定されると簡単に回避できる単純なアンチデバッグ手法を使用します。この第 1 段階のローダーは、最終的に第 2 段階のアセンブリを XOR 復号化し、 Bin-123.exeという名前の最終的な MassLogger ペイロード ( bc07c3090befb5e94624ca4a49ee88b3265a3d1d288f79588be7bb356a0f9fae ) を復号化し、ロードして実行します。最終的なペイロードは、簡単に抽出して個別に実行できます。したがって、主なアンチ分析手法が使用されるこの最終的なペイロードにのみ焦点を当てます。

基本的な静的分析では、あまりエキサイティングなことは明らかになりません。いくつかの興味深い文字列に気付きましたが、マルウェアの機能に関するヒントを得るには十分ではありません。制御された環境でペイロードを実行すると、サンプルがマルウェア ファミリ、そのバージョン、および最も重要ないくつかの構成オプションを識別するログ ファイルをドロップすることがわかります。サンプル ログ ファイルを図 1 に示します。サンプルを実行すると、興味深い文字列をメモリから抽出することもできます。ただし、基本的な動的分析では、すべてのホストベースのインジケーター (HBI)、ネットワークベースのインジケーター (NBI)、および完全なマルウェア機能を抽出するには不十分です。サンプルとその機能をよりよく理解するには、より深い分析を実行する必要があります。

ユーザー名: ユーザー
IP: 127.0.0.1
場所: アメリカ合衆国
OS:Microsoft Windows 7 Ultimate 32bit
CPU: Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
GPU: ヴイエムウェア SVGA 3D
AV: なし
画面解像度: 1438×2460
現在の時刻: 2020/06/17 1:23:30 PM
MassLogger 開始: 2020 年 6 月 17 日 1:23:21 PM
間隔: 2 時間
MassLogger プロセス: C:UsersuserDesktopBin-123.exe
MassLogger Melt: false
配信後の MassLogger 終了: false
管理者として: False
プロセス:
名前:cmd、役職:管理者: FakeNet-NG – fakenet
名前:iexplore、タイトル:FakeNet-NG – Internet Explorer
名前:dnSpy-x86、タイトル:dnSpy v6.0.5 (32 ビット)
名前:cmd、タイトル:管理者: C:WindowsSystem32cmd.exe
名前:ProcessHacker、役職:Process Hacker [WIN-R23GG4KO4SDuser]+ (管理者)

### WD 除外 ###
無効

### USBの広がり ###
無効

### バインダー ###
無効

### ウィンドウサーチャー ###
無効

### ダウンローダ ###
無効

### ボットキラー ###
無効

### 検索とアップロード ###
無効

### 電報デスクトップ ###
インストールされていない

### ピジン ###
インストールされていない

### FileZilla ###
インストールされていない

### 不和トークン ###
インストールされていない

### NordVPN ###
インストールされていない

### 展望 ###
インストールされていない

### FoxMail ###
インストールされていない

### サンダーバード ###
インストールされていない

### QQ ブラウザ ###
インストールされていない

### ファイアフォックス ###
インストールされていない

### クロム回収 ###
インストールされていない

### キーロガーとクリップボード ###

 

[20/06/17] [Chrome へようこそ – Google Chrome]
[ESC]

[20/06/17] [クリップボード]
Vewgbprxvhvjktmyxofjvpzgazqszaoo

図 1: MassLogger ログのサンプル

逆コンパイルするだけ

他の多くの .NET マルウェアと同様に、MassLogger はすべてのメソッド名とメソッド制御フローさえも難読化します。 de4dotを使用して、MassLogger ペイロードの難読化を自動的に解除できます。しかし、難読化が解除されたペイロードを見ると、すぐに重大な問題が特定されます。図 2 に示すように、ほとんどのメソッドにはロジックがほとんど含まれていません。

dnSpy showing empty methods
図 2: 空のメソッドを示す dnSpy

dnSpyの Intermediate Language (IL) ビューで元の MassLogger ペイロードを見ると、ほとんどのメソッドにはロジックが含まれておらず、単に何も返されないことが確認されます。サンプルが実際に悪意のあるアクティビティを実行し、ログ ファイルに記録することを動的分析で確認したため、これは明らかに本物のマルウェアではありません。いくつかのメソッドが残っていますが、最も顕著なのは、メイン モジュール コンストラクターで最初に呼び出されるトークン0x0600049Dを持つメソッドです。

メソッドの詳細を示す dnSpy IL ビュー
図 3: メソッドの詳細を示す dnSpy IL ビュー

メソッド0x0600049D の制御フローは、一連の switch ステートメントに難読化されています。デバッガーとしてdnSpyの助けを借りて、メソッドの高レベル ロジックをいくらかたどることができます。ただし、メソッドを完全に分析するには、非常に時間がかかります。代わりに、このペイロードを最初に分析するときに、モジュール全体をすばやくスキャンしてヒントを探すことにしました。幸いなことに、基本的な静的分析で見逃していたいくつかの興味深い文字列を見つけました。図 4 に示すように、 clrjit.dllVirtualAllocVirtualProtect 、およびWriteProcessMemoryです。

モジュール全体に散りばめられた興味深い文字列
図 4: モジュール全体に散らばる興味深い文字列

インターネットで「 clrjit.dll 」および「 VirtualProtect 」を検索すると、一般にジャスト イン タイム フックと呼ばれる手法を説明しているいくつか出版物がすぐに見つかります。本質的に、JIT フックには、JIT コンパイラが MSIL をアセンブリ (x86、x64 など) にコンパイルしようとしているcompileMethod()関数にフックをインストールすることが含まれます。フックを配置すると、マルウェアは各メソッド本体を元のマルウェア ロジックを含む実際の MSIL に簡単に置き換えることができます。このプロセスを完全に理解するために、.NET 実行可能ファイル、.NET メソッド、および MSIL が x86 または x64 アセンブリに変換されるしくみを調べてみましょう。

.NET 実行可能メソッド

.NET 実行可能ファイルは、Portable Executable (PE) 形式に準拠した別のバイナリです。 PE ファイル形式.NET メタデータ、および .NET トークン テーブルについて詳しく説明しているリソースはたくさんあります。先に進む前に、読者の皆様には、これらのトピックについて少し回り道をして記憶を新たにすることをお勧めします。この投稿では、これ以上の詳細には触れませんが、代わりに .NET メソッドに焦点を当てます。

.NET アセンブリ内の各 .NET メソッドは、トークンによって識別されます。実際、モジュール、クラス、メソッド プロトタイプ、文字列のいずれであっても、.NET アセンブリ内のすべてがトークンによって識別されます。図 5 に示すように、トークン0x0600049Dによって識別されるメソッドを見てみましょう。最上位バイト ( 0x06 ) は、このトークンがモジュール トークン (タイプ0x00 ) ではなくメソッド トークン (タイプ0x06 ) であること、つまり TypeDef トークンであることを示しています。 (タイプ0x02 )、または LocalVarSig トークン (タイプ0x11 ) など。最下位 3 バイトはメソッドの ID を示します。この場合は0x49D (10 進数で1181 ) です。この ID は、メソッド ID (MID) またはメソッドの行 ID とも呼ばれます。

メソッド 0x0600049D のメソッドの詳細
図 5: メソッド 0x0600049D のメソッドの詳細

このメソッドの詳細を確認するために、図 6 に示すように、.NETメタデータ ディレクトリ内の .NET メタデータ ストリームの「 #~ストリームのテーブル内を調べます。メソッド本体の相対仮想アドレス (RVA)、さまざまなフラグ、メソッド名へのポインター、メソッド シグネチャへのポインター、最後にパラメーター仕様へのポインターを含むメソッド メタデータを検索するためのメソッド テーブルこの方法。 MID は 0 ではなく 1 から始まることに注意してください

PE ファイル ヘッダーのメソッドの詳細
図 6: PE ファイル ヘッダーのメソッドの詳細

メソッド0x0600049Dの場合、メソッド本体の RVA は0xB690です。この RVA は、RVA が0x2000である.textセクションに属します。したがって、このメソッド本体は.textセクションの0x9690 ( 0xB6900x2000 ) バイトから始まります。 .textセクションは、セクション ヘッダーに従って、ファイルの0x200バイトから始まります。その結果、ファイルの0x9890 ( 0x9690 + 0x200 ) バイト オフセットでメソッド本体を見つけることができます。メソッド本体を図 7 に示します。

16 進エディタのメソッド 0x0600049D 本体
図 7: 16 進数エディターでのメソッド 0x0600049D 本体

.NET メソッド本体

.NET メソッド本体はメソッド本体ヘッダーで始まり、その後に MSIL バイトが続きます。 .NET メソッドには、tiny メソッドと fat メソッドの 2 種類があります。メソッド本体ヘッダーの最初のバイトを見ると、最下位 2 ビットによって、メソッドが tiny (最後の 2 ビットが10 ) であるか、または fat (最後の 2 ビットが11 ) であるかがわかります。

.NET Tiny メソッド

メソッド0x06000495を見てみましょう。前述と同じ手順に従って、メソッド テーブルの行番号0x495 (10 進数で1173 ) を調べて、メソッド本体の RVA が0x7A7Cであることを確認します。これは、ファイルへのオフセットとして0x5C7Cに変換されます。このオフセットでは、メソッド本体の最初のバイトは0x0A (バイナリで0000 1010 ) です。

メソッド 0x06000495 のメタデータと本文
図 8: メソッド 0x06000495 のメタデータと本文

最下位 2 ビットが10であるため、 0x06000495が小さなメソッドであることがわかります。 tiny メソッドの場合、メソッド本体のヘッダーの長さは1 バイトです最下位 2 ビット10で、これが極小メソッドであることを示します。最上位 6 ビットは、従うべき MSIL のサイズ (つまり、MSIL の長さ) を示します。この場合、上位 6 ビットは000010であり、メソッド本体の長さが 2 バイトであることを示しています。 0x06000495のメソッド本体全体は0A 16 2Aであり、その後に NULL バイトが続きます。これは、図 9 に示すようにdnSpyによって逆アセンブルされています。

dnSpy IL ビューのメソッド 0x06000495
図 9: dnSpy IL ビューのメソッド 0x06000495

.NET Fat メソッド

ファイル (RVA 0xB690 ) のオフセット0x9890にあるメソッド0x0600049D (エントリ番号1181 ) に戻ると、メソッド本体の最初のバイトは0x1B (またはバイナリで0001 1011 ) です。最下位 2 ビットは11で、 0x0600049Dがファット メソッドであることを示します。ファット メソッド本体のヘッダーは12 バイトの長さで、その構造はこのブログ投稿の範囲を超えています。本当に重要なフィールドは、このファット ヘッダーのオフセット0x04バイトにある4 バイト フィールドです。このフィールドは、このメソッド本体ヘッダーに続く MSIL の長さを指定します。メソッド0x0600049Dの場合、メソッド本体のヘッダー全体は「 1B 30 08 00 A8 61 00 00 75 00 00 11 」であり、続く MSIL の長さは「 A8 61 00 00 」または0x61A8 (10 進数で25000 ) バイトです。

16 進エディタのメソッド 0x0600049D 本体
図 10: 16 進数エディターでのメソッド 0x0600049D 本体

JITコンパイル

メソッドが小さいか太いかに関係なく、そのままでは実行されません。 .NET ランタイムがメソッドを実行する必要がある場合、前述のプロセスに正確に従って、メソッド本体ヘッダーと MSIL バイトを含むメソッド本体を検索します。メソッドを初めて実行する必要がある場合、.NET ランタイムは Just-In-Time コンパイラを呼び出します。このコンパイラは MSIL バイトを取得し、現在のプロセスが 32 ビットか 64 ビットかに応じて x86 または x64 アセンブリにコンパイルします。 .いくつかの準備の後、JIT コンパイラーは最終的にcompileMethod()関数を呼び出します。 .NET ランタイム プロジェクト全体がオープン ソース化されており、GitHub で入手できますcompileMethod()関数に次のプロトタイプがあることが簡単にわかります (図 11)。

CorJitResult __stdcall compileMethod (
ICorJitInfo *comp, /* IN */
CORINFO_METHOD_INFO *情報, /* IN */
unsigned /* code:CorJitFlag */ flags, /* IN */
BYTE **nativeEntry, /* OUT */
ULONG *nativeSizeOfCode /* OUT */
);

図 11: compileMethod() 関数のプロトタイプ

図 12 は、 CORINFO_METHOD_INFO構造体を示しています。

構造体 CORINFO_METHOD_INFO
{
CORINFO_METHOD_HANDLE ftn;
CORINFO_MODULE_HANDLE スコープ;
BYTE * ILコード;
署名されていないILCodeSize ;
署名されていない maxStack;
署名されていない EHcount;
CorInfoOptions オプション;
CorInfoRegionKind regionKind;
CORINFO_SIG_INFO 引数;
CORINFO_SIG_INFO ローカル。
};

図 12: CORINFO_METHOD_INFO 構造体

ILCodeは、コンパイルするメソッドの MSIL へのポインターであり、 ILCodeSizeは、MSIL の長さを示します。 compileMethod()の戻り値は、成功または失敗を示すエラー コードです。成功した場合、 nativeEntryポインターには、MSIL からコンパイルされた x86 または x64 命令を含む実行可能メモリ領域のアドレスが設定されます。

MassLogger JIT フック

MassLogger に戻りましょう。メイン モジュールの初期化が実行されるとすぐに、最初に他のメソッドの MSIL が解読されます。次に、独自のバージョンのcompileMethod() (メソッド0x06000499 ) を実行するフックをインストールします。このメソッドは、元のcompileMethod()の info 引数のILCodeフィールドとILCodeSizeフィールドを、実際のマルウェアの MSIL バイトに置き換えます。

MassLogger は、MSIL バイトを置き換えるだけでなく、モジュールの初期化時にメソッド本体のヘッダーにもパッチを適用します。図 13 からわかるように、ディスク上のメソッド0x060003DD (ファイル オフセット 0x3CE0) のメソッド本体ヘッダーは、メモリ内のヘッダー (RVA 0x5AE0 ) とは異なります。一貫性が保たれているのは、メソッドがタイニーかファットかを示す最下位の 2 ビットだけです。この分析防止手法をうまく打ち負かすには、実際の MSIL バイトと正しいメソッド本体ヘッダーを回復する必要があります。

ディスク上にある場合とメモリにロードされている場合のヘッダーが異なる同じメソッド本体
図 13: ディスク上にある場合とメモリにロードされている場合の、ヘッダーが異なる同じメソッド本体

JITM による JIT 法体置換の打破

MSIL とメソッド本体ヘッダーを自動的に回復するために、別の FLARE チーム メンバーが提案した 1 つの可能なアプローチは、MassLogger モジュール コンストラクターをロードして実行できるようにする前に、 compileMethod()関数に独自のフックをインストールすることです。マネージド フック (新しいcompileMethod()は C# で記述されたマネージド メソッドです) とネイティブ フック (新しいcompileMethod()はネイティブで C または C++ で記述されています) の両方を使用してcompileMethod()をフックする方法については、複数のチュートリアルオープンソースプロジェクトがあります。 .ただし、MassLogger がcompileMethod()をフックする独自の方法により、前述のプロジェクトの多くで実装されている vtable フック手法を使用できません。したがって、次のプロジェクトを共有したいと思います: JITMは、 PolyHookライブラリによって実装されたインライン フックを使用して設計されています。 JITM には、元のcompileMethod()を呼び出す前に、すべてのメソッド本体ヘッダーと MSIL バイトを JSON ファイルに記録するcompileMethod()のラッパーが付属しています。

フックに加えて、 JITMには .NET ローダーも含まれています。このローダーは、最初にネイティブ フック DLL ( jitmhook.dll ) をロードし、フックをインストールします。次に、ローダーは MassLogger ペイロードをロードし、そのエントリ ポイントを実行します。これにより、MassLogger のモジュール初期化コードが実行され、独自のフックがインストールされますが、元のcompileMethod()の代わりにjitmhook.dllコードがフックされます。 MassLogger のエントリ ポイントを実行する別の方法は、 RuntimeHelpers.PrepareMethod() API を呼び出して、すべてのメソッドで JIT コンパイラを強制的に実行することです。このアプローチは、マルウェアの実行を回避し、サンプルの自然なコード パスで呼び出されていないメソッドを回復できる可能性があるため、優れています。ただし、すべてのメソッドを強制的に適切にコンパイルするには、追加の作業が必要です。

MassLogger メソッドをロードして復元するには、まず次のコマンドを実行します (図 14)。

jitm.exe Bin-123.exe [optional_timeout]

図 14: jitm を実行するコマンド

タイムアウトになると、現在のディレクトリに作成されたファイルjitm.logjitm.jsonが表示されます。 jitm.jsonには、メソッド トークン、メソッド本体ヘッダー、およびBin-123.exeから復元されたすべてのメソッドの MSIL バイトが含まれています。あとは、静的分析を実行できるように .NET メタデータを再構築するだけです。

サンプルjitm.json
図 15: jitm.json のサンプル

アセンブリの再構築

復号化されたメソッド本体ヘッダーと MSIL バイトは元の .NET アセンブリに適切に収まらない可能性があるため、最も簡単な方法は、新しいセクションとセクション ヘッダーを MassLogger に追加することです。 PE セクションのヘッダーとデータを追加する方法に関するリソースたくさんありますが、どれも自明ではなく、簡単に自動化することもできません。したがって、 JITMには、このプロセスを自動化するために次の Python 2.7 ヘルパー スクリプトも含まれています: Scriptsaddsection.py

図 16 に示すように、各メソッドのメソッド本体ヘッダーと MSIL を新しい PE セクションに追加すると、.NET メタデータを簡単に解析し、新しいセクション内の正しいメソッド本体を指すように各メソッドの RVA を修正できます。残念ながら、.NET メタデータと MethodDef テーブルを簡単に解析できる Python ライブラリは見つかりませんでした。したがって、 JITMには、部分的に実装された .NET メタデータ パーサー ( Scriptpydnet.py ) も含まれています。このスクリプトは、 pefileおよびvivisectモジュールを使用し、PE ファイルをMethodテーブルまで解析して、すべてのメソッドとそれに関連する RVA を抽出します。

FLARE という名前のセクションを追加する前後の Bin-123.exe
図 16: FLARE という名前のセクションを追加する前後の Bin-123.exe

最後に、すべてを結び付けるために、 JITMScriptfix_assembly.pyを提供して次のタスクを実行します。

  1. jitm.jsonで復元された各メソッドのメソッド本体ヘッダーと MSIL を「 section.bin 」という名前の一時バイナリ ファイルに書き込み、同時に、関連するメソッド トークンとセクション.binへのオフセットを記憶します。
  2. addsection.pyを使用してsection.binBin-123.exeに追加し、データをBin -123.fixed.exe などの新しいファイルに保存します。
  3. pydnet.pyを使用してBin-123.fixed.exeを解析し、MethodDef テーブルの各メソッド エントリの RVA フィールドを更新して、正しい RVA を新しいセクションに指定します。

最終的な結果は、部分的に再構築された .NET アセンブリです。このアセンブリを正しく実行するには追加の作業が必要ですが、マルウェアの高レベルの機能を理解するには、静的分析を実行するだけで十分です。

再構築されたメソッド0x0600043Eを見てみましょう。このメソッドは、マルウェア構成の復号化ロジックを実装しています。元の MSIL と比較すると、再構築された MSIL は、マルウェアがAES-256PKCS7パディング付きのCBCモードで使用していることを示しています。動的分析と静的分析を組み合わせることで、キーが「 Vewgbprxvhvjktmyxofjvpzgazqszaoo 」であり、IV が引数として渡されたBase64でエンコードされたバッファの一部であることも簡単に特定できます。

アセンブリを修正する前後のメソッド 0x0600043
図 17: アセンブリを修正する前後のメソッド 0x0600043

その知識があれば、マルウェアの構成を解読し、すべての HBI と NBI を復元するための簡単なツールを作成できます (図 18)。

                            BinderBytes: ああああああああああああああああああああああああああああああああ
バインダー名: Mzvmy_Nyrrd
BinderOnce: false
ダウンローダーファイル名: Hrebxs
DownloaderOnce: false
DownloaderUrl: Vrwus
メールアドレス: appfoil@outlook.com
メール クライアント: smtp.outlook.com
EmailEnable: 真
メールパス: services000
メールポート: 587
メール送信先: appfoil@outlook.com
メールSSL: 真
EnableAntiDebugger: false
EnableAntiHoneypot: false
EnableAntiSandboxie: false
EnableAntiVMware: false
EnableBinder: false
EnableBotKiller: false
EnableBrowserRecovery: true
EnableDeleteZoneIdentifier: false
EnableDownloader: false
EnableForceUac: false
EnableInstall: false
キーロガーを有効にする: true
EnableMemoryScan: false
EnableMutex: false
EnableScreenshot: false
EnableSearchAndUpload: false
EnableSpreadUsb: false
EnableWDExclusion: false
EnableWindowSearcher: false
実行遅延: 6
ExitAfterDelivery: false
FtpEnable: false
FtpHost: ftp://127.0.0.1
FTPパス:
FTP ポート: 21
FtpUser: フー
インストールファイル: Pkkbdphw
インストールフォルダ: %AppData%
InstallSecondFolder: Eqrzwmf
鍵:
ミューテックス: Ysjqh
PanelEnable: false
PanelHost: http://example.com/panel/upload.php
SearchAndUploadExtensions: .jpeg、.txt、.docx、.doc、
SearchAndUploadSizeLimit: 500000
SearchAndUploadZipSize: 5000000
自己破壊: false
送信間隔: 2
バージョン: MassLogger v1.3.4.0
WindowSearcherKeywords: ユーチューブ、フェイスブック、アマゾン、

図 18: 復号化された構成

結論

JIT コンパイラ フックを使用して MSIL を置き換えることは、静的分析をほとんど不可能にする強力な手法です。この手法は新しいものではありませんが、ConfuserEx のような広く利用されている保護機能を使用する代わりに、独自の適応策を実装しようとしている .NET マルウェアはあまり見たことがありません。願わくば、このブログ投稿とJITM によって、アナリストは MassLogger や同様の手法を使用する将来の亜種を打ち負かすためのツールと知識を手に入れることができます。

これがあなたを興奮させるタイプの仕事なら。また、マルウェア分析とリバース エンジニアリングに関して最先端の技術を推進することに力を入れている場合は、Front Line Applied Research and Expertise (FLARE) チームが最適な場所になる可能性があります。 FLARE チームは、楽しく刺激的な課題に日々直面しています。そして、これらの課題に真正面から取り組むために、より多くのチーム メンバーを常に探しています。 FireEye のキャリア ページをチェックして、当社の機会があなたにぴったりかどうかを確認してください。

貢献者 (アルファベット順)

  • Tyler Dean ( @spresec ): 投稿のテクニカル レビュー
  • Michael Durakovich: 投稿のテクニカル レビュー
  • Stephen Eckels ( @stevemk14ebr ): PolyHook を使用するための JITM の移植を手伝ってください
  • Jon Erickson ( @evil-e ): 投稿のテクニカル レビュー
  • Moritz Raabe ( @m_r_tz ): 投稿の技術レビュー

参照: https://www.mandiant.com/resources/blog/bypassing-masslogger-anti-analysis-man-in-the-middle-approach

Comments

Copied title and URL