Dotfuscator は、ソース コードでなくコンパイルされた .NET アセンブリで機能するビルド後のツールです。 このため、Dotfuscator によるアプリケーションの保護方法を指定するオプションの大部分は、ソース コードから独立した Dotfuscator 構成ファイルに保存されます。
ただし、ソース コードへのアクセス権がある場合は、.NET 属性を使用して一部の Dotfuscator 機能を構成することもできます。
Dotfuscator は、アセンブリを処理するときに特定の属性を認識します。それらの属性では、アノテーションが付けられたコード要素を Dotfuscator で処理する方法が構成されています。 既定では、Dotfuscator はアセンブリの処理中にこれらの属性の除去も行い、出荷されるアプリケーションに重要な構成情報が含まれないようにしています。
互換性のある属性
Dotfuscator は、特定の属性のみを認識し、他の属性を無視します。 Dotfuscator によって認識される属性は次のとおりです。
各属性のセットの詳細については、リンク先ページを参照してください。 このページの残り部分では、多くの属性に共通する側面について説明します。
属性を使用するタイミング
属性を使用することで、ソース コードを読む際に、Dotfuscator がコード要素にどのように作用するかがわかりやすくなります。 たとえば、次の C# のスニペットは、ObfuscationAttribute
を使用して、クラス(そのメンバーではなく)を名前の変更対象から除外することを示しています。
using System.Reflection;
[Obfuscation(Feature = "renaming", Exclude = true, ApplyToMembers = false)]
private class MyClass { /* ...*/ }
しかし、属性を使用するより、Dotfuscator のユーザー インターフェイスを使用して Dotfuscator 構成ファイルを変更する方が、より良く実現できる場合もいくつかあります。 次のようなシナリオが挙げられます。
- ソース コードを編集できないアセンブリを使用する場合
- 保護設定を変更するたびにコードを再コンパイルするのが、開発プロセスのオーバーヘッドとしては大きすぎる場合
- 規則を使用してコード項目を難読化対象から除外した方が、個々のコード項目に属性でアノテーションを付けるより簡単または効率的な場合
- 複数の場所を対象とするチェックを構成する場合
属性と Dotfuscator 構成ファイルの設定を組み合わせることができます。 たとえば、上記のスニペットは、名前の変更対象から MyClass
を除外することを Dotfuscator に指示していますが、Dotfuscator ユーザー インターフェイスを使用して他の型を除外し、それらの対象除外を構成ファイルに保存しておくことができます。 Dotfuscator は、構成ファイルを使ってアセンブリを処理する際、属性または構成ファイルによって除外されているコード項目の名前を変更しません。
コードへの属性の追加
コードに属性を追加し、それらの属性を Dotfuscator に認識させるには
-
プロジェクトに適切な参照を追加します。 詳細については、以下を参照してください。
-
コードに互換性のある属性を適用します。適用方法は通常の属性の場合と同様です。
-
名前空間(このため、必要な
using
ステートメント)は、属性によって異なります。 詳細については、各属性のセクションを参照してください。 -
他の属性と同様に、使用する際にはサフィックス
Attribute
を省略できます。 たとえば、次はTamperCheckAttribute
の使用例です。[TamperCheck(Action = CheckAction.Exit)] public void MyMethod() { // メソッド本体 }
-
-
アプリケーションをビルドします。
-
難読化属性を使用する場合は、Dotfuscator のユーザー インターフェイスを使って以下の設定を構成します。
-
チェック属性を使用する場合は、Dotfuscator のユーザー インターフェイスを使って以下の設定を構成します。
-
チェック属性が含まれるアセンブリごとに、[チェック属性の使用]オプションと[チェック属性の除去]オプションが有効になっていることを確認します。
-
チェックが有効になっていることを確認します。
-
-
構成ファイルをビルドします。 Dotfuscator は、構成された属性に従って動作し、その後で、アプリケーションから属性(および関連するアセンブリ参照)を削除します。
アプリケーション コードとの対話
既存のアプリケーション コードは、Dotfuscator によって差し込まれたコードから情報を取得することができます。そのようなアプリケーション コードは、シンクと呼ばれます。
各チェックで、さまざまなコンテキストのために、1 つ以上のシンクが定義できます。 チェックのシンクは、次の 3 つのプロパティで定義されます。
-
element プロパティ。フィールドやメソッドなど、シンクとなるコード項目の種類を指定します。 詳細については、シンク要素の種類サブセクションを参照してください。
-
name プロパティ。コード項目の名前を指定します(該当する場合)。
-
省略可能な owner プロパティ。コード項目を定義する型を指定します(該当する場合)。 指定されていない場合は、チェックの場所を定義する型が既定値になります。 詳細については、オーナー サブセクションを参照してください。
たとえば、チェックが実行された場合、チェックはアプリケーション通知シンクを介して、結果をアプリケーションに通知できます。 シンクは、チェックの ApplicationNotificationSink プロパティを使って構成できます。
-
ApplicationNotificationSinkElement
-
ApplicationNotificationSinkName
-
ApplicationNotificationSinkOwner
特定のチェックに使用できるシンクの詳細については、チェック属性ページの関連セクションに記載されています。
シンク要素の種類
このセクションでは、差し込まれたコードのシンクとして使用できるコード要素の種類を列挙します。
サポートされている要素、要素の署名、シンクに提供される値の意味は、チェックによって異なることに留意してください。 詳細については、チェック属性ページを参照してください。
たとえば、チェックのアプリケーション通知シンクには、bool
型のフィールドまたはプロパティ、あるいは void(bool)
署名付きのメソッド、デリゲート フィールド、またはデリゲート メソッド引数を指定する必要があります。 ブール値は、チェックが不正な状態(デバッガーがアタッチされている、改ざんされている、など)を検出した場合は true
、検出されなかった場合は false
です。
以下に、チェックの element プロパティ(たとえば、改ざんチェックの ApplicationNotificationSinkElement)に使用可能な値を列挙します。 使用可能なシンク要素の種類は以下のとおりです。
-
None:シンクは無効であり、差し込まれたコードはアプリケーションに情報を提供しません。
-
通常、これが element プロパティの既定値です。
-
name プロパティおよび owner プロパティは、この設定では無視されます。
-
-
Method:差し込まれたコードはメソッドを呼び出し、そのメソッドのパラメーターを介して情報を提供します。 このメソッドは、チェックのすべての場所からアクセス可能である必要があります。
-
name プロパティには、このメソッドの単純名(たとえば、
void MyMethod(bool)
でなくMyMethod
)を指定します。 -
owner プロパティには、このメソッドを宣言する型を指定します。
-
-
Field:差し込まれたコードは、フィールドを設定することによって情報を提供します。 このフィールドは、チェックのすべての場所からアクセス可能かつ設定可能である必要があります。
-
name プロパティには、このフィールドの単純名を指定します。
-
owner プロパティには、このフィールドを宣言する型を指定します。
-
-
Property:差し込まれたコードは、プロパティを設定することによって情報を提供します。 このプロパティとその setter は、チェックのすべての場所からアクセス可能である必要があります。
-
name プロパティには、このプロパティの単純名を指定します。
-
owner プロパティには、このプロパティを宣言する型を指定します。
-
-
MethodArgument:差し込まれたコードは、メソッド引数で指定されたデリゲートを呼び出し、そのデリゲートのパラメーターを介して情報を提供します。 メソッド引数は、チェックのすべての場所に対応する引数である必要があります。
-
name プロパティには、メソッド引数の名前を指定します。
-
owner プロパティはこの設定では無視されます。
-
-
Delegate:差し込まれたコードは、フィールドで指定されたデリゲートを呼び出し、そのデリゲートのパラメーターを介して情報を提供します。 このフィールドは、チェックのすべての場所からアクセス可能である必要があります。
-
name プロパティには、このフィールドの単純名を指定します。
-
owner プロパティには、このフィールドを宣言する型を指定します。
-
-
DefaultAction:差し込まれたコードは、情報に基づくいくつかの既定の動作を実行します。 正確な動作は、構成する特定のシンクによって異なり、この設定を無効な構成としているものもあります。
-
これは、その名前に反して、必ずしも element プロパティの既定値ではありません。
-
name プロパティおよび owner プロパティは、この設定では無視されます。
-
オーナー
シンクの owner は、そのシンクを宣言する型です。
owner プロパティの値は、アセンブリ名ではなく名前空間を含めて表される型名です。 たとえば、名前空間 Outer.Inner
で宣言されたクラス MyType
のフィールド wasTampered
について考えてみましょう。 このフィールドにシンクを定義するプロパティは、以下のようになります。
-
element プロパティ: Field
-
name プロパティ:
wasTampered
-
owner プロパティ:
Outer.Inner.MyType
シンクには、オーナーのインスタンス メンバーまたは静的メンバーを使用できます。 この違いは、owner プロパティの使用方法に影響します。 また、複数の場所を持つチェックを使用する場合には、各場所に異なるオーナーを参照させることができます。
静的メンバーの場合
シンクが静的メンバーである場合は、シンクは、チェックのすべての場所からアクセス可能であれば、どのような型で定義されていてもかまいません。 これがどの型であるかを owner プロパティに指定します。 このプロパティの値が空白である場合は、チェックの場所を定義している型と見なされます。
インスタンス メンバーの場合
シンクがインスタンス メンバーである場合は、次の条件を満たしている必要があります。
-
チェックの場所もインスタンス メンバーである。
-
チェックの場所は、シンクを宣言した型と同じ型で定義されている。
-
owner プロパティは、この型の名前であるか、または空白である。
実行時、場所を呼び出す際に使用されたインスタンスが、シンクにも使用されます。
複数のオーナー
複数の場所を持つチェックを使用する場合、各場所は、シンクに関して個々に評価されます。 つまり、次の条件を満たしていれば、各場所が異なるシンクを持つことができます。
-
チェックの場所を定義する各型に、シンクのメンバーが指定されている。
-
特定の場所が静的メンバーである場合は、対応するシンクのメンバーも静的メンバーである必要があります。
-
特定の場所がインスタンス メンバーである場合は、対応するシンクのメンバーはインスタンス メンバーまたは静的メンバーのどちらでもかまいません。
-
-
owner プロパティが空白である。