Flameワーム(Win32/FlamerとしてESETでは検出)は、今年の最も興味深い標的型脅威の1つです。
これについては、すでにいくつかの記事が公開されていますが、そのメインモジュール(mssecmgr.ocx)の内部構造に関する事実の多くはまだ明らかにされていません。
この記事では、このコンポーネントの実装方法の一部について光を当てたいと思います。
Stuxnetのコード解析は、ワームの完全な機能を理解するためにかなりの労力が必要でした。
Duquのときは、その構造と実装がStuxnetと非常に近かったので、Duquの解析プロセスは非常に簡単でした。しかし、Flameの場合は別でして、構成情報のための内部ストレージと共に多くの相互接続モジュールがあり、また、未だ知られていない形式の動作を持っています。
これらの困難に負けず、我々は、メインモジュールmssecmgr.ocxについていくつかの興味深い詳細を明らかにしていこうと思います。
StuxnetとDuquの相互接続
FlameがStuxnetやDuquと同じ種類のマルウェアであることは明らかです。
これらの悪意のあるプログラムは、精巧なアーキテクチャと実装方法により非常に複雑なロジックで実装されています。これらは、攻撃されたシステム上で永続的なプレゼンスを維持することを意図しています。
C++によるオブジェクト指向型のFlameのプログラミングはコード解析をより複雑にさせています。なぜなら、解析のプロセス上、Flameのワークフローロジックだけでなくコンパイラのロジックをも再構築を必要とするからです。
例えば、再構築されたコールメソッド Rc4_GetBufferSize は次のようになります。
静的解析で一般的に遭遇する問題の1つは、VTABLEの正確な値を持つ単一値の関係を確かめることです。そして、それはVPTRポインタによって呼び出されるでしょう。
静的解析の過程で我々は、C++オブジェクトのエミュレーションのために構造の定義に関連するメソッドを使用します。
このメソッドは、次の資料に詳細に記載されています "英語記事:Reversing C++ programs with IDA pro and Hex-rays"。
DuquはStuxnetと同じソースコードに基づいています。
"mssecmgr.ocx"はStuxnetやDuquとは異なったソースコードを使用し開発された
Flameのメインモジュール(以下、この記事ではmssecmgr.ocxを指すことにします)のバイナリ解析に基づき、マルウェアの開発者は、StuxnetやDuquとは異なったソースコードを使用したことを結論することができます。
mssecmgr.ocxは、オブジェクト指向のコードを多用しますが、StuxnetはとDuquの両方で使用されている方法とはかなり異なります。
我々は特定のオブジェクトの実装方法を見れば、それらがはっきりと異なっていることがわかります。
例えば、ここで、すべてのマルウェアの中でのオブジェクトの型として最も頻繁に使われているであろう文字列型を表すオブジェクトを考えてみましょう。
我々は以下の図にStuxnetとFlameの文字列型の記述を表しましたが、それらは明らかに全く異なっています。同じなのは、オブジェクトの実装方法です。
[図1:StuxnetとFlameの文字列型の構造体]
このような型は、ファイル、ファイルマッピング、同期オブジェクト、メモリバッファ、メモリストリームなどと関連しており、Stuxnetに実装されているものとは異なっています。
Flameのコードのもう1つの特徴は、異なる型のオブジェクトへのポインタを処理するために、オブジェクトのようなスマートポインタを頻繁に使用することです。
「開発者の視点」からのアプローチと分けて、スマートポインタを利用することでコードがかさみ、コード解析を難しくさせるのです。
メインモジュールの解析
Flameは、Windowsファイルシステム内のさまざまなファイルにそのコンポーネントを格納します。それはファイルを格納するために、3つの異なる命名方式を使用しています。
このマルウェアは、構成情報およびそれが実行される環境に基づいて、それぞれのケースで特定のスキームを選択します。
次の表は、これらの命名方式に関する情報が含まれています。
[表1:Flameの命名方式]
Flameのスタートアップ
このマルウェアがシステムにインストールされているとき、それはシステムレジストリにLSA認証パッケージとして登録されています。
この結果、システム起動時にlsass.exeがシステムプロセスの一部としてmssecmmgr.ocxをロードします。
興味深いことに、LSA認証パッケージは、LSAのインターフェイスとしてのルーチンの特定のセットを公開する必要があります。これらのインタフェース・ルーチンはいずれもFlameの主要なモジュールで実装されていません。
FlameのOSがサポートされているバージョン
このマルウェアのメインモジュールが起動されるとき、それはオペレーティングシステムのバージョンがマルウェアが動作できるバージョンかどうか、またマシンがセーフモードで読み込まれたかどうかのようないくつかのチェックを行います。
[図2:スタートアップ時のFlameの初期チェック]
このマルウェアは64bitのOSでは動作しませんが、Windows2000以上のすべてのWindowsで動作します(Windows 8は除きます)。
アンチウイルスソフトでの検出
Flameのメインモジュールがロードされたとき、自身が感染したマシンにセキュリティソフトウェアがインストールされているかチェックを行います。そのチェックするセキュリティソフトウェアのリストは後述する構成情報に格納されています。
我々が解析したサンプルでは、およそ320の異なるソフトウェアの名前がありました。例えば、パーソナルファイアウォール、アンチウイルスソフトウェア、ペアレンタルコントロール、などです。
構成情報で定義されているいくつかの条件に応じて、特定のセキュリティソフトウェアがシステムに発見されている場合はマルウェアが実行を停止することがあります。検出されたすべての製品がその機能に応じてグループに分割されています。
・パーソナルファイアウォール
・HIPS
・アンチウイルスソフトウェア
・ネットワークパケット解析ソフトウェア
・ペアレンタルコントロールシステム
・システムモニタ
・DLPシステム など
プロセスへの挿入
どのようにマルウェアが感染したシステム内のプロセス間で伝播するかを見ていきましょう。
その前に、Flameのインジェクション技術に関する文献を紹介しておきます"英語記事:Inside Flame: You Say Shell32, I Say MSSECMGR"。他のプロセスのアドレス空間にコードを挿入できるようにするために、マルウェアは次のような標準APIルーチンを慎重に利用します。
・VirtualAllocEx:ターゲットプロセスに挿入されたモジュールのメモリを割り当てる。
・WriteProcessMemory\ReadProessMemory:コードを挿入する。
・CreateRemoteThread\RtlCreateUserThread:挿入されたモジュールを制御する
結果として、いくつかの点でターゲットプロセスのアドレス空間は次のようになります。
[図3:挿入中のターゲットプロセスのアドレス空間のレイアウト]
Flameの検出を難しくしている要因として、shell32.dllを用いた興味深い仕掛けがあります。図のようなコードを挿入することで、shell32.dllのマッピングシステムライブラリによってFlameはメモリ領域を割り当てられます。デコンパイルすることで、このコードが原因であると考えることができます。
[図4:shell32.dllの再利用メモリ領域]
挿入されたモジュールにより必要なシステム構造の全てを作成し、その結果、合法的にロードされたモジュールのように見えるのです。
全てのデータとコードがターゲットのアドレス空間に書き込まれると、FlameはCreateRemoteThredもしくはRtlCreateUserThredのAPIを呼び、エントリポイントとしてスタブ2の指定を、パラメータとしてデータを挿入することでリモートスレッドを作成します。
スタブ2はローダコードが含まれています。その目的は、以下のようなプロセスにより、挿入されたモジュールをアドレス空間にマップするためです。
・図のようなメモリ領域の割り当て
・ベースの再配置の適用
・インポートアドレステーブルの初期化
・エントリポイントの呼び出し
それは全ての必要なルーチンや補足的な文字列定数のアドレスを含むヘルパー構造体として挿入されたデータを使います。ここにある図は、この構造体の初期状態を定義するコードの一部です。
[図5:補足的な構造体の初期状態]
スタブ2がすることのもう一つはスタブ1のコードでmsvcrt.dllのエントリポイントをフックすることです。なぜ、そして、どのようにこのフック処理が実装されているかは後述します。
スタブ1の主な作業は、msvcrt.dllのエントリポイントが呼び出されるたびに、挿入されたモジュールのエントリポイントを呼び出すことです。
その結果、挿入されたモジュールは、msvcrt.dllが受け取る全てのイベントを受け取る事ができます。
マルウェアに、合法的にロードされたモジュールが作成するのと同様の実行環境を部分的に再作成することができます。Flameは非常に珍しい方法でmsvcrt.dllのエントリポイントをフックします。コードを継ぎ合わせる代わりに、PEB(プロセス環境ブロック)にあるInLoadOrderModuleListでPEB_LDR_DATA構造体の対応するフィールドを上書きします。挿入が完了した後、マルウェアはプロセスのアドレス空間内で侵入の痕跡をクリーンアップします。
Flameの構成情報
Flameの構成情報のストレージは非常に複雑で、実装レベルでStuxnetやDuquのものと大きく異なります。そのマルウェアが最初にシステム内に侵入すると、全ての構成データはメインモジュールに属するリソースの内部に含まれます。
我々がリソースディレクトリ内のID 146をもつリソースとして注目しているFlameのメインモジュールを見てください。ここが全ての構成データが格納された場所です。
マルウェアのバージョンに応じてリソースのサイズは異なります(37KBから3MBまであります)。単純なバイナリファイルで構成データを格納するStuxnetやDuquと違い、Flameは、解析することを難しくさせる、より洗練された種類のストレージを採用しています。
構成情報へのアクセスできるようにするために、リソースを復号し、その復号化データを解凍する必要があります。図6に示したように暗号化アルゴリズムは、かなり単純です。
[図6:Flameのリソースの複合化アルゴリズム]
復号するとデータをデータ圧縮アルゴリズムの膨張モードで解凍します。
したがって、そのマルウェアは小さなデータ部分(それぞれがKB未満)を解凍するように進行します。サンドボックスをバイパスするマルウェアは、その間、10ミリ秒待つためにスリープAPIルーチンを呼び出します。
これは解凍のプロセスを非常に快活にさせます。
[図7:リソースの解凍アルゴリズムに遅延を挿入している様子]
復号化データの解凍後、遂に、Flameは以下に定義したバイト配列に置換します。
[図8:解凍された構成データを置換するバイト配列]
全てのFlameの構成データは以下の構造でフォーマットされた特別なブロックに分割されています。
[図9:Flameの構成データの基本的なブロック構造]
ここで、ブロックのバイトはブロック内に含まれる情報の型を示しています。ブロックには2つの種類があります。
・構成情報の項目について補足情報を含むブロック
・構成情報の項目の値を含むブロック
データフィールドは、以下に示したような構成情報を含んだブロックのように構成されています。
[図10:補足情報を含んだFlameの構成データの基本的なブロック構造]
すなわち、それは項目のデータが入ったブロックのオフセットや次の構成データ項目上の補足情報を含んだデータのオフセット、更には項目の名前で指定します。
ルートブロックは、構成データの先頭から0x1Aのオフセットに位置しています。次の図で、構成項目であるRTS.MEDIA_SETUP.FILES_TO_DELETEについて記述したサンプルのブロックをお見せします。
[図11:Flameの構成データの基本ブロック]
構成情報の項目が無名だったStuxnetやDuquと違い、Flameの場合、マルウェアの研究者たちは項目名がFlameの機能の理解を容易にするという利点を得ることができました。
構成情報の項目のデータの型はブロックのバイト数によて定義できるようです。ここに、異なる項目の型に対応したブロックのバイト数について、いくつかを挙げます。
・0x08 - DWORD(4バイトの整数)
・0x06 - WORD(2バイトの整数)
・0x09 - QWORD(8バイトの整数)
・0x05 - NULLで終わるUnicode文字列
・0x04 - 生のバイナリデータ
・0x03 - 項目を説明しているブロック(図10を参照)
・0x02 - ルートブロック
数種類の状態に依って、そのマルウェアがシステムに感染するときに、mscrypt.da0もしくはwpgfilter.da0という名前のファイルに構成情報を格納します(表1の対応する部分を見てください)。
我々はWin32/Flamerの詳細なコード解析を続けます。すぐに新しい情報を提供できる見込みです。
出典:blog.eset.com