FireEye Labs の難読化文字列ソルバー (FLOSS) を使用して、マルウェアから難読化文字列を自動的に抽出する

Simple string obfuscation example using the XOR operation news

紹介と動機

マルウェアの実行可能ファイルに対してstrings.exeを実行し、その出力によって IP アドレス、ファイル名、レジストリ キー、およびその他の侵害の痕跡 (IOC) が得られたことがありますか?すごい!ファイルが悪意があるかどうか、その使用目的、および他のインスタンスを見つける方法を判断するために、さらに分析を実行したり、高価な専門家を雇ったりする必要はありません。残念なことに、マルウェアの作成者はあなたの分析に気づき、阻止しようとしています。これらの作成者は実行可能ファイルを保護しようとしていますが、FireEye Labs Obfuscated Strings Solver (FLOSS) を使用してマルウェア実行可能ファイルから機密性の高い文字列を復元する方法を教えます。

マルウェア作成者がソフトウェアを保護するために使用する一般的なアプローチの 1 つは、パッキングです。プログラムをパックすると、実行可能ファイルが圧縮および/または難読化された形式に変換されます。パックされたマルウェアは、最初にアンパックされたデータを復元する必要があるため、分析を妨げる可能性があります。一方、パッキングは通常とは異なるため、単にパッキングされたファイルにフラグを立てることは、疑わしい実行可能ファイルを特定するための信頼できる方法です。パックされたファイルは、インポートされた関数の数が少ない、エントロピー レベルが高い、疑わしいセクション ヘッダーの特徴などの機能を介して簡単に検出できます。そのため、パッキングによって文字列が隠されますが、悪意のあるバイナリが目立たなくなります。

代わりに、攻撃者は多くの場合、バイナリ ファイル全体をパックすることなく、機密性の高い文字列を個別にエンコードします。これは、実行時にプログラムが使用前に文字列をデコードすることを意味します。たとえば、プログラムは、初期化ルーチン中に無条件に文字列をデコードしたり、文字列を使用する直前にデコードしたりできます。いずれにせよ、文字列はディスク上の実行可能ファイルには表示されず、ファイルを簡単に検出することはできません。リスト 1 は、各文字に 0x15 のキーを持つシングルバイト XOR を適用することによって、難読化された文字列をデコードする単純なデコード関数の擬似コードを示しています。

Simple string obfuscation example using the XOR operation
リスト 1: XOR 演算を使用した単純な文字列難読化の例

文字列を手動で作成することは、マルウェアの作成者が文字列を隠すためによく使用するもう 1 つの手法です。文字列を形成するために連続したバイト シーケンスを格納する代わりに、一連の命令が文字列をバイト単位で再作成します。 strings.exe は一連の印刷可能な文字を検索するため、文字がオペコード データに散在しているため、人間が判読できる文字列を識別することができません。ファイル システム パスやドメイン名などの文字列を非表示にすると、フォレンジック アナリストがファイルに悪意があるかどうかを判断するのが難しくなります。

図 1 は、IDA Pro のスクリーンショットで、スタック上に手動で作成された文字列「goodbye world」を示しています。この手法を「スタックストリング」と呼んでいますが、グローバル メモリやヒープにも同様に簡単に適用できます。

スタック上に手動で構築された文字列
図 1: スタック上に手動で構築された文字列

難読化された文字列に対抗する現在の方法

リバース エンジニアは、マルウェア内の難読化された文字列の解読を任されると、さまざまな可能性を秘めています。 2 つの従来の手法は、デバッガーを使用して文字列を回復するか、デコード関数を再実装することです。どちらのアプローチでも、アナリストは最初にデコード関数を手動で特定する必要があります。

デバッガの使用

IDA Pro などの逆アセンブラーでデコード ルーチンを特定した後、アナリストはデバッガーを使用して、デコードされた文字列を生成するすべてのコード パスを実行できます。ブレークポイントを設定し、プログラムの重要な場所で CPU フラグを操作することで、これを行うことができます。マルウェアが文字列をデコードすると、アナリストはこのデータを含むメモリ領域をダンプします。この手法は、マルウェアの文字列デコードの実装を使用します。マルウェアが正しく機能する場合、文字列を正しくデコードする必要があります。ただし、デバッグ手順は、関連するすべてのコード パスに対して実行するのが困難な作業になる場合があります。デコード ルーチンとインライン化されたデコード関数の複雑な初期化により、この手法はさらに複雑になります。

ブログ投稿FLARE Script Series: Automating Obfuscating String Decodingで説明されているように、 flare-dbg プロジェクトは、WinDbg を使用して文字列のデコードを自動化するのに役立ちます。

デコード ルーチンの再実装

別の静的解析手法は、ルーチンの逆アセンブルに基づいて、Python などのスクリプト言語でデコード ルーチンを再実装することです。これにより、アナリストは、バイナリ内の難読化されたすべての文字列にデコード スキームを柔軟に適用できます。ただし、コードの移植は面倒でエラーが発生しやすいプロセスです。さらに、難読化されたデータを抽出することは困難な場合があります。たとえば、難読化されたデータがデコード関数の初期化の前に操作された場合、手動で変換を再作成することは困難な場合があります。

スタックストリングの回復

難しいことではありませんが、IDA Pro でスタック文字列を手動で回復するのは面倒なプロセスになる可能性があります。 FLARE チームは、スタックストリングのリカバリを自動化するIDA Pro プラグインを提供しています。

実際の難読化の実装によっては、各回復方法にかなりの時間がかかる場合があります。残念ながら、マルウェアの作成者は、ソース コードにわずかな変更を加えるだけで、エンコーディング ルーチンを大幅に変更できます。したがって、アナリストは、文字列が難読化されたマルウェア サンプルごとに、これらの手順を手動で繰り返す必要があります。これらの文字列を抽出する自動化されたシステムは、FLARE などのリバース エンジニアリング チームにとって、毎月数十時間を節約します。

FLOSSのご紹介

FireEye Labs の難読化文字列ソルバー (FLOSS) は、Apache License 2.0 の下でリリースされるオープン ソース ツールです。 Windows Portable Executable ファイル内の難読化された文字列を自動的に検出、抽出、およびデコードします。 FLOSS は非常に使いやすく、マルウェアの大規模なコーパスに対して機能します。これは、 strings.exeツールと同じように実行します。 FLOSS は、既にバイナリ内の文字列を探しているマルウェア アナリスト、フォレンジック調査員、およびインシデント レスポンダーに役立ちます。

図 2 は、文字列が難読化されたマルウェアで実行された FLOSS の出力例を示しています。この実行可能ファイルの場合、図 3 に示す文字列の出力からは、有用な情報が得られません。

アナリストに貴重な情報を提供する FLOSS 出力例
図 2: アナリストに貴重な情報を提供する FLOSS の出力例
この実行可能ファイルのインジケーターを表示しない文字列ツールの出力
図 3: この実行可能ファイルのインジケーターを表示しない Strings ツールの出力

多くの難読化されたサンプルについて、FLOSS の出力はプログラムの機能に関する貴重な洞察を提供しますが、 strings.exeツールは有用な情報を提供しません。難読化された文字列には通常、コマンド アンド コントロール サーバーのアドレス、動的に解決されたインポートの名前、疑わしいファイル パス、その他の侵害の兆候 (IOC) など、最も機密性の高い構成リソースが含まれているため、FLOSS はより価値の高い文字列を抽出します。

実際、FLOSS はすべての静的 ASCII および UTF-16LE 文字列を任意のファイルから抽出できるため、 strings.exeの必要性を完全に排除します。また、FLOSS は難読化を解除した文字列と、PE ファイルから復元されたスタック文字列も提供します。つまり、もはやstrings.exeを実行する本当の理由はありません。

FLOSSのしくみ

FLOSS は高度な静的解析技術を組み合わせて、デコード機能を自動的に検出し、難読化された文字列を復元します。アルゴリズムの詳細は次のとおりです。

1. プログラムを分析して、データ、コード、関数、基本ブロック、相互参照などを特定します。

FLOSS はvivisectを使用して、プログラムの制御フローを逆アセンブルし、分析します。 Vivisect は純粋な Python で書かれたプログラム解析ライブラリです。これは、オープンソースの IDA Pro インスタンスのように考えることができます。

2. ヒューリスティックを使用して、潜在的なデコード ルーチンを見つけます。

FLOSS はヒューリスティックを定義するためにプラグインを使用します。各ヒューリスティックは、関数がデコード ルーチンである可能性をスコア付けします。このアプローチにより、私たち (およびあなた) は FLOSS の識別機能を簡単に拡張できます。これまでのところ、たまたま非常に単純な最も効果的なヒューリスティックは次のとおりです。

  • 関数に非ゼロ化 XOR 演算が含まれている
  • 関数への多くのコード相互参照があります

3. 基本ブロックと関数の間のすべてのコード パスを力ずくでエミュレートします。

FLOSS は vivisect の CPU とメモリ モジュールを使用して x86 命令をエミュレートします。各実行可能ファイルは、Python ランタイムでエミュレートされます。このステップの目標は、デコード関数に渡される引数を取得することです。 FLOSS は、実行可能ファイル内のすべてのコード パスを単一パスのブルート フォース方式でエミュレートします。

4. 適切な時点でのエミュレータの状態 (レジスタとメモリ) のスナップショット。

FLOSS は、可能なデコード関数の呼び出しを検出するたびに、メモリとレジスタの状態のスナップショットを取得します。このトリックにより、FLOSS は、呼び出し規則や引数の数など、関数に関する詳細を知らなくても、関連するすべての関数入力を収集できます。

5. エミュレーター状態のスナップショットを使用して、デコーダー機能をエミュレートします。

FLOSS は、可能なデコード機能のエミュレーションを実行する前に、前のステップで作成した各スナップショットに「戻ります」。 FLOSS は、収集されたすべてのエミュレーター状態のスナップショットを使用して、各デコード ルーチンをエミュレートします。ルーチンが戻るか、または 10,000 命令がエミュレートされるまで、エミュレーションは停止します。これにより、プログラム エミュレーション中の無限ループが回避されます。これにより、FLOSS はデコード ルーチンによって導入された CPU とメモリの状態の変化を識別できます。

6. 関数エミュレーション前後のメモリ状態を比較します。

FLOSS は、デコーディング関数をエミュレートする前と後に、エミュレータのメモリ セグメントを比較します。これにより、内容が異なるバイト シーケンスのリストが生成されます。デコード ルーチンによって一部のデータが公開された場合、難読化が解除されたデータはこれらのバイト シーケンス内にある必要があります。

7. メモリ状態の違いから人間が読める文字列を抽出します。

異なるバイト シーケンスごとに、FLOSS は人間が読めるすべての文字列を ASCII および UTF-16LE 形式で抽出します。これがユーザーに表示されるものです。

インストール

https://github.com/fireeye/flare-floss/releasesで、Windows および Linux 用の FLOSS のスタンドアロン実行可能ファイルを提供しています。このツールは純粋な Python で記述されており、ソース コードは GitHub のhttps://github.com/fireeye/flare-flossで入手できます。

標準の Python パッケージ インストーラーpipを使用して FLOSS をインストールすることもできます。これにより、実行可能な floss.exe (Windows の場合) またはfloss (Linux の場合) が $PATH に追加されます。 3 番目のオプションとして、ソースから FLOSS をインストールできます。最新のインストール手順については、GitHub ページを参照してください。

使用法

静的 ASCII および UTF-16LE 文字列、難読化された文字列、およびスタック文字列を実行可能ファイルから抽出するには、次のコマンドを実行します。

$ floss.exe /path/to/binary

FLOSS の出力から静的文字列を除外する場合は、 –no-static-stringsスイッチを指定します。

$ floss.exe –-no-static-strings /path/to/binary

-qスイッチを使用すると、FLOSS のヘッダーとフォーマット出力を抑制することができます。このモードは、grep またはその他のツールへのパイプに適しています。

$ floss.exe –q /path/to/binary

最小限の長さの文字列のみを表示するには、 -nスイッチを使用します。デフォルトの最小文字列長は 4 です。

$ floss.exe –n 8 /path/to/binary

デコード関数のオフセットがわかっている場合 (またはコンマ区切りの関数オフセットのリストがある場合)、FLOSS に-fスイッチを使用して提供された関数のみを分析するように指示できます。

$ floss.exe /path/to/binary -f 0xF005BA11

$ floss.exe /path/to/binary -f 0xF005BA11,0xF00B005E

-iスイッチを使用して、デコードされた文字列で IDA Pro IDB データベースに注釈を付ける IDAPython スクリプトを作成します。

$ floss.exe -i SCRIPTOUTPUTPATH /path/to/binary

FLOSS は、 –rスイッチを使用して、radere2 スクリプトを作成することもできます。

$ floss.exe -r SCRIPTOUTPUTPATH /path/to/binary

-hスイッチは、FLOSS のすべての機能のヘルプ全体を表示します。

$ floss.exe -h

概要

このブログ投稿では、FLARE チームのマルウェア分析コミュニティへの最新の貢献を紹介しました。 FLOSS は、Windows Portable Executable ファイル内の難読化された文字列を自動的に検出、抽出、デコードするオープンソース ツールです。コミュニティは、プログラム内の文字列を一般的に難読化して静的および動的分析を抑止するマルウェア作成者に対抗するために、このタイプのツールを必要としています。 FLOSS は、ルーチンのデコードによって難読化が解除された文字列を抽出するだけでなく、スタック文字列を復元し、すべての静的文字列を取得できます。

次のマルウェア分析で FLOSS を試してみてください。このツールは非常に使いやすく、フォレンジック アナリスト、インシデント レスポンダー、リバース エンジニアに貴重な情報を提供します。ツールを気に入っていただけた場合、使用中に問題が発生した場合、またはその他のコメントがある場合は、プロジェクトの GitHub ページ ( https://github.com/fireeye/flare-floss/) からご連絡ください。

参照: https://www.mandiant.com/resources/blog/automatically-extracting-obfuscated-strings

Comments

Copied title and URL