※ 本ブログは、2021年12月9日にHP WOLF SECURITY BLOGにポストされたEmotet’s Return: What’s Different?の日本語訳です。
11月、HP Wolf Securityの一部であるHP Sure Click Enterpriseは、ある組織に対する大規模なEmotetキャンペーンを隔離しました。図1は、ユーザーが悪意のあるマクロを含むExcelのEメール添付ファイルを開いた様子を示しています。このマクロは cmd.exe を生成し、Web サーバーから Emotet のペイロードをダウンロードして実行しようとしました。Eメールで配信されるマルウェアは極めて一般的であるため、HP Sure Clickは、Eメールで配信されたファイルを自動的に信頼できないものとして扱います。ユーザーが添付ファイルを開くと、HP Sure Clickはファイルをマイクロ仮想マシン(micro-VM)に隔離し、ホストが感染するのを防ぎました。また、HP Sure Clickは、マイクロVM内での悪意ある動作を検知し、VM内で起こったことを記述したアクティビティ・トレースを含むアラートを生成して、顧客のセキュリティ・チームに送信しました。(図2)
            
        
    
    図1 - ユーザーが悪意のあるEmotetスプレッドシートを開いたことを示すアラートのタイムライン
    
            
        
    
    図2 - HP Sure Clickで取得したビヘイビアトレースのスニペット
    
2021年1月と2021年11月中旬に作成された2つの解凍済みEmotetサンプルを使用し、コードの違いをハイライトすることで、新しいコードに焦点を当てた解析を行いたいと考えました。これには、マルウェアの構造を分析し、コードの類似性に基づいて分類するThreatrayを使用しました。このサービスは、2つのマルウェアサンプル間の機能の違いを見つけて、それをハイライトすることもできます。
| 日付 | SHA256 Hash | 
| 2021-01-26 | 61a47ebee921db8a16a8f070edcb86b5efd47a8d185bf4691b57e76f697981f9 | 
| 2021-11-16 | ba758c64519be23b5abe7991b71cdcece30525f14e225f2fa07bbffdf406e539 | 
ThreatrayのAPIを使用してコードの類似性を取得すると、両サンプルの関数アドレスの表が返されます。双方のサンプルの列に関数アドレスがある場合、類似した関数が見つかったことを意味します。2つのEmotetサンプルを分析した結果、246個の関数のうち80個が類似していることがわかりました。これは、残りの関数がコードの変更や難読化をしている可能性を意味します。
            
        
    
    図3 - 類似した関数を示すThreatrayの出力
    
分析をさらに効率化するために、Threatrayの結果に基づいてIDCスクリプトを作成し、既知の関数を緑色に着色しました。こうすることで、マルウェアをリバースする際に、未知の領域に集中することができます。
            
        
    
    図4 - 既知の関数を緑で示した2021年11月 Emotet サンプルのIDA Proによる逆アセンブル
    
Emotet がその機能を隠す方法の 1 つは、ランタイムに Windows API 関数を解決することです。つまり、関数名はインポート アドレス テーブルから隠される、あるいは文字列として隠されます。目的の API 関数を見つけるために、Emotet は代わりにハッシュを使用します。ハッシュは、解決ルーチンに渡され、そこで DLL のすべてのエクスポートされた関数のハッシュと比較されます。2 つのハッシュが一致すると、DLL 内の正しい関数とアドレスが見つかり、その名前を参照せずに呼び出すことができます。
            
        
    
    図5 - EmotetのWindows APIラッパー関数
    
これらのラッパー関数は類似のものとして分類されないので、Windows API関数を解決するPythonスクリプトを書きました。11月16日のEmotetサンプルでは、109種類の関数を解決し、注釈を付けることができました。また、2021年1月のサンプルについては、サンプル間のAPI関数の違いを比較するために関数を解決しました。以下の表は、それぞれに固有のAPI関数の一覧です。
| 2021年1月 | 2021年11月 | 
| CryptAcquireContextW | BCryptCloseAlgorithmProvider | 
| CryptCreateHash | BcryptCreateHash | 
| CryptDecrypt | BcryptDecrypt | 
| CryptDuplicateHash | BcryptDeriveKey | 
| CryptDestroyHash | BcryptDestroyHash | 
| CryptDestroyKey | BcryptDestroyKey | 
| CryptGenKey | BcryptDestroySecret | 
| CryptEncrypt | BcryptEncrypt | 
| CryptExportKey | BcryptExportKey | 
| CryptGetHashParam | BcryptFinalizeKeyPair | 
| CryptImportKey | BcryptFinishHash | 
| CryptReleaseContext | BcryptGenRandom | 
| CryptVerifySignatureW | BcryptGenerateKeyPair | 
| CryptDecodeObjectEx | BcryptGetProperty | 
| HeapAlloc | BcryptHashData | 
| MultiByteToWideChar | BcryptImportKey | 
| WideCharToMultiByte | BcryptImportKeyPair | 
| RtlRandomEx | BcryptOpenAlgorithmProvider | 
| BcryptSecretAgreement | |
| BcryptVerifySignature | |
| RtlAllocateHeap | |
InternetQueryOptionW 
  | 
API関数の違いとしては、新しいEmotetサンプルではBcrypt暗号化関数を使用するようになりました。2021年1月の Emotet サンプルは、advapi32.dll の暗号化関数を使用していました。この変更の説明は、Microsoftが古いAPIを非推奨とし、現在は新しいAPIへの切り替えを推奨しているため、Emotetの開発者が新しい暗号化APIに切り替えたというものです。
暗号の変更に加えて、Emotet はヒープ メモリの割り当てに関数 RtlAllocateHeap を使用するようになりました。通常、プログラムは HeapAlloc を呼び出し、次に RtlAllocateHeap を呼び出します。各 Emotet バイナリには、暗号化された設定情報が含まれており、それらはランタイムに復号化されてヒープに保存されます。これまでは、マルウェアをデバッグする場合、HeapAllocにブレークポイントを設定して、マルウェアのコマンド&コントロール(C2)アドレスなどの暗号化されていない情報を見ることができました。しかし、最新のEmotetサンプルでは、マルウェアが代わりにRtlAllocateHeapを呼び出すため、この方法は使えません。ブレークポイントをRtlAllocateHeapに変更するだけで、期待通りの結果を得ることができます。しかし、この小さな変更により、自動分析システムがマルウェアから暗号化されていない情報を抽出できなくなる可能性があり、そのためアップデートが必要になります。
Threatrayの結果で特定された関数に、緑色のラッパー関数を加えると、246中167関数となります。残りの関数の中には、興味のない非常に小さな補助的な関数もあれば、手作業で比較すれば古いEmotetのサンプルの中にすでに見つけられる関数もあります。しかし、なぜこれらの機能が最初は類似しているとマークされなかったのでしょうか。これには2つの理由が考えられます。まず、Emotetでは制御フローを難読化するためにswitch case文を使用して正しい順序で関数を呼び出していますが、これを静的解析で解決するのは容易ではありません。
            
        
    
    図7 - switch case文による難読化を示すコントロールフローグラフ
    
次に、2つ目のEmotetサンプルでは、古いサンプルに比べて、より多くの関数がフラット化されていることに気づきました。これは、より多くの関数が、サブ関数の中に入れ子になっているのではなく、一箇所で呼び出されていることを意味しています。これは、制御フローの変化につながり、古いEmotetサンプルとの類似性が低下します。図8は、2021年1月のサンプルで、ヒープ上にメモリを確保し、文字列を作成した後にメモリを解放するサブ関数を呼び出している様子を示しています。
            
        
    
    図8 - サブ関数を呼び出しがさらなる実行とAPIコールにつながる2021年1月のサンプル
    
最近のサンプルではこのサブ関数が解決され、メモリの割り当てと文字列の合成のための関数呼び出しがメイン関数に移されています。(図9)
            
        
    
    図9 - サブ関数の代わりに直接ファンクションコールを使用する2021年11月のサンプル
    
我々の分析によると、Emotet は約10ヶ月の休止期間中に変化しました。更新された暗号ライブラリの使用に加えて、メモリの割り当てやEmotetのコードの一部の機能構造に小さな変更がありました。しかし、マルウェアの大部分は同じであり、既存の機能がシステムを危険にさらすのに十分であることを示しています。私たちの目的は、2つのサンプル間の変化を迅速かつ効率的にハイライトする方法を示すことだったので、これは最終的な分析ではありません。Emotetのさらなる分析をサポートするために、この記事で使用したIDAデータベースとPythonスクリプトを共有します。
Author : Patrick Schläpfer
監訳:日本HP