Skip to content

MS_DecompileAndObfuscation

nishi_74322014 edited this page Sep 1, 2026 · 1 revision

逆コンパイル・難読化

概要

逆コンパイル・難読化などの質問が稀にあるため。

詳細

難読化ソリューションは、

  • 実行時コンパイラや
  • スクリプト言語が

出てきて、必要になってきたんじゃないでしょうか?

補足(原文の見立ては本質を突いている): 「実行時コンパイラや
スクリプト言語が出てきて、必要になってきた」——
この推測は正しい。理由を整理する。

【なぜ中間コード・スクリプトだと逆コンパイルされやすいのか】

  ネイティブ コンパイル(C/C++)
    ソース ──最適化──▶ 機械語
      ・変数名、型名、構造が【完全に失われる】
      ・レジスタ割り当て、インライン展開、ループ変形で原型を留めない
      ・【元に戻す情報がそもそも残っていない】★

  中間コード(.NET / Java)
    ソース ──▶ IL / バイトコード ──実行時──▶ 機械語
      ・【メタデータ(型名・メソッド名・シグネチャ)が必須】
         → リフレクション、GC、型安全性のために【消せない】★
      ・IL は高水準(スタックマシン、構造化された分岐)
      → 元のソースに近い形に復元できる

「消せない」のが要点である。
.NET は実行時に型情報を必要とする設計(.NET の Reflection
ガベージ コレクション、DI など)であるため、
メタデータを削ることが原理的にできない
だから**「消す」のではなく「読みにくくする」=難読化**しかない。

逆コンパイラ

C言語

C 言語のプリプロセッサに通した後のコードは ≒ リバースできないもよう。

  • 奇跡的に C/C++ の逆コンパイラを手に入れられたとしても
    それが吐き出すソースを理解できる可能性は全くない。

  • C++ の逆コンパイラは C よりもはるかに困難 (事実上不可能)

※ 機械語自体を読む人がいるかも知れないので、保護したいレベルによるかもしれませんが。

補足(この判断は現在は少し慎重に): 原文の
「理解できる可能性は全くない」「事実上不可能」は
当時としては妥当だが、現在はやや状況が変わった

ツール 内容
Ghidra NSA が 2019 年に公開。無償。C 風の擬似コードを出力
IDA Pro + Hex-Rays 商用の定番。デコンパイラの品質が高い
Binary Ninja 商用。中間表現が扱いやすい
radare2 / rizin OSS
【現在の実際】
   ・変数名・型名は【依然として復元されない】
      → 出力は sub_401000(a1, a2) のような形
   ・しかし【制御フローとアルゴリズムは読める】
   ・シンボル(デバッグ情報 / PDB)が残っていれば、かなり読める ★
   ・機械学習で関数名を推定する研究・ツールも出ている

【結論】
   「不可能」ではなく【非常に手間がかかる】が正しい
   → 費用対効果が攻撃者側で見合うかどうかの問題

原文の※(「保護したいレベルによる」)が、
現在も最も的確な締め方
である。

スクリプト言語

  • スクリプト・ファイルがそのまま動く。
  • インタプリタでソースコードを、機械語プログラムに解釈・変換しながら処理・実行する。

中間コードのある言語

以下の理由で、逆コンパイルが容易であるケースが多いらしい。

  • 中間コードはネイティブコードに比べて命令の種類や複雑さが少ない。

  • 逆コンパイルされ易い言語

    • ガーベージ・コレクションやリフレクション機能のある言語

    • その他、

      • 共用体が無い
      • ポインタ演算・キャストの制限
      • class に定義情報が含まれる。
      • goto 文を禁止している
      • , etc.
  • 言語毎のツール

    • Java:
      JAD(Jad Decompiler)

    • .NET:

      • IL Disassembler(ildasm.exe)
        Visual Studio に付属

      • .NET Reflector
        昔は無償で一択だったが、2011 年の 3 月に有償化された。

      • dotPeek
        ReSharper に付属

      • ILSpy
        MIT の OSS でスタンドアロンで利用可能。

      • Telerik JustDecompile
        Telerik 社製

      • .NET CodeReflect

補足(挙げられた理由は的確): 「逆コンパイルされ易い言語」の
特徴の一覧は、なぜ復元できるのかを正しく説明している

【共用体(union)が無い】
   C の union は「同じ領域を別の型として解釈する」
     → 逆コンパイラはどの型か判断できない
   .NET には(原則)無いので、型が一意に決まる ★

【ポインタ演算・キャストの制限】
   C では p + 3 が何を指すか、静的に分からない
   .NET は型安全なので、参照が何を指すか追える

【class に定義情報が含まれる】
   メタデータそのもの。前述の通り消せない ★

【goto を禁止している】
   構造化された制御フロー(if / while / for)に戻しやすい
     → 任意の goto があると、元の構造を推定できない

移行メモ(各ツールの現況):

ツール 現況
ildasm.exe 現役(IL の逆アセンブル。C# には戻らない)
ILSpy 現役・活発。MIT。VS 拡張版もある
dotPeek 現役・無償(JetBrains。ReSharper 不要になった)
.NET Reflector 有償(Redgate)。現役
Telerik JustDecompile 提供終了(2023 年)
.NET CodeReflect 提供終了
dnSpy 開発停止(2020)。dnSpyEx がフォークとして継続
JAD(Java) 開発停止。現在は CFRProcyonFernflower
【現在の .NET での定番】
   ・ILSpy(無償・OSS)★
   ・dotPeek(無償)
   ・dnSpyEx(デバッガ付き。動的解析ができる)

なお、逆コンパイルは「攻撃」だけの手段ではない

【正当な用途】
   ・ソースを失った自社製 DLL の調査
   ・NuGet パッケージの挙動確認([NuGetパッケージのデバッグ](MS_NuGetPackageDebugging))
   ・.NET ランタイム自体の実装確認
      → 現在は【source.dot.net / GitHub】でソースが公開されている ★
   ・障害解析(配置されたバイナリが期待の版か)

ライセンス上の注意:

・第三者の製品を逆コンパイルする行為は、
  【使用許諾契約(EULA)で禁止されている】ことが多い
・著作権法上も、リバース エンジニアリングの可否は
  目的・国によって扱いが異なる
→ 業務で行う場合は【契約と法務を確認する】★

難読化

  • 難読化は単なる時間稼ぎに過ぎず、プログラムの逆コンパイルを不可能とするものではない。

  • 商用の難読化ソリューションはソースコードの難読化や Java や .NET などのプラットフォーム中立な
    バイトコードの変換が大部分を占めるが、中にはコンパイルされたバイナリに直接作用するものも存在する。

C言語

そもそも、逆コンパイルができないので難読化も不要。

スクリプト言語

そもそも、コンパイルがないので難読化もできない。

移行メモ(スクリプト言語も難読化はできる): 「コンパイルがないので
難読化もできない」は正確ではない
難読化はコンパイルの有無とは独立である。

【JavaScript の難読化は実際に広く行われている】
   ・変数名の短縮・無意味化(Minify + Mangle)
      → terser / esbuild が標準で行う
      → [ASP.NET の BundleConfig](MS_ASPNETBundleConfig) の Minification
   ・文字列の分割・エンコード
   ・制御フローの平坦化(javascript-obfuscator 等)

【ただし】
   ブラウザで動く以上、【最終的には必ず読める】
     → デバッガで実行時の値を見れば分かる
     → やはり「時間稼ぎ」である

原文の主張の核——
「難読化は時間稼ぎに過ぎない」——は、
スクリプト言語でも中間コードでも等しく正しい

中間コードのある言語

  • 逆コンパイルが容易なため、難読化が必要になるケースもある。

  • 言語毎のツール

    • Java:

      • ProGuard
      • JODE
      • JavaGuard
      • RetroGuard
      • jarg
      • yGuard
    • .NET:

      • ConfuserEx(無料)
      • NanDoKu(無料)
      • Phoenix Protector(無料)
      • Dotfuscator(有料 – 簡易版有り)
      • Eazfuscator.NET(有料 – 試用版有り)
      • babelfor.net(Babel)(有料 – 試用版有り)

補足(難読化が実際に何をするか): 「読みにくくする」の中身を
具体化しておくと、限界と副作用が理解しやすい。

手法 内容 副作用
識別子の改名 CalcTaxab リフレクションで名前解決している箇所が壊れる
制御フローの平坦化 if/forswitch + 状態変数に変形 性能低下、スタック トレースが無意味に
文字列の暗号化 文字列リテラルを実行時に復号 起動が遅くなる。復号キーはバイナリ内にある
不要コードの注入 意味のない分岐を混ぜる サイズ増、性能低下
メタデータの除去 未使用の型・メンバを削る 動的読み込みが壊れる
対デバッガ デバッガ検知で終了する 正当な障害解析も困難になる
【難読化で壊れる典型的なもの】★ 実務で必ず当たる
   ・リフレクション(型名・メソッド名を文字列で指定している箇所)
   ・シリアライズ/デシリアライズ(JSON、XML のプロパティ名)
   ・DI コンテナの型名による解決
   ・Entity Framework のマッピング
   ・WPF / XAML のバインディング(プロパティ名を文字列で指定)★
   ・単体テスト(internal を見るテスト)

 → 【除外設定(exclude)を丁寧に書く】必要がある
 → 難読化後に【必ず結合テストを通す】

スタック トレースの問題:

難読化すると、本番で出る例外のスタック トレースが
   at a.b(c d)  のようになり【解析できない】

【対策】 マッピング ファイルを保存し、復元ツールで戻す
   ・Dotfuscator: Map ファイル
   ・ProGuard:    mapping.txt
 → 【リリースごとに保管する】。失うと解析不能になる ★

移行メモ(ツールの現況):

ツール 現況
ConfuserEx 開発停止。フォークの ConfuserEx2 が継続
Dotfuscator Community Visual Studio に同梱(現役)★
Eazfuscator.NET 現役(有償)
Babel 現役(有償)
NanDoKu / Phoenix Protector 更新停止
ProGuard(Java) 現役。Android では R8 が後継

補足(現在の「保護」の考え方): 難読化の議論は、
前提から見直すべき段階にある。

① そもそも守るべきものは何か

【クライアントに配るバイナリに置いてはいけないもの】
   ・API キー、接続文字列、暗号鍵 ★
      → 難読化しても【実行時にはメモリ上に平文で存在する】
      → デバッガを付ければ取れる
   ・認可のロジック
      → クライアント側の判定は【必ず迂回される】

 → 【サーバ側に置く】のが唯一の解

② 守れるもの / 守れないもの

対象 難読化の効果
アルゴリズムの機密(独自の計算ロジック) 一定の効果(時間稼ぎ)
ライセンス チェック 限定的(クラックの主戦場)
秘密情報(鍵、パスワード) 効果なし
認可・課金の判定 効果なし(サーバでやる)

③ 現在の代替手段

・【サーバ側に置く】(SaaS 化)
    → そもそもクライアントに渡さない。最も確実
・【Native AOT でネイティブ化する】★
    → IL が残らないため、逆コンパイルの難度が跳ね上がる
    → .NET 7 以降で実用的に。副次的な保護効果がある
    → ただしリフレクション等に制約([自作CUI(CLI)の話](MS_BuildingYourOwnCLI))
・【署名して改竄を検知する】(Authenticode)
    → 「読まれない」のではなく「書き換えを検知する」
・【重要処理を HSM / セキュア エレメントに置く】
【判断の順序】
 ① その情報は本当にクライアントに置く必要があるか?
      → No なら サーバへ移す(これで大半が解決する)★
 ② 置くなら、漏れた場合の影響はどれくらいか?
 ③ 影響が大きいなら、難読化 + 検知 + ローテーションを組み合わせる
 ④ 難読化は【多層防御の 1 層】であり、単独では機能しない

原文の「難読化は単なる時間稼ぎに過ぎず」という一文が、
20 年近く経った現在も最も正確な要約
である。

参考

逆コンパイラ

難読化

Microsoft Learn


Tags: 移行, プログラミング, その他、開発の色々, .NET開発

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally