2 ポイント 投稿者 GN⁺ 2024-03-18 | 1件のコメント | WhatsAppで共有
  • LLM4Decompileは、Linux x86_64バイナリをGCC O0〜O3最適化レベルで人間が読めるCソースコードへ戻すオープンソースの大規模言語モデルプロジェクト
  • アプローチは、バイナリをObjdumpでアセンブリに変換した後、LLMがCコードへ逆コンパイルする流れで、Ghidra出力の擬似コードを整形するLLM4Decompile-Ref系統も提供
  • モデルは1.3B〜22B規模で公開されており、llm4decompile-9b-v2はDecompileベンチマークで再実行可能率64.9%を記録
  • 評価指標は、逆コンパイルされたコードが事前定義されたテストを通過して正しく実行されるかを見る再実行可能率で、HumanEval-Decompileの164個のC関数とExeBenchの2,621個の関数がベンチマークとして使われる
  • プロジェクトは2025年にdecompile-benchとSK²Decompileを公開し、より多くのアーキテクチャ・設定・逆コンパイルツール連携を目標に拡張中

LLM4Decompileの目的と対応範囲

  • LLM4Decompileは逆コンパイルに特化したオープンソースの大規模言語モデルプロジェクト
  • 現在のバージョンは、Linux x86_64バイナリをGCC最適化レベルO0〜O3の範囲で、人間が読めるCソースコードへ逆コンパイルする
  • プロジェクトは、より広いアーキテクチャと設定をサポートするための拡張を進めている
  • 主な利用方法は2つある
    • LLM4Decompile-End: バイナリを直接逆コンパイルするモデル系統
    • LLM4Decompile-Ref: Ghidraが逆コンパイルした擬似コードをLLMで整形するモデル系統

逆コンパイルの学習・評価フロー

  • コンパイル過程はCソースコードから始まり、前処理、コンパイル、アセンブル、リンクを経て実行ファイルを生成する
  • 逆コンパイルはこの過程を逆にたどり、バイナリコードを再びソースファイルへ変換する
  • LLMはバイナリデータを直接処理できないため、まずバイナリをObjdumpでアセンブリ言語へ逆アセンブルする必要がある
  • READMEでは、バイナリと逆アセンブルされたASMは相互変換可能であるため同等に扱えると説明している
  • 学習では逆コンパイルされたコードと元のソースコードの間の損失を計算し、評価ではテストアサーションを通過するかで機能性を確認する

評価指標とベンチマーク

  • 中核指標はRe-executability
    • 逆コンパイルされたコードが正しく実行できるかを確認する
    • 事前定義されたすべてのテストケースを通過するかを評価する
  • HumanEval-Decompileは、標準Cライブラリのみに依存する164個のC関数の集合
  • ExeBenchは、実際のプロジェクトから取得した2,621個の関数の集合
    • ユーザー定義関数、構造体、マクロを含む

公開モデルと性能

  • LLM4Decompileは1.3B〜33Bパラメータ規模のモデルを含み、モデルはHugging Faceで公開されている
  • 主なモデルの再実行可能率は以下の通り
  • V1.5系統は、15Bトークンのより大きなデータセットと最大トークン長4,096で学習され、従来モデル比で100%以上の性能向上があったとしている
  • V2系統はGhidraベースで、Ghidraが生成した逆コンパイル擬似コードを整形するよう2Bトークンで学習された
  • 22B-V2は6.7B-V1.5よりさらに40.1%高い性能を示したとしている

最近公開された項目

  • 2025年10月4日にSK²Decompileが公開
    • 第1段階のStructure Recovery、すなわちSkeleton段階では、バイナリまたは擬似コードを難読化された中間表現へ変換する
    • 第2段階のIdentifier Naming、すなわちSkin段階では、意味のある識別子を持つ人間が読めるソースコードを生成する
    • モデルリンク: sk2decompile-struct-6.7b, sk2decompile-ident-6.7
  • 2025年5月20日にdecompile-benchが公開
    • 学習用バイナリ・ソース関数ペア200万件を含む
    • 評価用関数ペア7万件を含む
    • 詳細はdecompile-benchフォルダにある
  • 2024年10月17日にdecompile-ghidra-100kが公開
    • 最適化レベルごとに25,000件ずつ、合計100,000件の学習サンプルを含む
    • 単一のA100 40G GPUで約3.5時間で実行できる学習スクリプトを提供
    • 迅速な再現コストは合計20ドル未満で、再実行可能率0.26を達成
  • 2024年9月23日にLLM4Decompile-9B-v2が公開
    • Yi-Coder-9Bをベースにファインチューニング
    • Decompileベンチマークで再実行可能率0.6494を達成

利用フロー

  • クイックスタートは、リポジトリの複製、Conda環境の作成、requirements.txtのインストールで構成される
  • 前処理段階では、CコードをGCCでバイナリへコンパイルした後、objdump -dでアセンブリ命令を抽出する
  • 関数名は例のfunc0ではなく、逆コンパイルしたい関数名に置き換える必要がある
  • 入力アセンブリは次の形式を想定している
    • <FUNCTION_NAME>:
    • 続く複数行のアセンブリ命令
  • 逆コンパイル段階では、transformersAutoTokenizerAutoModelForCausalLMでHugging Faceモデルを読み込み、アセンブリプロンプトからCコードを生成する
  • Dockerの利用も可能
    • イメージをビルドした後、GPUオプション付きでコンテナを実行する
    • ghidraディレクトリでdemo.pyを実行するフローが提供される

HumanEval-Decompileのデータ形式

  • HumanEval-Decompileデータはllm4decompile/decompile-eval/decompile-eval-executable-gcc-obj.jsonにJSONリスト形式で保存されている
  • サンプル数は164個の関数にO0, O1, O2, O3最適化レベルを掛けた164*4
  • 各サンプルは5つのキーを持つ
    • task_id: 問題ID
    • type: O0, O1, O2, O3のいずれかである最適化段階
    • c_func: HumanEval問題のC解答
    • c_test: Cテストアサーション
    • input_asm_prompt: アセンブリ命令とプロンプト
  • 評価スクリプトはevaluationフォルダにある

進行中の項目とライセンス

  • 進行中の項目には、より大きな学習データセットと整理過程、人気の高い言語・プラットフォーム・設定対応、実行ファイル対応、Ghidra・Rizinのような逆コンパイルツール統合が含まれる
  • より大きな学習データセットと実行ファイル対応は、2024年5月13日に完了した項目として表示されている
  • コードリポジトリはMIT LicenseDeepSeek Licenseでライセンスされている
  • 論文はarXiv:2403.05286にあり、プロジェクトはColabとYouTube資料も提供している

1件のコメント

 
GN⁺ 2024-03-18
Hacker News のコメント
  • 興味深いアイデアだが、結果が信頼できるのかが気になる。
    再コンパイルすると別の機械語が出る可能性があるためハルシネーションを見分けにくく、特にコードの中核になり得る新しい構造で静かに失敗するのではないかと心配している。
    生成方式で実行する際に、LLM が特定区間の確信度もあわせて報告する方法があるのか気になるし、結局は人間の確認が必要になりそうだ。

    • だからラウンドトリップ変換が重要になる。
      バイナリをソースに逆コンパイルした後、再びバイナリにコンパイルしたときに元のバイナリが得られるべきで、損失が許容できる水準まで下がるまで繰り返せばよい。
      こうした問題には強化学習が非常によく合っており、実際にこの種の問題で異常なほど効果的だと知られている。
    • LLM は本質的に確率的なので、自然言語処理のような厳密でない領域ではかなりうまく機能するが、逆コンパイルや逆アセンブルに使うのは、個人的には「道具の選択を間違えている」ケースに近いと思う。
      最近よくある「とりあえず LLM を使おう」というミームを探る実験ではあるかもしれないが、既存の逆コンパイラがはるかに少ない計算量ですでにより良くできている点のほうが大きな反論になる。
    • 入力、出力、そして入力が出力の意味と一致するという形式的証明を受け取る形式検証ツールを用意し、LLM に出力とともにその証明も作らせればよい。
      その後、検証ツールで LLM が提供した証明に従って結果が正しいか確認できる。
      もちろん、そのような証明を作れる LLM を構築して学習させることのほうが大きな難題だろうが、ハルシネーションを安全に捕捉する方法にはなり得る。
    • 差分ファジングを使ってもよい。
    • 完全に信頼できなくても、バイナリを修正する場合はたいてい数個の関数だけを変えれば十分なことが多い。
      したがって、その数個の関数だけを再コンパイルすればよい。
  • アプリケーションを作った開発者を知っているなら、彼らの過去のコードを学習データとして使い、逆コンパイルモジュールを訓練できるのかは興味深い。
    例えば Super Mario 64 と Zelda 64 は完全に逆コンパイルされており、他の N64 ゲームも進行中なので、両ゲームに関わった開発者をマッピングし、誰がどのモジュールを作ったのかまで推定して、他のゲームの逆コンパイルに活用できるのか気になる。
    これが本当に良くなれば、PC 内のすべてのバイナリブロブを解読してドライバを公開し、OS まで開け放つような生活も夢見られる。
    Linux に満足せず、Windows XP を復活させて現代的なセキュリティとアプリ互換性をバックポートし、Microsoft の Windows 11 はそのままにしておく、という想像もできる。

    • 逆コンパイラはすでに存在し、性能も良い。
      LLM が既存の逆コンパイラと同じことをできるなら、弁護士はそれを同等の手続きと見る可能性が高い。
      核心的な問題は技術ではなく、法的・政治的な問題だ。
    • 学士論文で似たテーマを扱ったが、特定の条件下ではコンパイル済みバイナリだけを見ても誰がプログラムを書いたのかを当てる作者識別分類器を学習できる、という研究があった。
      実際に有用に使われた事例はよく知らないが、個人のコーディングスタイルがコンパイル過程を経た後にも残り、互いのコンパイル済みプログラムを区別できるという点は面白い。
    • 実際に書かれたコードそのものを識別することはできないと思う。
      結果は元のものにかなり似るだろうが、多くのコードスタイル要素は失われ、残って見えるスタイルもおおむねハルシネーションに近いだろう。
  • 公開されている C コードから大量の入力/出力ペアのデータセットを作るのは簡単なので、これはLLM のファインチューニングに非常に良いユースケースだ。

    • コーディング LLM、例えば DeepSeek のようなモデルで非常に多くの C コードを生成し、コンパイルできるかを検証して合成学習データとして使うのも、この状況ではかなり有利だと思う。
      通常は合成学習データの品質が大きな懸念になるが、ここではコードがコンパイルされるという事実が重要だ。
  • 結果図の再実行可能性の数値を正しく読めているなら、アイデアは素晴らしいが、実際にはうまく機能していないようだ。
    https://raw.githubusercontent.com/albertan017/LLM4Decompile/...
    補足すると、再実行可能性は意味的正確性を測る中核的な指標だ。
    逆コンパイル結果を再コンパイルしてテストケースを実行し、プログラムのロジックと動作が保たれているかを評価するもので、再コンパイル可能性と再実行可能性はそれぞれ構文の復元と意味の保存を表す。

  • この問題は少なくとも二つの面で興味深い。
    第一に、理想的な逆コンパイラはプロプライエタリなソースコードの意味を弱める可能性がある。
    第二に、公開されている C コードが豊富なので、アセンブリとソースコードのペアデータセットを簡単に作れ、最適化レベル・コンパイラ・プラットフォームも多様にできる。
    ただ、なぜ著者たちが DeepSeek-Coder をファインチューニングしたのかは気になる。
    似たデータセットで LLM をゼロから学習できるのか、どの程度の規模が必要なのか、ローカル実行が可能なのかも気になる。

    • ほとんどのプロプライエタリコードはファイアウォールの内側で実行されるため、このような方式の影響を大きく受けることはないだろう。
      やりたい作業が初期モデルとそれほど近くなくても、ランダム初期化より事前学習済みモデルから始めるほうが、ほぼ常に望ましい。
    • 理想的な逆コンパイラは存在しない。
      コンパイラが情報を失うため、ある意味では決して存在し得ないし、「結果コードの高水準な理解」という寛容な観点で見ても、これはコンピュータセキュリティ分野における汎用人工知能級の問題だ。
      まだ誰もこれに近づけていない。
    • 言語モデルをゼロから学習するには大量のデータが必要だ。
      Llama2 は2兆トークンで開発されたが、このデータセットは約40億トークン規模だ。
      適切なモデルサイズも単純には決めにくく、実験では70億パラメータモデルが21%の実行可能性を示した一方、10億パラメータモデルは10%にとどまった。
      ただし再コンパイル可能性は両者でかなり近い。
      10億パラメータモデルは最低 2GB の GPU メモリが必要で、ほとんどの GPU で可能であり、70億モデルは 14GB が必要なので 3090/4090 系に適している。
      330億モデルは単一カードなら A100 80GB が選択肢で、技術的には MacBook でも可能だろうが、実際に使いたいとは思わないはずだ。
    • 学習コストとファインチューニングコストの差が理由だと思う。
      アイデアを検証するための出発点でもあるのかもしれない。
  • Pythonバイトコード向けのLLMベース逆コンパイラ https://github.com/kukas/deepcompyle を作っている
    この研究方向に取り組んでいる人は多くないようだが、特に長い注意コンテキストが可能になりつつある今は、かなり面白いものになり得ると思う
    この分野を扱うチームを知っている人がいれば、協業に興味がある

    • PythonバイトコードにLLMを使う利点があるのか気になる
      経験上、Pythonバイトコードは十分に高レベルなので、ソースコードへ直接変換できる
    • なぜPythonなのか気になる
      Pythonには大規模なオープンソースライブラリエコシステムがあるが、バイナリ形式で配布されるソフトウェアに多く使われているとは思わない
    • PyLingual はあるが、残念ながらオープンソースではない
      LLMベースなのかもはっきりしない
    • 逆コンパイル作業はC方面が多いように思う
      バイナリにコンパイルされるPythonプロジェクトは多くなさそうだ
  • こういうものを試そうと計画していた
    いつか誰かがバイナリ入力 → 良いソースコード出力のパイプラインを突破するだろうが、まだ数年はかかりそうだ
    この問題の先に大金が積まれているようには見えないのでそう思うが、間違っているかもしれない
    良い暫定的なアプローチは、Ghidraをヘッドレスモードで動かす逆コンパイルパイプラインを作り、逆コンパイラの厳密な構文正確性とLLMの直感的能力を組み合わせることだ
    AlphaGeometryのように、逆コンパイラとLLMが互いの弱点を補完する必要がある: https://deepmind.google/discover/blog/alphageometry-an-olymp...
    また、AICIのようなものを接着剤として使い、Cソース生成を調整する方式が必要だ: https://github.com/microsoft/aici
    LLMの重みを文法的に正しいCソース生成に使うより、変数名・スニペットパターン・アーキテクチャ選択を考えさせ、GhidraやLLVMのようなツールに残りを任せるほうが望ましい
    やや手振りに近い元大学院生の安楽椅子コメントではあるが、この研究者たちが飛び込んだのは素晴らしいし、著者らが今後の作業でGhidra統合に言及しているのを見ると、方向性は合っているように思う

  • 60億モデルが330億モデルよりうまくやる点が興味深い
    330億モデルにはより多くの学習データが必要という意味なのか気になる
    約100万個のCプログラムで事前学習されたものと、数兆トークン規模で学習されたDeepSeek-Coderを比べると、データ量に数桁の差がある
    LLMではない解法と比べるとどうなのかも気になる

    • こうした流れはLLMでしばらく続いてきた
      ほとんどのLLMは大きく過小学習されており、70億モデルは主流モデルの中ではまだ過小学習が少ないほうなので、LLMファインチューニングコミュニティで広く使われるようになった
    • 330億モデルを学習するのは簡単ではない
      標準方式のまま単純にファインチューニングするナイーブなファインチューニングでは大きなモデルの学習は難しく、データ量だけでなく、データ精製・学習率・減衰といったあらゆる要素が最終性能に影響する
    • 約100万個のCプログラムと2兆トークンをそのまま比較できるのか疑問だ
      そのためには、それらのCプログラムの平均サイズが200万トークンより数桁小さいと仮定しなければならないが、実際にそうであり得るとしても、かなり楽観的な仮定に聞こえる
  • 成功するなら、コンパイラの機械語を1:1で複製することになるのか気になる
    そうだとすれば、完全なコードが潜在空間内に確率分布として存在し得るという意味になる
    あるいは、より可能性が高いのは、ロジックだけを複製してから対象言語へ翻訳する形かもしれない
    コンパイルに非決定的な入力、たとえばキーやハッシュが必要なバイナリは壊れそうだ
    本当に興味深い

  • GPT-4が比較でいまだにかなり健闘しているのが驚きだ
    このモデルよりコンパイル可能なコードははるかにうまく作るが、動作が正しいコードを再現する正確度は低い
    それでもかなり印象的だ

    • GPT-4は逆コンパイルに直接学習されたモデルではないのに非常に印象的だ
      モデルを改善中なので、アップデートを引き続き見守ってほしい
    • この方式がCと同じくらい C++ でもうまくいくなら印象的だろうが、ここではそうではない