В .NET есть ObfuscationAttibute. Но я не понимаю, как исключить код внутри конструктора из обфускации.

// Obfuscated class
class MyClass {
    [Obfuscation(Exclude = true)] // "Attribute 'Obfuscation' is not valid on this declaration type"
    public MyClass() {
        //some code, I need to exclude this code from obfuscation
    }
    // Obfuscated method
    public void Method1() {
        //some code
    |
    // Obfuscated method
    public void Method2() {
        //some code
    |
}

UPD: Речь идет НЕ о переименовании конструктора. Его имя явно стало ".ctor". Мне нужно предотвратить обфускацию самого кода. Да, некоторые обфускаторы не только переименовывают символы, но и изменяют код. Да, я знаю, что не могу этого сделать с этим атрибутом. Компилятор говорит то же самое. Я уже знаю, что не могу. Я спрашиваю, что я могу сделать, желательно использовать только стандартные инструменты .net.

2
Alex Butenko 26 Фев 2015 в 07:59

4 ответа

Лучший ответ

Вы можете делать все, что хотите, используя только ObfuscationAttribute, но это утомительно: применять [Obfuscation(ApplyToMembers=false)] к классу и [Obfuscation] к каждому отдельному члену кроме конструктора.

В качестве альтернативы используйте конфигурацию вашего обфускатора, чтобы исключить конструктор из рассмотрения. Поскольку ObfuscationAttribute предлагает только очень ограниченное управление (в основном, просто включение и выключение функций), большинство из них имеют отдельную конфигурацию для детального управления.

Наконец, подумайте о том, чтобы сделать ваш конструктор настолько простым и неинтересным, что не имеет значения, запутан поток или нет. В идеале так и должно быть - если ваш конструктор выполняет только инициализацию членов, то в первую очередь особо нечего запутывать. Вы можете вызывать функции-члены для более сложных вещей, и вы можете контролировать обфускацию тех, кто использует атрибут.

6
Jeroen Mostert 26 Фев 2015 в 11:44

Почему [Атрибут обфускации] не разрешен для конструкторов

Вы не можете поместить [Obfuscation(Exclude = true)] в конструктор потому что обфускация переименовывает символы , а не содержимое методов (обычно - более продвинутые обфускаторы могут изменять поток кода, изменять константы и т. д., чтобы произвести обратное проектирование сложнее) .

Например, рассмотрим следующее:

// obfuscated class
public class MyClass
{
    public MyClass()
    {
    }

    public void MyMethod()
    {
    }
}

// unobfuscated class
public class CallingClass
{
    public static void TestMyClass()
    {
        MyClass class = new MyClass();
        class.MyMethod();
    }
}

Обфускатор переименовал бы MyClass во что-то другое (например, qfghjigffvvb) и MyMethod() во что-то еще (например, ghjbvxdghh()) и изменил бы все ссылки так, чтобы код по-прежнему работал, т.е.

public class qfghjigffvvb
{
    public qfghjigffvvb()
    {
    }

    public void ghjbvxdghh()
    {
    }
}

// unobfuscated class
public class CallingClass
{
    public static void TestMyClass()
    {
        qfghjigffvvb class = new qfghjigffvvb();
        class.ghjbvxdghh();
    }
}

Если вы поместите атрибут [Obfuscation(Exclude = true)] в конструктор для MyClass, то CallingClass.TestMyClass() будет выглядеть так:

public class CallingClass
{
    public static void TestMyClass()
    {
        qfghjigffvvb class = new MyClass(); // ?
        class.ghjbvxdghh();
    }
}

Если вам нужно, чтобы содержимое конструктора MyClass не запутывалось, вам нужно поместить атрибут [Obfuscation(Exclude = true)] во все, что он вызывает, чтобы символы не переименовать.


Мысленный эксперимент: исключение содержимого конструктора

Допустим, у вас есть атрибут [ContentObfuscation], который можно использовать, чтобы предотвратить обфускацию содержимого метода (или конструктора, или свойства). Что бы вы хотели, чтобы он здесь делал?

public class MyClass
{
    [ContentObfuscation(Exclude = true)]
    public MyClass()
    {
        // SecurityCriticalClass is obfuscated
        var securityCriticalClass = new SecurityCriticalClass();
        securityCriticalClass.DoSomeTopSecretStuff();
    }
}

Если содержимое конструктора не запутывается, то SecurityCriticalClass также не должно быть запутано, что может создать проблему безопасности.

0
Wai Ha Lee 26 Фев 2015 в 08:21

Я полностью согласен с комментариями, отмечая, что обфускация - это не только переименование, и, похоже, упущение в том, что конструкторы не считались допустимой целью для [Obfuscation]. Я столкнулся с проблемой удаления мертвого кода, когда обфускатор может удалить код, который недоступен (я упрощаю). Иногда требуется переопределение этого поведения, например, для сценариев отражения / сериализации, и оно может в равной степени применяться к конструкторам так же, как и к любому другому элементу кода. Обратите внимание, что [AttributeUsage] носит рекомендательный характер и обеспечивается компилятором C # (или VB). CLR не применяет его. Итак, если ваш обфускатор предназначен для поиска [Obfuscation] в конструкторах (что вполне может иметь место случайно, учитывая, что некоторая логика обфускатора может обрабатывать все методы одинаково), и вы можете использовать какую-то структуру обработки IL после компиляции (например, PostSharp), тогда вы можете поместить [Obfuscation] в конструкторы. Для пользователей PostSharp вот многоадресная версия ObfuscationAttribute, которая с радостью применит [Obfuscation] к конструкторам:

using System;
using PostSharp.Aspects;
using PostSharp.Extensibility;
using PostSharp.Reflection;
using System.Collections.Generic;
using System.Reflection;

/// <summary>
/// A multicast adapter for <see cref="ObfuscationAttribute"/>. Instructs obfuscation tools to take the specified actions for the target assembly, type, or member.
/// </summary>
[AttributeUsage( AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.Delegate | AttributeTargets.Constructor, AllowMultiple = true, Inherited = false )]
[MulticastAttributeUsage( 
    MulticastTargets.Assembly | MulticastTargets.Class | MulticastTargets.Struct | MulticastTargets.Enum | MulticastTargets.Method | MulticastTargets.Property | MulticastTargets.Field | MulticastTargets.Event | MulticastTargets.Interface | MulticastTargets.Parameter | MulticastTargets.Delegate | MulticastTargets.InstanceConstructor | MulticastTargets.InstanceConstructor,
    AllowMultiple = true,
    PersistMetaData = false)]
public sealed class MulticastObfuscationAttribute : MulticastAttribute, IAspectProvider
{
    bool _stripAfterObfuscation = true;
    bool _exclude = true;
    bool _applyToMembers = true;
    string _feature = "all";

    bool _stripAfterObfuscationIsSpecified;
    bool _excludeIsSpecified;
    bool _applyToMembersIsSpecified;
    bool _featureIsSpecified;

    static readonly ConstructorInfo ObfuscationAttributeCtor = typeof( ObfuscationAttribute ).GetConstructor( Type.EmptyTypes );

    IEnumerable<AspectInstance> IAspectProvider.ProvideAspects( object targetElement )
    {
        var oc = new ObjectConstruction( ObfuscationAttributeCtor );

        if ( _applyToMembersIsSpecified )
            oc.NamedArguments[ nameof( ObfuscationAttribute.ApplyToMembers ) ] = _applyToMembers;

        if ( _excludeIsSpecified )
            oc.NamedArguments[ nameof( ObfuscationAttribute.Exclude ) ] = _exclude;

        if ( _featureIsSpecified )
            oc.NamedArguments[ nameof( ObfuscationAttribute.Feature ) ] = _feature;

        if ( _stripAfterObfuscationIsSpecified )
            oc.NamedArguments[ nameof( ObfuscationAttribute.StripAfterObfuscation ) ] = _stripAfterObfuscation;

        return new[] { new AspectInstance( targetElement, new CustomAttributeIntroductionAspect( oc ) ) };
    }

    /// <summary>
    /// Gets or sets a <see cref="T:System.Boolean" /> value indicating whether the obfuscation tool should remove this attribute after processing.
    /// </summary>
    /// <returns>
    /// <see langword="true" /> if an obfuscation tool should remove the attribute after processing; otherwise, <see langword="false" />. The default is <see langword="true" />.
    /// </returns>
    public bool StripAfterObfuscation
    {
        get => _stripAfterObfuscation;
        set
        {
            _stripAfterObfuscationIsSpecified = true;
            _stripAfterObfuscation = value;
        }
    }

    /// <summary>
    /// Gets or sets a <see cref="T:System.Boolean" /> value indicating whether the obfuscation tool should exclude the type or member from obfuscation.
    /// </summary>
    /// <returns>
    /// <see langword="true" /> if the type or member to which this attribute is applied should be excluded from obfuscation; otherwise, <see langword="false" />. The default is <see langword="true" />.
    /// </returns>
    public bool Exclude
    {
        get => _exclude;
        set
        {
            _excludeIsSpecified = true;
            _exclude = value;
        }
    }

    /// <summary>
    /// Gets or sets a <see cref="T:System.Boolean" /> value indicating whether the attribute of a type is to apply to the members of the type.
    /// </summary>
    /// <returns>
    /// <see langword="true" /> if the attribute is to apply to the members of the type; otherwise, <see langword="false" />. The default is <see langword="true" />.
    /// </returns>
    public bool ApplyToMembers
    {
        get => _applyToMembers;
        set
        {
            _applyToMembersIsSpecified = true;
            _applyToMembers = value;
        }
    }

    /// <summary>
    /// Gets or sets a string value that is recognized by the obfuscation tool, and which specifies processing options.
    /// </summary>
    /// <returns>
    /// A string value that is recognized by the obfuscation tool, and which specifies processing options. The default is "all".
    /// </returns>
    public string Feature
    {
        get => _feature;
        set
        {
            _featureIsSpecified = true;
            _feature = value;
        }
    }
}
2
tg73 12 Июн 2019 в 15:00

Конструкторы всегда внутренне переименовываются в .ctor, вы не можете использовать обфусцированное имя (но вы также не можете использовать исходное имя). И декомпиляторы назовут конструктор обфусцированным именем класса.

Я полагаю, вы имеете в виду обфускацию кода внутри функции, а не имени члена? Предположительно, более продвинутый обфускатор, поддерживающий реорганизацию кода, а не только обфускацию имени, будет иметь свой собственный атрибут для управления этим ... потому что System.Reflection.ObfuscationAttribute не подходит для управления более мощными методами обфускации.

В частности, AttributeUsageAttribute в классе ObfuscationAttribute не включает AttributeTargets.Constructor в качестве разрешенного использования.

5
Ben Voigt 26 Фев 2015 в 05:03