Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
fnprint — バイナリ内の関数を、バイト列の見た目ではなく動作内容でマッチングします。マイクロ実行による挙動ベースの関数フィンガープリンティング。 | Kitploit
ツール/GitHubGitHub/1rhino2/fnprint
脆弱性分析動的コード分析 (DAST)リバースエンジニアリングマルウェア分析バイナリ解析ファームウェア解析
GitHub1rhino2/fnprint

fnprint

バイナリ内の関数を、バイト列の見た目ではなく動作内容でマッチングします。マイクロ実行による挙動ベースの関数フィンガープリンティング。

リポジトリを見る
444371日前未レビュー
ウェブサイト

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

fnprint

fnprint は、バイナリ内の関数を、そのバイト列や制御フローグラフの見た目ではなく、関数が何をするかでマッチングします。各関数を小さなエミュレータ上ででっち上げの入力とともに実行し、生じる副作用を記録し、その振る舞いをフィンガープリントへとハッシュ化します。同じように振る舞う2つの関数は、たとえ異なるコンパイラや異なる最適化レベルでビルドされていても、似たフィンガープリントを得ます。

この方法を取る理由: バイトシグネチャ (FLIRT、FunctionID) はコードが再コンパイルされた瞬間に壊れ、CFG マッチャー (BinDiff、Diaphora) は -O0 と -O3 の間で揺らぎます。振る舞いはそのどちらにもずっとうまく耐えます。

今のところ x86-64 ELF のみです。信頼する前に 限界 を参照してください。

デモ

fnprint がストリップされ、別の方法でコンパイルされたバイナリ内の関数を命名する様子

ストリップされたバイナリと、すでに名前を付けているもののコーパスを指定します:

root@kitploit:~
$ strip --strip-all mystery.so
$ nm mystery.so
nm: mystery.so: no symbols

$ fnprint index libz.so -o corpus.db          # a build you have symbols for
$ fnprint query mystery.so --corpus corpus.db
named 9 function(s):
  0x000022f9  100.0%  adler32_z
  0x00002a8d  100.0%  compress2
  0x0000ad5d  100.0%  inflateBackEnd
  0x0000adc4   86.7%  inflate_fast
  0x00002e67   80.5%  crc32_z
  ...

この実行は、完全にストリップされた -O0 ビルドを -O2 のコーパスから命名したものです。最適化レベルが異なり、シンボルは一切残っていないのに、名前が正しく戻ってきます。自信のあるものには名前を付け、それ以外については黙っています。

もう一つの機能は、2つのビルドを差分比較し、どの関数の振る舞いが変わったかを教えることです。ベンダーが新しいファームウェアを出荷し、実際に何が変わったのか知りたいときに便利です:

root@kitploit:~
$ fnprint match old.so new.so
compared 84 functions present in both
  unchanged:  53
  changed:    1
  low-signal: 31 (too small to judge)

changed behavior (lowest similarity first):
   61.7%  deflate_stored

実際の n-day 作業向けには triage があります。ある関数の既知の脆弱なバージョンから1つのコーパスを、パッチ済みバージョンからもう1つを構築し、未知のビルドを両方に対してランク付けします。脆弱な側に近く、パッチ済み側から明確に分離している関数こそ、人間の前に出すべきものです。解釈が必要な単一のマッチスコアだけではありません:

root@kitploit:~
$ fnprint index vuln.so    -o vuln.db
$ fnprint index patched.so -o patched.db
$ fnprint triage mystery.so --vuln vuln.db --patched patched.db
43 functions triaged: 1 look vulnerable, 0 patched, 42 inconclusive

review queue (vuln-leaning, strongest first):
   addr         vuln%  patched%  margin  matches
   0x000022f9  100.0     27.3   +72.7  adler32_z vs crc32_z

両バージョンで同一である42個の関数は、意図的に inconclusive として返されます。どちらの側にも断定できず、フラグを立てるべきではないからです。--margin と --min-sim は、断定する前に両側がどれだけ強く分離していなければならないかを制御します。

仕組み

各関数について:

  • バイナリをマップし、引数レジスタにジャンクを入れた状態でその関数へジャンプします。
  • こちらが設定していないメモリからの読み取りは決定的な値を返し、そのページはオンザフライでマップされます。ワイルドポインタが実行をクラッシュさせることはなく、同じ入力は常に同じトレースを与えます。これは Godefroid のマイクロエグゼキューションのトリックです。
  • 他の関数への呼び出しはスタブ化され (記録され、その後スキップされ)、libc に踏み込むことはなく、実行はこの関数に留まります。
  • アーキテクチャ中立な効果のストリームを記録します: どの引数バッファや構造体フィールドを読み書きするか、どの値クラスを書き込むか (入力のコピー、小さな定数、ポインタ)、行う呼び出し、取る分岐、返すもの。絶対アドレスは捨てられ、オフセットと形状だけが保持されます。
  • そのストリームはシングルへ変換され、minhash シグネチャになります。類似度は一致する minhash スロットの割合で、2つの関数の振る舞いがどれだけ重なるかを見積もります。LSH バンドインデックスにより、クエリがすべてをすべてと比較することを防ぎます。

学習データもモデルもありません。同じアイデアは文献では Blanket Execution (Egele et al, USENIX Security 2014) として登場します。fnprint はそれに対する実用的でメンテナンスされた取り組みで、実際に使える CLI を備えています。

インストール

rust ツールチェーンと unicorn + capstone ライブラリが必要です。

root@kitploit:~
# debian/ubuntu/kali
sudo apt install libunicorn-dev libcapstone-dev

cargo install --path cli
# or just
cargo build --release   # binary at target/release/fnprint

使い方

root@kitploit:~
fnprint index <binary> [-o out.db]      fingerprint every function, optionally to a db
fnprint match <a> <b>                   diff two binaries (or .db files) by behavior
fnprint query <target> --corpus <db>    name unknown functions from a corpus
fnprint triage <t> --vuln <db> --patched <db>   rank a build against vuln vs patched corpora
fnprint eval <a> <b>                     accuracy metrics using symbol names as truth
fnprint dump <binary> <func>            print the recorded effect trace (debugging)

match と query は ELF か、index で構築した .db のどちらでも受け取れるので、コーパスを一度フィンガープリントして再利用できます。

マシン出力

すべてのコマンドはグローバルな --format を受け取ります:

root@kitploit:~
fnprint query mystery.so --corpus corpus.db --format json > names.json
fnprint query mystery.so --corpus corpus.db --format r2   > fnprint.r2

json はスクリプト (および contrib/ の Ghidra インポートスタブ) 向けの安定したスキーマで、r2 は rizin/radare2 内で . fnprint.r2 として実行する afn リネームコマンドを出力します。ターゲットからのシンボル名はどちらに渡る前にもサニタイズされるので、細工された名前が r2 コマンドを注入することはできません。スキーマとセットアップは docs/integrations.md にあります。

インデックス作成はデフォルトでシングルプロセスです。FNPRINT_SHARDS=N fnprint index ... は大きなインデックスを N 個の隔離されたワーカーに分散します。コーパスは N が何であれバイト単位で同一です。これは大きく関数豊富なバイナリでのみ役立つので、要求しない限りオフです。

精度

rank-1 精度とは: ビルド A のある関数について、ビルド B のすべての関数を類似度でランク付けしたとき、トップヒットが正しいものであるかどうか。これはまさにストリップされたバイナリの命名タスクです。zlib 1.3.1 (84 関数) で測定し、bench/run.sh で再現可能です:

pairrank-1precision
gcc O0 -> O197.1%93.8%
gcc O0 -> O293.1%83.3%
gcc O0 -> O391.3%100.0%
gcc/clang O097.7%97.1%
gcc O2 -> O356.5%66.7%
gcc/clang O259.1%50.0%

完全な表と2つ目のライブラリ (lua) は bench/NUMBERS.md にあります。

eval は recall@3 / recall@5 と棄権率も報告します。rank-1 だけでは多くを隠してしまうからです。gcc O0 -> O2 ではトップヒットが正しいのは 93% の確率ですが、正しい関数がトップ5に入るのは 96.6% の確率なので、小さなレビュー予算でギャップのほとんどを埋められます。また、確信が持てないペアについては推測する代わりに棄権 (自信のある「同じ」判定を控える) するので、同じ閾値で recall が低いまま precision が高く保たれます。

正直な評価: 少なくとも片側に何らかの振る舞いの豊かさがある場合 (-O0/-O1 のもの、または -O0 でのクロスコンパイラペア) は 80-98% の範囲に収まります。両側が高度に最適化されていると、観察できる振る舞いが薄くなり、コイントスに近づきます。これは単一パスで学習不要のマッチャーにとっての難しいフロンティアであり、本ツールはそうでないふりをしません。

苦手なこと

  • 小さな関数。サンクや一行アクセサはフィンガープリントするのに十分なことをしないので、それらは保留されます (これが「low-signal」と「with enough signal」のカウントです)。
  • 純粋な計算。バッファを読んで数値を返す2つのチェックサムは似て見えます。外から見ればほぼ同じだからです。
  • 実際の事前条件の背後にある深いロジック。ジャンク入力でのマイクロエグゼキューションは関数のエントリ時の振る舞いを試します。ジャンク入力では決して到達しない状態に埋もれた変更は match に現れません。構造的および初期パスの変更は捉えますが、すべての深い微調整を捉えるわけではありません。
  • 両側の重い最適化。上の数値が示すとおりです。
  • 重い難読化 (特に VM ベース) はこれを破壊します。

先行技術と、このツールの位置づけ

  • FLIRT / FunctionID / Lumina: バイトシグネチャ。正確で高速だが、再コンパイルで壊れる。
  • BinDiff / Diaphora: グラフ構造。優れているが、最適化やアーキテクチャをまたぐと脆い。
  • Ghidra BSim: デコンパイラの特徴ベクトル。精神は近いが、ほぼ単一アーキテクチャ。
  • Asm2Vec / SAFE / jTrans: 学習済み埋め込み。強力だが学習が必要で、誰も学習していないアーキテクチャには一般化しない。
  • マイクロエグゼキューション (Godefroid, 2014) と Blanket Execution (Egele et al, 2014): このアプローチの学術的ルーツ。メンテナンスされたツールとして出荷されたものはない。

fnprint は学習不要で振る舞い優先の選択肢です。効果モデルはすでにアーキテクチャ中立で、これは CPU をまたいだマッチングへの土台です。

ロードマップ

  • arm64 と mips。x86 で関数をフィンガープリントし、ストリップされたルーターファームウェア内で見つけられるようにするため。効果モデルはすでにアーキテクチャ中立で、これは主にアーキテクチャごとのエミュレータの配管です。
  • より賢いパスカバレッジ。素朴な分岐反転はコード内にあります (explore_depth、デフォルトはオフ) が、到達不可能なパスにビルド固有のノイズを加え、テストではクロスビルド精度を損なったので、その価値を発揮する前にパス整合性フィルタが必要です。
  • pe と mach-o のローダー。
  • rizin/radare2 エクスポートは現在出荷されています (--format r2)。次は本物の ghidra プラグインです。それまでの間、contrib/ に実験的な jython インポートスタブがあります。

ライセンス

MIT。LICENSE を参照してください。

ツールをダウンロード