You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

.Net программа

Для работы .NET программы в ОС Linux необходимо настроить переменную среды для поиска библиотеки защиты (по умолчанию название protectstorage*). При этом библиотека должна находиться в одном каталоге с защищенными файлами.

Символьная обфускация

Чтобы выделить участки кода, которые не требуется защищать при помощи символьной обфускации, необходимо добавить специальные атрибуты.

Ограничения

Не переименовываются:

Не гарантируется поддержка сборок с Reflection API и GUI-фреймворков, реализующих MVVM (в частности, WPF и AvaloniaUI).

Не поддерживаются сборки, использующие метод System.Windows.DependencyProperty.RegisterAttached().

Логика работы с System.Reflection.ObfuscationAttribute и System.Reflection.ObfuscateAssemblyAttribute

  • Исключения применяются только для символьной обфускации. Причем для ObfuscationAttribute значение свойства Feature (если оно задается) должно быть одним из следующих (без учета регистра): "Renaming", "Default", "All". Отсутствующее свойство Feature интерпретируется как имеющее значение "Default", т.е. исключения не игнорируются.
  • Выбор (исключить или нет) осуществляется, исходя из значения ObfuscationAttribute либо ObfuscateAssemblyAttribute с наибольшей вложенностью для данного символа. Вычисление уточняется от потенциально исключаемого символа к сборке вверх по иерархии вложенности символов.

Иерархия вложенности символов:

      • конечный член (метод, поле, свойство, событие)
      • тип(-ы)
      • модуль
      • сборка
  • Анализ ObfuscationAttribute происходит в соответствии с логикой, изложенной в официальной документации. При анализе текущего символа сначала проверяется наличие ObfuscationAttribute для него самого. Если такой атрибут есть, то исключение символа происходит в соответствии со значением флага Exclude (значение по умолчанию интерпретируется как true). Если атрибута нет, то анализируются атрибуты для родительских символов вверх по иерархии вложенности символов. Если находится родительский символ, для которого задан атрибут, то исключение символа происходит в соответствии со значениями его флагов Exclude и ApplyToMembers (значение по умолчанию интерпретируется как true). Если ApplyToMembers имеет значение false, то поиск следующего ObfuscationAttribute продолжается дальше вверх по иерархии символов. Если поиск доходит до уровня сборки, происходит анализ ObfuscateAssemblyAttribute.
  • Анализ ObfuscateAssemblyAttribute. При анализе текущей сборки проверяется значение флага AssemblyIsPrivate (значение по умолчанию интерпретируется как false). Если AssemblyIsPrivate имеет значение false, то вся сборка исключается из обфускации целиком.

Защита методов

Не защищаются:

  1. Методы структур
  2. Конструкторы и деструкторы, а также методы, вызываемые (прямо или косвенно) из деструкторов
  3. Обобщенные (шаблонные) методы (дженерики) и методы обобщенных (шаблонных) классов (дженериков)
  4. Методы, имеющие обработчики исключений типов [https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/keywords/when  ] Filter (с использованием ключевого слова when в выражении catch) и Fault (не встречается в C#)
  5. Методы, включающие [https://docs.microsoft.com/ru-ru/dotnet/api/system.reflection.emit.opcodes.calli] инструкцию Calli (обращающиеся к нативным unmanaged функциям и методам)
  6. Методы, помеченные с применением кастомных атрибутов
  7. Методы, не имеющие тела

Не рекомендуется защищать методы-аксессоры (get_* и set_*). Но в случае такой необходимости следует использовать тривиальные свойства или выделять код в отдельный метод.

Обфускация внешних интерфейсов

Чтобы переименованные символы, экспортируемые защищаемым dll-файлом, были доступны для других файлов программы, не включенных в Проект защиты, необходимо в исходную программу добавить атрибуты обфускации, исключив вручную все необходимые символы.

Обработка исключений

Опция использования исключений для сборок .NET позволяет перехватывать ошибки автоматической защиты как исключения. Перехват генерируемых исключений требует некоторых дополнительных усилий – в простейшем случае, использования приведенной конструкции try-catch в теле метода Main. Проверку и обработку исключений рекомендуется выносить в отдельный метод, помеченный атрибутом ObfuscationAttribute для исключения шифрования строк; в противном случае из-за обращения к зашифрованным строкам возникнет повторная ошибка автоматический защиты.

Пример  модификации функции Main для приложения на WPF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
[System.Reflection.Obfuscation(Feature = "stringencryption")]
 
public static void Main() {
    try
    {
        SampleWpfApp1.App app = new SampleWpfApp1.App();
        app.InitializeComponent();
        app.Run();
    }
    catch (System.Reflection.TargetInvocationException ex) when (ex.InnerException != null)
    {
        Exception inner = ex.InnerException;
        object obj = inner.Data["Mark"];
        if (obj != null && obj is string && obj as string == "GUARDANT")
            MessageBox.Show(string.Format(
                "Guardant exception:\n" +
                "Mark = GUARDANT\n" +
                "Message = {0}\n" +
                "Code = {1}",
                inner.Message,
                (int)inner.Data["Code"]));
    }
}

Обработка ошибок в примере выше соответствует исключениям, генерируемым в случае ошибки, инфраструктурой автоматической защиты сборок .NET, а именно:

  1. генерируется обычное исключение System.Exception (используется для простоты, чтобы вендор мог написать обработку исключений без линковки дополнительных библиотек);
  2. текст для поля Message берется из библиотеки защиты, как и в других случаях (защита с использованием message box, защита сервисов и т.д.);
  3. в поле Data записываются следующие значения:
    1. по ключу Mark записывается значение (string) «GUARDANT», которое позволяет однозначно отличать исключения, генерируемые автоматической защитой, от прочих исключений,
    2. по ключу Type записывается значение (string) «Guardant Software Licensing Kit»,
    3. по ключу Code записывается код ошибки автоматической защиты (int),
    4. по ключу Expected (только для ошибки среды с кодом «-2») записывается ожидаемое имя библиотеки защиты (string) в генерализированном виде.

Исключение, генерируемое защищенным в автоматическом режиме приложением, обертывается системными библиотеками .NET в TargetInvocationException, поэтому оказывается необходимо перехватывать именно такое исключение. Естественно, необходимо убедиться, что методы, используемые при обработке ошибок от автоматической защиты, не защищаются – достаточно не выбирать их для защиты и добавить в исключения шифрования строк (пометив эти методы атрибутом ObfuscationAttribute).

Также важно отметить, что существуют внутренние ошибки, связанные с взаимодействием между защищенной сборкой .NET и библиотекой защиты (нативной, для данной платформы). Для них также генерируются исключения, но без сообщений (т.к. получить подготовленные вендором сообщения об ошибках невозможно, из-за самой ошибки обращения к библиотеке защиты), и эти генерируемые исключения также обертываются в системные исключения, например, в System.TypeInitializationException.

  • No labels