Skip to Content
新しいバージョン 12 を公開しました 🎉
Obfuscator概要一般機能

一般機能

Babel Obfuscator が何をするのか、どこで動作するのか、何を保護するのかを説明します。各セクションには、その機能の設定方法を示すページへのリンクがあります。

リバースエンジニアリングからのコードと知的財産の保護

Babel Obfuscator は、コンパイル済みのアセンブリに、互いに独立した複数の保護レイヤーを適用します。シンボルをリネームして意味のない識別子に変え、文字列、定数と配列、リソースを暗号化し、メソッドの制御フローを書き換え、呼び出し先を動的プロキシの背後に隠します。さらに、メソッド本体全体を暗号化して、マネージドの仮想マシンで実行させることもできます。アプリケーションの動作とパブリックインターフェイスは変わりませんが、デコンパイラーが復元するものは、もはや元のソースコードではありません。

これらのレイヤーは、組み合わさって効果を発揮します。リネームは読み手が頼りにする語彙を取り除き、文字列暗号化と値の暗号化はリネーム後も残る手がかりを取り除き、制御フロー難読化は構造を取り除き、コード暗号化はコードそのものを取り除きます。これらを併用し、知的財産のある箇所に絞って適用することで、アセンブリを理解して改変するためのコストは、攻撃者がそこから得られる価値をはるかに上回るようになります。

.NET エコシステム全体との互換性

Babel Obfuscator は IL とメタデータのレベルで動作するため、標準の .NET アセンブリを生成するすべてのランタイムとアプリケーションモデルをサポートします。

  • .NET 10 と、それ以前のすべての .NET および .NET Core のリリース
  • .NET Framework 2.0 から 4.8
  • WPF、Windows Forms、Avalonia で作成されたデスクトップアプリケーション
  • Android と iOS 上の .NET MAUI、および Xamarin
  • Blazor と ASP.NET Core
  • .NET Standard、UWP、Mono、nanoFramework

C#(C# 14 まで)、VB.NET、F# で書かれたコードを処理でき、最新の SDK の公開モードであるフレームワーク依存、自己完結型、単一ファイル、トリミング、NativeAOT に対応しています。シンボルのリネーム、STREAM 文字列暗号化、およびチェーン状態を含む制御フロー難読化は、トリミングと AOT コンパイルを経てもそのまま維持されます。コード暗号化、動的プロキシ、デスクトップの改ざんチェックなど、メモリマップされたイメージや動的 IL に依存する機能には、MAUI、Blazor、AOT のターゲットで制限事項があります。制限事項は各機能のページに記載されており、.NET MAUI を難読化すると Blazor Web アプリのサンプルでは、動作する構成を確認できます。

Windows、macOS、Linux での動作 Ultimate

すべてのエディションに、Windows 用のコマンドラインツールと MSBuild タスク(zip パッケージ)が含まれています。Babel Desktop の実行、macOS と Linux での Babel の実行、および Azure DevOps、GitHub Actions などの CI ビルドパイプラインでの実行には、Ultimate エディション、またはそれを含む Babel Licensing の Server エディションか Data Center エディションが必要です。Babel Obfuscator の NuGet パッケージが付属するのはこれらのエディションだけで、このパッケージによって Babel をどのオペレーティングシステムでも dotnet ツールとして実行し、dotnet build と dotnet publish に組み込めます。Enterprise エディションで使用できるのは、.NET Framework 版 zip パッケージに含まれる Windows 用のコマンドラインツールと MSBuild タスクに限られます。

難読化は IL に対して行われるため、ビルドホストのオペレーティングシステムによってターゲットが制約されることはありません。Windows のビルドエージェントで linux-x64、linux-arm64、osx-arm64 向けに公開されたアセンブリを保護でき、Linux コンテナーで Windows のデスクトップアプリケーションを保護できます。そのため、チームは既存のビルド環境をそのまま使い続けられます。

完全にマネージドなコード暗号化と仮想化

コード暗号化は、メソッドの IL を独自の命令セットに書き換えて暗号化し、元の場所にはスタブを残します。このスタブは、難読化されたアセンブリに埋め込まれた軽量なマネージドランタイムである Babel Virtual Machine(BVM)に制御を渡します。BVM は、メソッドが呼び出されたときにそれを復号して実行します。メソッド本体は、デコンパイラーが読める形ではアセンブリ内に存在しなくなり、命令にパッチを当てることもできません。

この仕組みは完全にマネージドです。暗号化されたメソッドが特定のプラットフォーム向けのネイティブコードに置き換えられることはないため、.NET のクロスプラットフォーム性は保たれ、JIT コンパイラーは引き続きターゲット CPU 向けに最適化します。暗号化されたコードは、ライセンスと一緒に配布する外部コードファイルに格納することも、実行時に指定するパスワードで保護することもでき、これが機能ベースのライセンスの基盤になります。ハードウェアドングルへの紐付けの記事では、暗号化されたコードを物理デバイスに紐付ける方法を紹介しています。コード暗号化はパフォーマンスに影響するため、コードベースの重要な部分に使用し、残りの部分はほかの保護でカバーすることを想定しています。

自動化された難読化解除への耐性の強化 Ultimate

従来の難読化は、人間の読み手には有効です。しかし、ある種の自動化ツールは、フラット化されたメソッドの順序を静的に復元したり、暗号化された文字列の隣にあるキーを読み取ったりして、その一部を 1 回のパスで元に戻せます。バージョン 12.0 では、こうした相手を想定して設計された 2 つの変換が追加されました。

  • チェーン状態は、ディスパッチャーを中心にメソッドをフラット化し、その元の順序は静的解析だけでは復元できません。標準的な自動難読化解除ツールを使った社内テストでは、通常の switch アルゴリズムでフラット化したメソッドは再構築されましたが、同じメソッドを chain でフラット化した場合は復元されませんでした。検証可能な IL を出力し、実行時の依存関係を追加せず、通常のフラット化と数パーセント以内の差で動作します。
  • STREAM 文字列暗号化は、認証付き暗号で文字列を 1 つずつ暗号化し、最初に使用されるときに遅延して復号します。キーをインラインで格納することはありません。同一の文字列でも異なるバイト列に暗号化され、すべての文字列がまとめて平文で存在する瞬間はありません。また、完全にマネージドな復号ルーチンは、トリミング、NativeAOT、FIPS モードでもそのまま公開できます。

デスクトップとモバイルでのデバッグと改ざんの検出

アセンブリに挿入されたデバッグ保護のコードは、アタッチされたデバッガーを検出すると、プロセスを終了するか、指定したメソッドを呼び出します。改ざん検出は、アセンブリが Babel の生成したものであることを起動時に検証します。デスクトップターゲットでは、メモリに読み込まれたイメージのハッシュを計算し、難読化時に記録されたハッシュと比較します。

バージョン 12.0 以降、改ざん検出は、デスクトップの手法を適用できない .NET MAUI にも対応しています。Android では、難読化されたアプリが、実行中の APK の署名に使われた証明書を、難読化時にピン留めした信頼された署名者のフィンガープリントと比較するため、再パッケージまたは再署名されたアプリは拒否されます。iOS では、自身のバンドル ID と Apple のチーム ID を検証します。どちらのチェックも、マネージドイメージではなくオペレーティングシステムのパッケージを検査するため、トリミングや完全な AOT でも機能します。いずれの場合も、検出時の対応は自由に選択できます。終了するか、カスタムハンドラーを実行して、ログの記録、機能の制限、サーバーへの通知などを行えます。

依存関係のマージと埋め込みによるデプロイの簡素化

マージと埋め込みは、アプリケーションとその依存関係を単一のファイルにまとめます。マージは、参照されるアセンブリのコードをターゲットに取り込み、独自のコードと一緒にリネームします。マージされた型は internal 化して 1 つの単位として難読化できるため、デプロイが簡単になると同時に、読み取り可能なコードの範囲も小さくなります。埋め込みは、アセンブリを丸ごと暗号化されたリソースとして格納し、実行時に読み込みます。変更してはならないサードパーティ製のアセンブリや厳密名付きアセンブリに適しています。この 2 つは、同じプロジェクトで併用できます。

コードとメタデータの最適化

保護に加えて、Babel は生成するアセンブリを最適化します。デッドコード除去は、一度も使用されないメソッド、フィールド、プロパティ、型を取り除きます。メタデータの最適化は、クラスを自動的にシールし、不要なカスタム属性、System.Enum 型、プロパティとイベントの構成要素を除去します。コードの最適化は、小さなメソッドとプロパティをインライン展開し、const フィールドを除去します。その結果、アセンブリはディスク上で小さくなり、読み込みが速くなり、読み解きにくくなります。リバースエンジニアリングを行う者が頼りにするメタデータが、ランタイムに必要なものだけに減るためです。

Visual Studio、MSBuild、NuGet、ビルドサーバーとの統合

Babel は、ビルドの後ではなくビルドの中で実行されます。Babel の MSBuild タスクは、Visual Studio からも、MSBuild を実行する任意のビルドサーバーからも難読化を実行でき、タスクのすべてのプロパティには、プロジェクトファイル内で IntelliSense による説明が表示されます。SDK スタイルのプロジェクトでは、Babel.Obfuscator NuGet パッケージ Ultimate がさらに踏み込んだ統合を提供します。パッケージ参照を 1 つ追加するだけで、dotnet build と dotnet publish のパイプラインの適切な位置、つまりトリミングと AOT コンパイルがアセンブリを書き換える前にタスクが配置されます。これらの公開モードを保護できるのは、この順序の場合だけです。ビルドサーバーのサンプルは、Azure DevOps、GitHub Actions、AppVeyor、App Center を扱っており、難読化された出力に対して単体テストを実行する方法も示しています。NuGet パッケージと同様に、これらには Ultimate エディションが必要です。

AI に適したモードを備えたコマンドラインツール

Babel のすべての機能は、Windows、Linux、macOS のコマンドラインから利用できます。バージョン 11.7 以降、このツールにはパイプラインや AI エージェント向けの AI に適したモードもあります。--format=json または --format=ndjson を指定すると、構造化されバージョン管理されたイベントストリームが stdout に出力され、診断情報は stderr に出力されます。--quiet はバナーを表示せず、入力を求める代わりにただちに失敗します。--strict-exit は、無効な引数、入力の不足、難読化の失敗、ライセンスの失敗、署名の失敗を区別する、意味を持つ終了コードを有効にします。同じフラグによって、--help はすべてのオプションを機械可読な形式で説明するようになります。

MCP を介した AI アシスタントによる操作

Babel Desktop は Model Context Protocol サーバーをホストできます。これにより、Claude Code などのアシスタントは、実行中のアプリケーションに接続して操作できます。プロジェクトの作成、アセンブリの追加、ルールの記述、マージまたは埋め込む対象の選択、難読化、警告と統計の確認、スタックトレースのデコード、テーマの作成、結果を確認するためのスクリーンショットの取得などです。ツールは、最もよく行う操作に対応するもののほか、設定、Babel Licensing、アプリケーションのアップデートのためのものが用意されています。Server エディションと Data Center エディションでは、同じサーバーでライセンス管理データベースも管理できます。対象は、顧客、製品、注文、ライセンス、署名キー、およびライセンスの生成とエクスポートです。

サーバーは既定でオフになっており、ループバックアドレスにのみバインドし、すべての要求でアクセストークンを必須にできます。Babel Licensing には、ホストされた Licensing Service 向けに、別の MCP サーバーがあります。

難読化されたスタックトレースのデコード

リネームによって、例外のスタックトレースに表示される名前が変わります。そのため Babel は、難読化されたアセンブリごとに XML マップファイルを生成し、トレースを元に戻すためのツールを提供しています。Babel Desktop のスタックデコーダーと、コマンドラインオプション --stacktrace は、元の名前を復元します。行番号については、任意で PDB も利用できます。動的プロキシが有効な場合、デコーダーは各プロキシのブリッジフレームの背後にあるメソッドの名前を示します。Babel が生成したフレームを完全に非表示にすることもでき、その場合は、難読化されていないアプリケーションが出力するものと同一のトレースが得られます。マップファイルはアセンブリ間のリネームにも使用されるため、アプリケーションとそのライブラリを別々のビルドで難読化しても、リネームされたシンボルを一致させられます。

FIPS 対応

Babel で保護されたアセンブリは、FIPS モードのホストで動作します。実行時にコンテンツを復号する機能、つまりコード暗号化、文字列暗号化、リソース暗号化、値と配列の暗号化は、自己完結したマネージド AES 復号ルーチンを使用するように設定できます。そのため、挿入されたランタイムがプラットフォームの暗号化プロバイダーに依存することはなく、OpenSSL の FIPS プロバイダーがないコンテナーでもアプリケーションは起動します。FIPS 準拠のページでは、環境側の条件、難読化時の対処、環境レベルの対処について説明しています。

ルール、属性、プラグインによる拡張

すべての機能は、シンボルごとに調整できます。XML ルールは、パターン、属性、可視性、継承によって型とメンバーを選択し、それらに対して機能を有効にしたり、無効にしたり、設定したりします。カスタム属性を使うと、同じことをソースコードから行えます。難読化エージェントは、難読化の前にアセンブリを解析し、リフレクション、シリアル化、データバインディング、動的コードが動作し続けるようにするルールを生成します。それ以上のことが必要な場合は、.NET で作成したプラグインで、文字列暗号化と値の暗号化のアルゴリズム、独自のリネーム方式、生成されるルール、コード変換を追加できます。出発点として、GitHub にオープンソースのサンプルがあります。

Last updated on