
ストリップされたx86-64バイナリ内の関数に名前を付け、説明する小規模言語モデル。オープンデータセット、ベースライン、LoRAファインチューニング実験を備える。
英語 · トルコ語
ストリップされたバイナリ内の関数を解析し、意味のある名前と短い説明を付与する小規模言語モデル。
v4データセットには、5つの最適化レベルにわたる341プロジェクトの228,177関数が含まれており、v4設定としてHugging Faceで公開されています。Ghidraスクリプトは準備完了です。これまでで最良の小規模モデルであるQwen3-8B + LoRAをv5データ(説明を先に、次に名前)で学習させたものは、固定されたv4テストサンプルで名前F1 0.124、eval_115で0.155を達成しています。呼び出しコンテキストを用いた最良の大規模モデルは、同じテストサンプルで0.167を記録しています。詳細は「結果」のセクション6を参照してください。モデルは名前とともに英語とトルコ語の一文説明を出力します。アダプタはHugging Faceで公開されています:krxi123/asmsense-qwen3-8b-lora。
GhidraやIDAでストリップされたプログラムを開くと、FUN_00401a30という名前の関数が何百も表示されます。リバースエンジニアリングの多くは、これらの関数を一つずつ理解し、命名することにあります。このプロジェクトは、モデルにその第一歩を教えることを目的としています:
input (stripped x86-64) target output
───────────────────────────── ──────────────────────────────────────────────
movzx eax, byte ptr [rsi] name: adler32_update
lea rdx, [rdi + rax] description: Computes the Adler-32 checksum
cmp rdx, 0xfff1 ← 65521 over the bytes of a buffer.
... # TR: Tampondaki baytlar üzerinden Adler-32
# sağlama toplamı hesaplar.
大規模な汎用モデルもある程度このタスクを扱えるが、遅く、高コストで、クラウド上でホストされている。目標は次の問いに答えることである:
専用に構築されたデータで学習した小規模モデルが、ラップトップ上で動作しながら、このタスクで大規模モデルに匹敵、あるいは凌駕できるか?
同じテストセット上で3つの階層が評価される:
| 階層 | モデル | 役割 |
|---|---|---|
| 上限 | 大規模オープンモデル(DeepSeek、GLM、MiMo、Gemma、Qwen) | 既製モデルで現在達成可能な最高水準 |
| ベースライン | ファインチューニング前の小規模オープンモデル | 出発点 |
| 本プロジェクト | 同じ小規模モデル + 本データセットでのLoRA | 本プロジェクトの貢献 |
データ生成(cikar.py): オープンソースのCプロジェクトを、異なる最適化レベル(-O0、-O2)でx86-64向けにコンパイルする。各関数のアセンブリが抽出される。正解、すなわち元の関数名はソースから直接得られるため、手動でのラベリングは不要である。projeler.jsonは、すべてのプロジェクトで使用されたコミットとコンパイラフラグを記録する。
ストリップされたバイナリのシミュレーション: 出力は、ストリップされたバイナリ内の関数に対してGhidraが表示するものに似ている:
sub_01a3になり、グローバルデータはdat_0042になる(番号はシャッフルされ、-O0と-O2で別々の名前空間を持つ)、loc_1やloc_2のような関数ローカルラベルを使用する、memcpy、__stack_chk_fail)と文字列リテラル(; -> "out of memory")は、実際のバイナリでも見えるため、可視のまま残る。関数の実際の名前が自身のアセンブリ内に現れる場合——たとえばエラーメッセージ内——その行はsizintiとマークされ、テストセットから除外される。
評価(taban.py): モデルはアセンブリのみを受け取り、名前を予測するよう求められる。予測はトークンの重複(F1)で採点されるため、crc32_updateとupdate_crcのような近い回答には部分点が与えられる。
loc_6:
movzx r9d, byte ptr [rsi + rdx]
add rdi, r9 ← adler32_z (-O2), as the model sees it
add rcx, rdi
inc rdx
cmp rax, rdx
jne loc_6
| プロジェクト | 関数 (-O0 + -O2) | |
|---|---|---|
| トレーニング | zlib, libpng, sqlite, lua, mbedtls, zstd, libsodium, expat, brotli, jansson, lz4, libyaml, xxhash, cJSON | 16,804 |
| テスト (記憶耐性) | tomlc17, cyaml, mu_json_x, sajs, picomatch | 777 → 評価セット 115 |
データセットは Hugging Face で公開されています: krxi123/asmsense (16,804 件のトレーニング例、777 件のテスト例、eval_115 評価セット、ライセンス文)。Kaggle にもミラーされています: krxiii/asmsense。
olcekle.py で GitHub から選定した寛容なライセンス (MIT, BSD, Apache-2.0, ISC, zlib) の C プロジェクトを、cikar_bin.py (実際の dylib + strip -x) を用いて -O0/-O1/-O2/-O3/-Os でコンパイルしました。プロジェクトのビルドスクリプトは実行せず、ファイルは clang で個別にコンパイルし、コンパイルに失敗したファイルやプロジェクトはスキップしました。行は正規化されたアセンブリハッシュで重複排除しました。アセンブリが検証/テストデータと同一の行はトレーニングから削除し、(ファイル, 名前) のペアがトレーニングに現れたベンダーコピーは検証/テストから削除しました。すべての行に lisans フィールドがあります。
| 分割 | プロジェクト | 行 | ユニークなソース関数 |
|---|---|---|---|
| トレーニング | 290 | 196,117 | 72,179 |
| 検証 | 23 | 19,770 | 6,667 |
| テスト (知名度低、≤200 スター、2024+) | 28 | 12,290 | 4,685 |
473 プロジェクトのうち、352 が行を生成し、120 がコンパイルに失敗しました (カーネル、組み込み、またはプラットフォーム依存のコード)。clang のみを使用しました。データは Git の外に保持され、python3 aday_bul.py と python3 olcekle.py hepsi で再生成できます。
トレーニング/テスト分割は厳密にプロジェクトレベルです: あるプロジェクトの関数が両側に現れることはありません。テストプロジェクトは意図的に知名度の低いもの (2-190 スター) が選ばれ、そのほとんどが 2024-2025 年に開始されたため、zlib のようなライブラリよりも大規模モデルがトレーニング中に遭遇した可能性がはるかに低くなっています。ライセンス: veri/LISANSLAR.md。
既知の例外: ベンダーコード。 リリースされた v6 データの独立した監査 (rapor/arastirma/V6_VERI_DENETIMI.md, veri_denetim_v6.py) により、プロジェクト、id、または (プロジェクト, ファイル, 名前) が両側に現れないことが確認されましたが、テストプロジェクト snkv は独自のファイル名で SQLite を埋め込んでおり、sqlite はトレーニングプロジェクトです。修正された 2,000 行のテストサンプルでは、217 行 (10.85%) が SQLite のトレーニング関数と同一の名前を持っています。すべてのモデルはこれらの行でより低いスコアを記録するため、結果を水増しすることはありません。むしろ、小規模モデルと大規模モデルの差を狭めます (結果、セクション 6 を参照)。検証サンプル valid_300 には同様の行が 16 件 (5.3%) 含まれています。
平均名前 F1 (1.0 = 完全一致)。「プレフィックス除去 F1」列では、各プロジェクトの共通名前プレフィックス (cyaml_, mu_, sajs_) が両側から除去されています。モデルはこのプレフィックスをアセンブリから推測することはできません。
| モデル | -O0 | -O2 | プレフィックス除去 F1 | 完全一致 |
|---|---|---|---|---|
| mimo-v2.6-pro (reasoning) | 0.20 | 0.17 | 0.21 | 3 / 115 |
| mimo-v2.6-pro | 0.18 | 0.16 | 0.20 | 4 / 115 |
| glm-5.3 (reasoning) | 0.16 | 0.11 | 0.15 | 4 / 115 |
| qwen3.8-flash-next (reasoning) | 0.16 | 0.08 | 0.13 | 3 / 115 |
| deepseek-v4.1-flash (reasoning) | 0.12 | 0.08 | 0.12 | 3 / 115 |
| deepseek-v4.1-flash | 0.10 | 0.11 | 0.12 | 2 / 115 |
| glm-5.3 | 0.12 | 0.08 | 0.12 | 2 / 115 |
| qwen3.8-flash-next | 0.13 | 0.07 | 0.11 | 1 / 115 |
| gemma-4-31b (reasoning) | 0.11 | 0.08 | 0.10 | 2 / 115 |
| gemma-4-31b | 0.11 | 0.07 | 0.10 | 0 / 115 |
| qwen2.5-coder-0.5b, 未学習 | 0.00 | 0.01 | 0.01 | 0 / 112 |
| qwen2.5-coder-0.5b + LoRA v1 | 0.02 | 0.00 | 0.01 | 0 / 112 |
reasoning 実行では max_tokens の上限を 12,288 に設定しました。その上限でも、deepseek と qwen は半数以上のリクエストで reasoning を完了して回答を生成することができませんでした。glm も 115 件中 50 件で同様でした。これらの行は 0 としてスコアリングされました。
同じデータパイプライン、同じ関数数 (115)、mimo-v2.6-pro:
| reasoning なし | reasoning あり | |
|---|---|---|
| zlib (非常によく知られている) | 完全一致 9 件、F1 0.18 | 完全一致 28 件、F1 0.29 |
| 知名度の低いプロジェクト | 完全一致 4 件、F1 0.20 | 完全一致 3 件、F1 0.21 |
reasoning は zlib での完全一致数を 3 倍にしますが、知名度の低いコードには何も貢献しません。最も可能性の高い説明は、reasoning 中にモデルがアセンブリを「理解」しているのではなく、以前に見たソースコードを想起しているということです。したがって、有名なライブラリで既製のモデルを評価すると、このタスクでの性能について誤解を招く像が得られます。

各関数のアセンブリに内部呼び出し先に関する情報を追加しました (reasoning なし、プレフィックス除去 F1):
| モデル | コンテキストなし | Summary | Deep | 長い関数 (コンテキストなし → deep) |
|---|---|---|---|---|
| mimo-v2.6-pro | 0.20 | 0.22 | 0.24 | 0.12 → 0.25 |
| deepseek-v4.1-flash | 0.12 | 0.17 | 0.17 | 0.10 → 0.18 |
| qwen3.8-flash-next | 0.11 | 0.15 | 0.16 | 0.06 → 0.18 |
| gemma-4-31b | 0.10 | 0.09 | 0.10 | 0.04 → 0.11 |
| glm-5.3 | 0.12 | 0.14 | 0.13 | 0.06 → 0.05 |
コンテキストは長い関数と他の内部関数を呼び出す関数に最も役立ちます (glm を除く: 115 件中 35 件のリクエストで応答が切り捨てられ、長い入力が glm に悪影響を与えることを示しています)。Deep コンテキストは summary に比べてほとんど追加されません。ラッパーは deep コンテキストでも 0 のままです (テストセットには 6 件しかありません; 呼び出し先の完全なアセンブリでさえモデルを正しい名前へ導くことはありません)。
Qwen2.5-Coder-0.5B (4-bit)、1,500 ステップ (約 1 時間 40 分、4.8 GB メモリ)。どちらの試行もうまくいきませんでした: