
IDA Pro プラグインで、バイナリ内をクエリベースで検索するためのもので、主に脆弱性調査に役立ちます。
VulFi(Vulnerability Finder)ツールは、IDA Proのプラグインであり、バイナリのバグハンティングを支援するために使用できます。主な目的は、最も興味深い関数(strcpy、sprintf、systemなど)へのすべてのクロスリファレンスを一つのビューで提供することです。Hexraysデコンパイラが使用できる場合、脆弱性研究の観点から興味深くない関数呼び出し(たとえば strcpy(dst,"Hello World!") など)を除外しようとします。デコンパイラがない場合、ルールははるかに単純になり(アーキテクチャに依存しないように)、最も明白なケースのみを除外します。
更新情報の詳細は変更履歴を参照してください。
vulfi.py、vulfi_prototypes.json、vulfi_rules.jsonファイルをIDAプラグインフォルダに配置します(cp vulfi* <IDA_PLUGIN_FOLDER>)。
VulFiを実行する前に、扱っているバイナリについて十分に理解しておいてください。すべての標準関数(strcpy、memcpyなど)を特定し、それに応じて名前を付けてください。プラグインは大文字小文字を区別しないため、MEMCPY、Memcpy、memcpyはすべて有効な名前です。ただし、関数の検索は完全一致が必要であることに注意してください。つまり、memcpy?やstd_memcpy(その他のバリエーション)は標準関数として検出されず、潜在的な脆弱性を探す際に考慮されません。未知のバイナリを扱っている場合は、まずコンパイラオプションを設定する必要があります(Options > Compiler)。その後、VulFiは明らかな誤検出(例えば、最初のパラメータが定数文字列であるprintfの呼び出しなど)を可能な限りフィルタリングします。プラグインは特定のアーキテクチャに依存しないように作られていますが、一部のプロセッサでは型指定が完全にサポートされていない場合があります。そのような場合、VulFiは潜在的に危険な標準関数へのすべてのクロスリファレンスを単純にマークし、手動分析に進めるようにします。そのような場合、プラグインの追跡機能を活用できます。
スキャンを開始するには、トップバーメニューからSearch > VulFiオプションを選択します。これにより、新しいスキャンが開始されるか、idb/i64ファイルに保存された以前の結果が読み込まれます。データは、データベースを保存するたびに自動的に保存されます。
スキャンが完了するか、以前の結果がロードされると、以下のカラムを含むビューがテーブルとして表示されます:
Not Checkedが割り当てられます。他のステータスはFalse Positive、Suspicious、Vulnerableです。これらはアイテムの右クリックメニューから設定でき、その関数呼び出しの手動レビューの結果を反映する必要があります。High、Medium、Low(スキャナーがすべてのパラメータを適切に識別できなかった場合はInfo)。優先度は他のルールとともにvulfi_rules.jsonファイルで定義されています。idb/i64ファイル内にデータがない場合、またはユーザーが新しいスキャンを実行することを決定した場合、プラグインはデフォルトのルールを使用してスキャンを実行するか、カスタムルールファイルを使用するかを尋ねます。既存のデータで新しいスキャンを実行しても、以前に保存された結果と同じ名前のルールによって特定されたアイテムは上書きされないことに注意してください。したがって、スキャンを再度実行しても、既存のコメントやステータスの更新は削除されません。

VulFiビュー内の右クリックコンテキストメニューから、結果からアイテムを削除したり、すべてのアイテムを削除したりすることもできます。この操作を行うと、コメントやステータスの更新は失われることに注意してください。
バージョン2.1以降、VulFiは複数の選択されたアイテムに対する一括操作もサポートしています。これにより、複数のアイテムに特定のステータスを設定したり、削除したり、同じコメントを追加したりできます。操作が正しく更新されないことがあります。その場合は、UIを(Ctrl+U)数回リフレッシュして変更が反映されるまで続けてください。
検出された脆弱性の可能性がある関数のインスタンスを調査したい場合は、目的の行の任意の場所をダブルクリックするだけで、IDAが潜在的に興味深いと特定されたメモリ位置に移動します。右クリックしてSet Vulfi Commentオプションを使用すると、そのインスタンスにコメントを入力できます(ステータスを正当化するためなど)。
プラグインはカスタムルールの作成も可能です。これらのルールはIDAインターフェース内で定義するか(単一関数に最適)、カスタムルールファイルとして提供できます(複数の関数をカバーするルールに最適)。
分析中に特定されたカスタム関数をトレースしたい場合は、その関数の本文内で右クリックし、Add <name> function to VulFiを選択します。現在の逆アセンブリ/デコンパイラビュー内で関数名をハイライトして右クリックすることもでき、関数本文に切り替える必要がありません。

複数のルールセットを含むカスタムファイルをロードすることも可能です。以下の構造を持つカスタムルールファイルを作成するには、含まれているテンプレートファイルこちらを使用できます。
[ // An array of rules
{
"name": "RULE NAME", // The name of the rule
"function_names":[
"function_name_to_look_for" // List of all function names that should be matched against the conditions defined in this rule
],
"wrappers":true, // Look for wrappers of the above functions as well (note that the wrapped function has to also match the rule)
"mark_if":{
"High":"True", // If evaluates to True, mark with priority High (see Rules below)
"Medium":"False", // If evaluates to True, mark with priority Medium (see Rules below)
"Low": "False" // If evaluates to True, mark with priority Low (see Rules below)
}
}
]
以下は、関数mallocへのすべてのクロスリファレンスを探し、そのパラメータが定数でないかどうか、および関数の戻り値がチェックされているかどうかを確認するルールの例です:
{
"name": "Possible Null Pointer Dereference",
"function_names":[
"malloc"
],
"wrappers":false,
"mark_if":{
"High":"not param[0].is_constant() and not function_call.return_value_checked()",
"Medium":"False",
"Low": "False"
}
}
Loop Check - すべてのループをマークします。この場合、param[0]はループのカウンター(検出された場合)、param[1]はカウンターがチェックされてループを終了する条件です。Array Access - すべての配列アクセスをマークします。この場合、param[0]は配列、param[1]はインデックスです。ルールを作成する際には、通常の関数パラメータと同じ関数を使用できます(param[<index>]に対して呼び出せるものはすべて)。
param[<index>]: 関数呼び出しのパラメータにアクセスするために使用(インデックスは0から始まる)function_call: 関数呼び出しイベントにアクセスするために使用param_count: 関数に渡されたパラメータの数を保持param[<index>].is_constant()param[<index>].number_value()param[<index>].string_value()param[<index>].set_to_null_after_call()function_call.return_value_checked(<constant_to_check>)param[<index>].used_in_call_<before|after>(["function1","function2"])function_call.reachable_from("<function_name>")param[<index>].is_sign_compared()param[<index>].used_as_index()param[2].number_value() > 5"%s" in param[1].string_value()not param[1].is_constant()function_call.return_value_checked(param_count)function_call.return_value_checked()all(not p.is_constant() for p in param[2:])any(p.is_constant() for p in param)Truestrlenでチェックされていない関数へのすべての呼び出しをマーク: not param[1].is_constant() and not param[1].used_in_call_before(["strlen"])read関数から到達可能な関数へのすべての呼び出しをマーク: Low優先度でマークされます。これは、すべてのパラメータを正しく取得できなかった場合にクロスリファレンスを見逃さないための方法です(主に逆アセンブリモードに適用されます)。Ctrl+Uショートカットを使用して手動でビューをリフレッシュしてください(数回)。function_call.reachable_from("read")