アセンブリ間のリネーム
難読化の過程で、Babel Obfuscator は、アセンブリの外部から参照できないすべてのシンボルをリネームします。これにはプライベートおよび internal のシンボルが含まれます。つまり Babel は、アセンブリの外部からアクセスすることを想定していないフィールド、メソッド、クラスなどのコード要素の名前を変更します。
Babel は、パブリックシンボルなど、アセンブリの外部から参照できるシンボルをリネームしません。パブリックシンボルはほかのアセンブリからアクセスされることを想定しており、リネームするとアプリケーションの機能が壊れるためです。そのため Babel は、ほかのアセンブリからアクセスすることを想定していないシンボルだけをリネームし、アプリケーションが意図したとおりに動作し続けるようにします。
ただし Babel には、複数のアセンブリにまたがって、パブリックメンバーと internal メンバーの両方を難読化する機能があります。これは、各アセンブリで参照されている難読化されたシンボルの名前を、XML マップファイルを使って修正することで実現します。
これが必要なのは、アセンブリを難読化するとそのシンボルの名前が変わるためです。したがって、ほかのアセンブリからこれらのシンボルへの参照は、新しい名前を反映するように更新する必要があります。入力と出力の XML マップファイルを指定すると、Babel Obfuscator はそれらを使って、関係するすべてのアセンブリ間の名前の相互参照を修正できます。これにより、難読化されたコードは正しく動作し、誤ったシンボル名が原因で壊れることがなくなります。
マップファイルは非公開のまま保管し、どのような場合でも難読化されたアプリケーションと一緒に配布しないでください。マップファイルを使うと難読化を元に戻すことができ、アプリケーションのセキュリティが損なわれます。
アセンブリ間のリネームのセットアップ
アセンブリ間のリネームをセットアップするには、リネームの処理に関係するすべてのアセンブリを考慮する必要があります。メインアセンブリのアプリケーション MainAssembly.dll が、2 つの外部コンポーネント Library1.dll と Library2.dll のパブリックインターフェイスを使用する場合を考えます。Library1.dll も、次の構成のとおり Library2.dll のパブリックインターフェイスにアクセスする必要があります。
- MainAssembly.dll
- Library1.dll
- Library2.dll
- Library1.dll
- Library2.dll
この構成は、難読化の処理に関係するアセンブリ間の関係を示しています。最初の手順は、Library1.dll と Library2.dll のパブリックシンボルを難読化するように Babel を設定することです。そのためには、両方のライブラリのソースコードに、次のアセンブリレベルのカスタム属性を追加します。
[assembly: System.Reflection.ObfuscateAssembly(true)]この属性は、外部の XML ルールファイルを使わずに、指定したアセンブリのパブリックシンボルを難読化するよう Babel に指示します。Boolean パラメーターを true に設定すると、アセンブリのパブリックインターフェイスがプライベートとして扱われ、パブリックメンバーの名前を安全に難読化できます。
または、XML ルールファイルを使って、アセンブリのパブリックインターフェイスをリネームするように Babel を設定することもできます。この方法のほうが柔軟に制御でき、パブリックインターフェイスの一部だけを選んで難読化できます。次に示すのは、すべてのパブリックメンバーの名前を強制的に難読化する、public.xml という名前の XML ルールファイルの例です。
<Rules>
<Rule name="obfuscate public" exclude="false">
<Access>Public</Access>
<Pattern isRegEx="false">*</Pattern>
<Description>Obfuscate all public symbols.</Description>
</Rule>
</Rules>ObfuscateAssembly 属性と比べると、XML ルールを使う方法では、どのパブリックシンボルを難読化するかをよりきめ細かく制御できます。Pattern 式を使って、パブリックインターフェイスのどの部分を難読化するかを指定できるため、目的に合わせた難読化の方針を立てられます。
この時点で、Library1.dll と Library2.dll は、ObfuscateAssembly 属性または XML ルールファイル(この例では public.xml)のいずれかを使用するように設定されています。
- MainAssembly.dll
- Library1.dll(public.xml で設定)
- Library2.dll(public.xml で設定)
パブリックインターフェイスをリネームするように設定した各アセンブリでは、XML マップファイルの生成を有効にする必要があります。
このファイルには、元のシンボル名と、対応する難読化された名前とのマッピングが含まれます。XML マップファイルは、難読化の処理に関係するアセンブリのうち、パブリックインターフェイスがリネームされたアセンブリを 1 つ以上参照するすべてのアセンブリで使用されます。これにより、難読化されたアセンブリ間で名前が正しく解決されます。
Library1.dll と Library2.dll を難読化するには、次の CLI 構文を使用します。
babel Library2.dll --rules public.xml --mapoutこの最初のコマンドは Library2.dll を難読化し、元のシンボル名と難読化された名前とのマッピングを含む、Library2.map.xml という名前の XML マップファイルを生成します。
Library1.dll は Library2.dll を参照し、そのパブリックインターフェイスを使用します。そのため、Library1.dll を難読化するときは、Library2.dll の難読化されたシンボルが正しく対応付けられるように、Library2.map.xml ファイルを入力として指定する必要があります。さらに、Library1.dll のパブリックインターフェイスも難読化するため、ルールファイル public.xml を読み込み、Library1.dll に対応する XML マップファイルを生成するように Babel を設定します。
この手順の CLI コマンドは次のとおりです。
babel Library1.dll --rules public.xml --mapout --mapin Library2.map.xmlこれにより、Library1.dll は Library2.dll の難読化されたシンボルを正しく参照し、同時に、難読化の以降の処理で使用する自身のマップファイルも生成します。
最後に、MainAssembly.dll を難読化するには、Library1.dll と Library2.dll の両方の XML マップファイルを読み込むように Babel を設定する必要があります。これらのアセンブリは「MainAssembly」から参照されているためです。これにより、「MainAssembly」は難読化の処理中に、依存するライブラリの難読化されたシンボルを正しく解決できます。
この手順の CLI コマンドは次のようになります。
babel MainAssembly.dll --mapin Library1.map.xml --mapin Library2.map.xmlこのコマンドは、先に生成したマップファイル(Library1.map.xml と Library2.map.xml)を読み込み、これらのライブラリの難読化されたシンボルへの参照が「MainAssembly」で正しく処理されるようにします。
アセンブリを難読化するときは、正しい順序を守ることが重要です。Library2.dll や Library1.dll のように、ほかのアセンブリから参照されるライブラリを先に難読化して、必要なマップファイルを生成しなければなりません。その後、Library1.dll や MainAssembly.dll のように依存する側のアセンブリを、マップファイルを使って難読化できます。
MSBuild タスクからのセットアップ
MSBuild でアセンブリ間のリネームを設定するには、難読化プロジェクトに関係する各アセンブリについて、XML ルールファイルに加えて、入力と出力の XML マップファイルを指定する必要があります。難読化される各アセンブリは XML マップファイルを生成し、そのファイルは、このターゲットアセンブリを参照する、難読化されるほかのすべてのアセンブリに入力として渡されます。
次に、1 つのメインアセンブリと、参照される 2 つのアセンブリが次の構成になっている場合の、アセンブリ間のリネームの設定例を示します。
- MainAssembly.dll
- Library1.dll
- Library2.dll
- Library1.dll
- Library2.dll
依存関係のない Library2 プロジェクトから始めます。ほかのアセンブリに依存しないため、入力の XML マップファイルを必要とせず、単独で難読化できます。
Library2 アセンブリのプロジェクト
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<GenerateMapOutFile>true</GenerateMapOutFile>
</PropertyGroup>
<Target Name="Obfuscate" AfterTargets="CoreCompile">
<ItemGroup>
<RulesFile Include="path\to\referenced\public.xml" />
</ItemGroup>
<Babel Input="$(TargetPath)" RulesFiles="@(RulesFile)"
GenerateMapOutFile="$(GenerateMapOutFile)" />
</Target>
</Project>Library1 は Library2 を参照しているため、難読化プロジェクトでは、GenerateMapOutFile=true で XML マップファイルを生成するだけでなく、Library2 用に生成されたマップファイルも参照する必要がある点に注意してください。
Library1 アセンブリのプロジェクト
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<Reference Include="path\to\referenced\Library2.dll" />
</ItemGroup>
<PropertyGroup>
<GenerateMapOutFile>true</GenerateMapOutFile>
</PropertyGroup>
<Target Name="Obfuscate" AfterTargets="CoreCompile">
<ItemGroup>
<MapInFile Include="path\to\referenced\Library2.dll.map.xml" />
</ItemGroup>
<ItemGroup>
<RulesFile Include="path\to\referenced\public.xml" />
</ItemGroup>
<Babel Input="$(TargetPath)" MapInFiles="@(MapInFile)" RulesFiles="@(RulesFile)"
GenerateMapOutFile="$(GenerateMapOutFile)" />
</Target>
</Project>MainAssembly プロジェクトは、パブリックインターフェイスが難読化された 2 つのライブラリ Library1 と Library2 を参照しています。そのため、各ライブラリ用に生成された 2 つの XML マップファイルを読み込むように Babel タスクを設定する必要があります。
メインアセンブリのプロジェクト
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<Reference Include="path\to\referenced\Library1.dll" />
<Reference Include="path\to\referenced\Library2.dll" />
</ItemGroup>
<Target Name="Obfuscate" AfterTargets="CoreCompile">
<ItemGroup>
<MapInFile Include="path\to\referenced\Library1.dll.map.xml" />
<MapInFile Include="path\to\referenced\Library2.dll.map.xml" />
</ItemGroup>
<Babel Input="$(TargetPath)" MapInFiles="@(MapInFile)" />
</Target>
</Project>これにより、Library1 と Library2 の間の相互参照が、難読化の処理中に正しく処理されます。Library2 用に生成された XML マップファイルを参照しないと、Library1 の難読化で 2 つのライブラリ間の相互参照が正しく処理されず、実行時に問題が発生するおそれがあります。そのため、アセンブリ間のリネームを設定するときは、必要な XML マップファイルがすべて正しく生成され、参照されるようにすることが不可欠です。
Babel Desktop からのセットアップ
Babel Desktop のプロジェクトには、関係するすべてのアセンブリを含められます。プロジェクトのキャンバスで、各ライブラリをそれを使用するアセンブリに接続し、「マップ ファイルを渡す」を選択します。するとライブラリが自身のマップファイルを書き出し、使用する側のアセンブリがそれを読み込み、ライブラリが先に難読化されます。上記の例では、Library2 を Library1 と MainAssembly に、Library1 を MainAssembly に接続します。「実行順序のみ」の接続は、順序を設定するだけで、マップファイルは渡しません。
パブリックシンボルをリネームするルールは、XML ルールまたは RulesFiles を使って、これまでどおり各ライブラリに追加します。ターゲットのプロパティの「マップ ファイル」グループには、各ターゲットが書き出すマップと読み込むマップが表示され、以前のビルドのマップファイルも追加できます。実行順序とマップファイルを参照してください。