yck1509 / ConfuserEx

An open-source, free protector for .NET applications
http://yck1509.github.io/ConfuserEx/
Other
3.57k stars 1.63k forks source link

Add support for ObfuscationAttribute #24

Closed 613038475 closed 9 years ago

613038475 commented 10 years ago

Very happy to see public members rename support added, Can also add support for ObfuscationAttribute? Here is the description page: http://msdn.microsoft.com/en-us/library/system.reflection.obfuscationattribute%28v=vs.110%29.aspx

yck1509 commented 10 years ago

Sorry, but no. ObfuscationAttribute has different semantics with the internal marking process. It would also make the Marker code complicated in order to support them.

bignoncedric commented 10 years ago

I see one very good reason to support this attribute: when refactoring the code (renaming, moving clases/members), it won't require to update the configuration file.

Could you explain why "ObfuscationAttribute has different semantics with the internal marking process" ?

Here is the code I've implemented to add support for this attribute (in Marker.cs):

protected void ApplyRules(ConfuserContext context, IDnlibDef target, Rules rules)
{
    var ret = CheckObfuscationAttribute(context, target, rules);
    foreach (var i in rules)
    {
        if (!(bool)i.Value.Evaluate(target)) continue;

        if (!i.Key.Inherit)
            ret.Clear();

        FillPreset(i.Key.Preset, ret);
        foreach (SettingItem<Protection> prot in i.Key)
        {
            if (prot.Action == SettingItemAction.Add)
                ret[protections[prot.Id]] = new Dictionary<string, string>(prot, StringComparer.OrdinalIgnoreCase);
            else
                ret.Remove(protections[prot.Id]);
        }
    }

    ProtectionParameters.SetParameters(context, target, ret);
}

private ProtectionSettings CheckObfuscationAttribute(ConfuserContext context, IDnlibDef target, Rules rules)
{
    var result = new ProtectionSettings();
    var parents = GetParents(target);
    List<CustomAttribute> obfuscationAttributes = new List<CustomAttribute>();
    obfuscationAttributes.AddRange(from parent in parents
                                    from customAttribute in parent.CustomAttributes
                                    where customAttribute.TypeFullName == "System.Reflection.ObfuscationAttribute"
                                    let property = customAttribute.GetProperty("ApplyToMembers")
                                    where property != null ? (bool)property.Value : true
                                    select customAttribute);
    obfuscationAttributes.AddRange(from customAttribute in target.CustomAttributes
                                    where customAttribute.TypeFullName == "System.Reflection.ObfuscationAttribute"
                                    select customAttribute);

    if (obfuscationAttributes.Count == 0)
        return result;

    foreach (CustomAttribute obfuscationAttribute in obfuscationAttributes)
    {
        var property = obfuscationAttribute.GetProperty("Exclude");
        bool exclude = property != null ? (bool)property.Value : true;
        property = obfuscationAttribute.GetProperty("Feature");
        string feature = property != null ? ((UTF8String)property.Value).String : "all";

        if (feature == "all")
        {
            if (exclude)
                result.Clear();
            else
                foreach (var value in protections.Values)
                    result[value] = new Dictionary<string, string>(new Dictionary<string, string>(), StringComparer.OrdinalIgnoreCase);
        }
        else
        {
            if (exclude)
                result.Remove(protections[feature]);
            else
                result[protections[feature]] = new Dictionary<string, string>(new Dictionary<string, string>(), StringComparer.OrdinalIgnoreCase);
        }
    }

    return result;
}

private static IEnumerable<IDnlibDef> GetParents(IDnlibDef target)
{
    List<IDnlibDef> result = new List<IDnlibDef>();
    do
    {
        target = GetParent(target);
        if (target == null)
            break;
        result.Add(target);
    } while (true);
    result.Reverse();
    return result;
}

private static IDnlibDef GetParent(IDnlibDef target)
{
    if (target is AssemblyDef)
        return null;
    if (target is ModuleDef)
        return ((ModuleDef)target).Assembly;

    IMemberDef memberDef = target as IMemberDef;
    if (memberDef != null)
    {
        TypeDef result = memberDef.DeclaringType;
        if (result != null)
            return result;

        if (target is TypeDef)
            return ((TypeDef)target).Module;
    }
    throw new InvalidOperationException("AFAIK This shouldn't happen.");
}
yck1509 commented 10 years ago

That's one good use of ObfuscationAttribute. I'll consider supporting this feature.

By 'different semantics', the way ObfuscationAttribute works is inconsistent with ConfuserEx's rule system. Take 'Exclude' property as an example, does it means 'Exclude the whole item from protection' or 'exclude the rules in this attribute from the item'? The documentation of this attribute is ambiguous about its exact semantic and how should we interpret the attribute.

Also, it's hard to describe the rich options of ConfuserEx --- all it provides is a single Features field. Users can use the current UI to specify a protection preset, add/remove protections, and specify protection parameters. To support these options, some kind of format would have to be used.

ivan-danilov commented 9 years ago

@yck1509 Is it possible to implement ConfuserEx pattern that allows to match attributes, so that ObfuscationAttribute in question would be just a particular case? Then ConfuserEx rich options are preserved and supporting obfuscation of attributed code is possible.

I have a case when I have partially-obfuscated third-party library heavily marked with ObfuscationAttribute and license requirement that I should obfuscate the rest before shipping my own product. So I'd like to run ConfuserEx on it and have it protect everything not excluded by the attribute.

Or maybe I missed something already existing?

ElenaMilito commented 9 years ago

@yck1509 Please add ObfuscationAttribute scheme for Include and Exclude, currently rules scheme is really hard to use.