コード暗号化
Babel Obfuscator のコード暗号化機能を使用すると、コード全体を暗号化して、リバースエンジニアリングから保護できます。
Babel Obfuscator は、元のメソッドの IL 命令を新しいカスタム命令のセットに変換します。このカスタム命令にはさまざまな難読化手法を含めることができ、コードのリバースエンジニアリングや変更がより難しくなります。コードの新しい表現が構築されると、選択した暗号化アルゴリズム(AES など)で暗号化され、理解や変更がさらに難しくなります。
実行時に、保護されたアセンブリがメモリに読み込まれると、Babel Virtual Machine(BVM)が保護されたコードを復号して実行します。BVM は難読化されたアセンブリに含まれる軽量なランタイムエンジンで、コードを復号して実行し、正しく動作させるために必要な機能を提供します。
FIPS が有効なホストにデプロイする場合:コード暗号化は、実行時にプラットフォームの暗号化プロバイダーを通じてメソッド本体を復号します。そのため、認定済みの OpenSSL FIPS プロバイダーを持たないコンテナーを FIPS が有効なホストで実行すると、起動に失敗することがあります。原因と対処方法については、FIPS 準拠を参照してください。
コード暗号化は、リバースエンジニアリングや知的財産の盗用に対して強力な保護を提供しますが、アプリケーションのパフォーマンスと複雑さの面でトレードオフがあるため、コードベース全体に適用することはお勧めしません。保護が必要な最も機密性の高い部分にだけこの難読化手法を適用し、残りのコードにはほかの難読化手法を使用してください。こうすることで、セキュリティとパフォーマンスのバランスを取れます。
コード暗号化の適用前
コード暗号化の適用後
Babel のコード暗号化は、完全にマネージドなソリューションです。つまり、暗号化されたメソッドが、特定のプラットフォーム向けのネイティブコードに置き換えられることはありません。マネージドメソッドによるこの方式では、.NET Framework のクロスプラットフォーム性が損なわれず、JIT(Just-In-Time)コンパイラーがターゲット CPU に合わせてコードを最適化できます。
コード暗号化の制限事項
Babel のコード暗号化機能は、次の主な理由により、.NET MAUI と Blazor のアセンブリではサポートされません。
プラットフォームの制約
• 事前(AOT)コンパイル:.NET MAUI の中心となる iOS などのプラットフォームは、AOT コンパイルに依存しています。この処理はコードを事前にネイティブバイナリへコンパイルするため、コードの暗号化と復号に不可欠な、実行時の動的なコード生成や変更ができなくなります。
System.Reflection.Emit 名前空間のサポートの制限
• IL 生成の制限:IL を動的に生成するために使われる System.Reflection.Emit 名前空間は、iOS や WebAssembly(Blazor が使用)などの主要なプラットフォームでは、サポートが限定的か、まったくサポートされていません。コード暗号化は多くの場合 IL の動的な操作に依存するため、この制限は MAUI と Blazor での暗号化機能の実装をさらに難しくします。
セキュリティ上の制限
• サンドボックス環境:MAUI と Blazor はどちらも、セキュリティのためにアプリがサンドボックス化される環境で動作します。iOS などのプラットフォームは、悪意のあるコードの実行を防ぐために、実行時のコード変更を一切許さない厳格なセキュリティ対策を課しているため、動的な暗号化は現実的ではありません。
• コードインジェクションのリスク:暗号化と復号に必要な動的コード生成は、コードインジェクションの脆弱性の可能性を含む、重大なセキュリティリスクを伴います。MAUI と Blazor のフレームワークは、こうしたリスクを避けることでセキュリティを優先しています。
これらの制約のため、.NET MAUI と Blazor はコード暗号化機能をサポートせず、安全で移植性が高く、プラットフォーム間で一貫した開発手法を重視しています。
暗号化できないメソッド
サポートされるターゲットでは、コード暗号化はメソッド単位で適用され、一部のメソッドは自動的に暗号化されないまま残されます。
• インスタンスコンストラクター(.ctor)は暗号化されません。これは仕様です。インスタンスは、使用される前に基底コンストラクターのチェーンを通じて完全に初期化されている必要があり、コンストラクター本体がコード暗号化によって移動されると、その保証を維持できません。これはインスタンスコンストラクターだけに当てはまる点に注意してください。静的コンストラクター(.cctor)は影響を受けず、ほかのメソッドと同じように暗号化されます。
• サポートされないシグネチャを持つメソッドは自動的にスキップされます。コード暗号化は、メソッド本体を Babel Virtual Machine(BVM)に移し、統一された引数マーシャラーを通じて呼び戻します。そのため、表現できないシグネチャの形がいくつかあり、それらは暗号化されないまま残されます。
- ジェネリックメソッド:
EM0003として報告されます。 - サポートされない戻り値の型:
ref(参照渡し)の戻り値、ポインターの戻り値、関数ポインターの戻り値、またはSpan<T>/ReadOnlySpan<T>などのref struct(byref に似た型)の戻り値。EM0001として報告されます。 - ポインターまたは関数ポインターのパラメーター:
EM0002として報告されます。 ref struct(byref に似た型)のパラメーター(Span<T>/ReadOnlySpan<T>など):EM0013として報告されます。
これらの制限は .NET ランタイムに固有のものです。ポインターや ref struct はボックス化できないため、BVM の引数マーシャラーでは受け渡せません。それ以外はすべてサポートされます。ref/out/in パラメーター(構造体、列挙型、参照渡しの参照型を含む、あらゆる要素型)、値型とジェネリックインスタンスの戻り値、例外処理、反復子、async メソッドなどです。EM の完全な一覧については、付録の警告とエラーを参照してください。
これらの理由で除外されたメソッドはビルド中に報告されますが、難読化が失敗することはありません。暗号化されないまま出力されるだけです。
パフォーマンスに関する考慮事項
暗号化されたメソッドの本体も JIT コンパイルされたコードとして実行されるため、メソッド内部の処理はネイティブに近い速度で動作します。コード暗号化によって加わるのは、暗号化されたメソッドに入るたびに発生する、わずかな呼び出しごとのディスパッチコストです(引数が BVM にマーシャリングされ、結果がマーシャリングされて戻ります)。このオーバーヘッドは、実質的な処理を行うメソッドでは無視できますが、非常に頻繁に実行されるループ(数百万回の呼び出し)の中で呼び出されるごく小さなメソッドでは、支配的になることがあります。この理由から、またアセンブリを小さく高速に保つためにも、コード暗号化はコードベース全体ではなく、保護が必要な機密性の高いメソッドに限定して適用し、クリティカルパス上にある小さくて呼び出し頻度の高いヘルパーメソッドは暗号化しないでください。
コード暗号化の有効化
Babel Obfuscator では、コードベース全体を暗号化するのではなく、コードベース内の特定のメソッドを選んでコード暗号化を適用できます。これは、大量のコードを暗号化することで生じるパフォーマンスの問題を避けるためです。
暗号化するメソッドを指定するには、XML ルールまたは Obfuscation 属性を使用します。XML ルールでは、暗号化するメソッドの名前を指定できます。
<Rule name="encrypt code" feature="msil encryption" exclude="false">
<Target>Methods</Target>
<Pattern>ACME.Algorithms::*</Pattern>
<Description>Encrypt all methods of Algorithm class.</Description>
</Rule>または、Obfuscation 属性の Feature パラメーターを「msil encryption」に設定して、個々のメソッドを暗号化の対象としてマークすることもできます。
[Obfuscation(Feature = "msil encryption", Exclude = false)]
public void ProcessData()
{
// Encrypted code
}コード暗号化を有効にすると、選択したメソッドが難読化の過程で暗号化されます。
コマンドライン
babel myapp.exe --msilencryptionXML ルールや属性を使う代わりに、--msilencryption スイッチに正規表現を指定して、コード暗号化を有効にするメソッドや型を選択することもできます。たとえば、次のコマンドを見てください。
babel myapp.exe --msilencryption ACME.LicenseManager::.*このコマンドは、ACME 名前空間の LicenseManager クラスに属するすべてのメソッドを暗号化するように Babel を設定します。
MSBuild の Babel タスク
<PropertyGroup>
<MsilEncryption>true</MsilEncryption>
</PropertyGroup>
<Babel MsilEncryption="$(MsilEncryption)" />Babel Desktop
プロジェクトのキャンバスでアセンブリを選択し、プロパティパネルの「コード暗号化」グループで MsilEncryption を有効にします。必要に応じて、正規表現のリストを追加し、コード暗号化を適用する名前空間やクラスを絞り込みます。XML ルールや Obfuscation 属性で暗号化するメソッドを選択した場合は、リストを空のままにします。Babel Desktop でのプロジェクトの扱い方については、難読化プロジェクトを参照してください。
実行後は、「結果」ビューに暗号化されたメソッドが一覧表示されるので、コード暗号化が適用されたことを確認できます。
コード暗号化の統計は、出力ログ(Babel Desktop では「アクティビティ」パネル)にも表示されます。このログには、コード暗号化を含む難読化の各フェーズが記録されます。
Encrypt Msil phase, elapsed time 00.579s
Embedded resource: omJYi
size : 13170 bytes
Method statistics:
194/[ 252] resources: 76.98 %
194/[ 252] overall: 76.98 %
Number of encrypted methods: 194出力ログのコード暗号化の統計を調べると、コード暗号化がコードに適用されたかどうかを簡単に検証でき、その保護のレベルも把握できます。機密性の高いコードが正しく暗号化され、不正アクセスに対して安全に保たれていることを確認できます。