编译器生成的匿名类型错误混淆的类

时间:2018-10-25 16:04:41

标签: obfuscation crypto-obfuscator

此问题末尾的代码在Source上具有GetHashCode()。匿名类型也是如此:编译器会生成类似的代码。

使用Crypto Obfuscator,当您指定重命名方法时,GetHashCode公共方法被重命名。结果是GroupBy返回了错误的元素:应该相等的元素被认为是不同的,因为它们引用了不同的对象,并且使用了默认的GetHashCode实现。

是否有一种明智的方法来禁用诸如GetHashCode()之类的基本方法上的Crypto Obfuscator重命名,尤其是当它们由编译器自动生成时?

还是我们必须完全停止使用匿名类型,将其替换为显式类型,并确保所有的GetHashCode和Equals方法都正确地使用了Obfuscation属性修饰?

未混淆的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Invantive.Basics
{
    /// <summary>
    /// Check obfuscation not too aggressive.
    /// </summary>
    [Obfuscation(ApplyToMembers=false, Exclude = true)]
    public static class ObfuscationAsserter
    {
        private class Source
        {
            public string S1;
            public string S2;

            public Source(string s1, string s2)
            {
                this.S1 = s1;
                this.S2 = s2;
            }

            public override int GetHashCode()
            {
                return 23 * this.S1.GetHashCode() + this.S2.GetHashCode();
            }

            public override bool Equals(object o)
            {
                if (o is Source s)
                {
                    return s.S1 == this.S1 && s.S2 == this.S2;
                }
                else
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Check anonymous types etc. are correctly obfuscated.
        /// </summary>
        public static void Check()
        {
            List<Source> strings = new List<Source>();
            strings.Add(new Source("a", "a"));
            strings.Add(new Source("a", "b"));
            strings.Add(new Source("a", "b"));
            strings.Add(new Source("c", "c"));

            int expected = 3;
            int t1cnt = strings.GroupBy(x => new { x.S1, x.S2 }).ToList().Count();
            int t2cnt = strings.GroupBy(x => new { x.S1, x.S2 }.GetHashCode()).ToList().Count();
            int t3cnt = strings.GroupBy(x => x.S1 + x.S2).ToList().Count();
            int t4cnt = strings.GroupBy(x => (x.S1 + x.S2).GetHashCode()).ToList().Count();
            int t5cnt = strings.GroupBy(x => x).ToList().Count();
            int t6cnt = strings.GroupBy(x => x.GetHashCode()).ToList().Count();
            int t7cnt = strings.GroupBy(x => (x.S1, x.S2)).ToList().Count();
            int t8cnt = strings.GroupBy(x => (x.S1, x.S2).GetHashCode()).ToList().Count();

            InvantiveTrace.WriteLine($"t1: {t1cnt}, t2: {t2cnt}, t3: {t3cnt}, t4: {t4cnt}, t5: {t5cnt}, t6: {t6cnt}, t7: {t7cnt}, t8: {t8cnt}.");

            if (t1cnt != expected)
            {
                throw new Exception($"t1 is {t1cnt:N0} versus expected {expected:N0}.");
            }

            if (t2cnt != expected)
            {
                throw new Exception($"t2 is {t2cnt:N0} versus expected {expected:N0}.");
            }

            if (t3cnt != expected)
            {
                throw new Exception($"t3 is {t3cnt:N0} versus expected {expected:N0}.");
            }

            if (t4cnt != expected)
            {
                throw new Exception($"t4 is {t4cnt:N0} versus expected {expected:N0}.");
            }

            if (t5cnt != expected)
            {
                throw new Exception($"t5 is {t5cnt:N0} versus expected {expected:N0}.");
            }

            if (t6cnt != expected)
            {
                throw new Exception($"t6 is {t6cnt:N0} versus expected {expected:N0}.");
            }

            if (t7cnt != expected)
            {
                throw new Exception($"t7 is {t7cnt:N0} versus expected {expected:N0}.");
            }

            if (t8cnt != expected)
            {
                throw new Exception($"t8 is {t8cnt:N0} versus expected {expected:N0}.");
            }
        }
    }
}

运行良好:Check()不会引发异常。

沉迷于重命名

WZ已被GroupBy使用,因此不应该引入它们:

private class D
{
    public string J;
    public string V;

    public D(string text1, string text2)
    {
        this.J = text1;
        this.V = text2;
    }

    public override int W() => 
        ((0x17 * this.J.GetHashCode()) + this.V.GetHashCode());

    public override bool Z(object obj1)
    {
        ObfuscationAsserter.D d = obj1 as ObfuscationAsserter.D;
        if (d == null)
        {
            return false;
        }
        return ((d.J == this.J) && (d.V == this.V));
    }
}

混淆而不重命名

这仍然可以正常工作:

private class Source
{
    public string S1;
    public string S2;

    public Source(string s1, string s2)
    {
        this.S1 = s1;
        this.S2 = s2;
    }

    public override bool Equals(object o)
    {
        ObfuscationAsserter.Source source = o as ObfuscationAsserter.Source;
        if (source == null)
        {
            return false;
        }
        return ((source.S1 == this.S1) && (source.S2 == this.S2));
    }

    public override int GetHashCode() => 
        ((0x17 * this.S1.GetHashCode()) + this.S2.GetHashCode());
}

示例匿名类型类

由于GetHashCode()不再存在,因此编译器生成的类具有相同的问题:

[Serializable, CompilerGenerated]
private sealed class <>c
{
    public static Func<ObfuscationAsserter.D, int> E;
    public static Func<ObfuscationAsserter.D, int> F;
    public static Func<ObfuscationAsserter.D, ObfuscationAsserter.D> I;
    public static readonly ObfuscationAsserter.<>c J = new ObfuscationAsserter.<>c();
    public static Func<ObfuscationAsserter.D, J<string, string>> V;
    public static Func<ObfuscationAsserter.D, int> W;
    [TupleElementNames(new string[] { "S1", "S2" })]
    public static Func<ObfuscationAsserter.D, (string S1, string S2)> X;
    public static Func<ObfuscationAsserter.D, int> Y;
    public static Func<ObfuscationAsserter.D, string> Z;

    internal int B(ObfuscationAsserter.D d1)
    {
        (string, string) tuple = (d1.J, d1.V);
        return tuple.GetHashCode();
    }

    [return: TupleElementNames(new string[] { "S1", "S2" })]
    internal (string S1, string S2) L(ObfuscationAsserter.D d1) => 
        (d1.J, d1.V);

    internal int N(ObfuscationAsserter.D d1) => 
        d1.GetHashCode();

    internal string P(ObfuscationAsserter.D d1) => 
        (d1.J + d1.V);

    internal J<string, string> R(ObfuscationAsserter.D d1) => 
        new J<string, string>(d1.J, d1.V);

    internal int S(ObfuscationAsserter.D d1) => 
        (d1.J + d1.V).GetHashCode();

    internal int T(ObfuscationAsserter.D d1) => 
        new J<string, string>(d1.J, d1.V).GetHashCode();

    internal ObfuscationAsserter.D U(ObfuscationAsserter.D d1) => 
        d1;
}

0 个答案:

没有答案