PEVerify警告重复方法错误吗?

时间:2016-02-02 15:21:58

标签: c# .net il peverify

我正在研究组件的混淆,在混淆之后,PEVerify发出以下错误:

[MD]: Error: Method has a duplicate, token=0x060035d8. [token:0x060035D5]
[MD]: Error: Method has a duplicate, token=0x060035d5. [token:0x060035D8]

这是带头的第一个方法声明:

// Token: 0x060035D5 RID: 13781 RVA: 0x000D7828 File Offset: 0x000D5A28
.method private final hidebysig newslot virtual 
    instance void b () cil managed
{
    .override method instance void [mscorlib]System.IDisposable::Dispose()
    // Header Size: 12 bytes
    // Code Size: 52 (0x34) bytes
    // LocalVarSig Token: 0x11000050 RID: 80
    .maxstack 2
    .locals init (
        [0] int32
    )

这是第二个:

// Token: 0x060035D8 RID: 13784 RVA: 0x000248BC File Offset: 0x00022ABC
.method private hidebysig 
    instance void b () cil managed
{
    // Header Size: 1 byte
    // Code Size: 31 (0x1F) bytes
    .maxstack 8

对我来说似乎是一个明确的IDisposable接口实现。这两种方法都被调用,因此并不是所有对一个方法的调用都被替换为另一个方法。他们只是共享相同的名称

如果在C#中编写了类似的代码 - 编译器将发出方法System.IDisposable.Dispose()和Dispose(),从而消除相同的名称并使PEVerify保持静默。

要确保相同的名称在其中一个显式覆盖接口方法时生成有效的IL,而其他名称不是我编写的示例应用程序:

namespace ClassLibrary1 {
    public interface IX { void M(); }
    public class Class1 : IX {
        void IX.M() { Console.WriteLine("IX.M()"); }
        public void M() { Console.WriteLine("M()"); }
    }
    public class Class2 {
        public static void Main(string[] args) {
            var x = new Class1();
            x.M();
            ((IX)x).M();
        }
    }
}

IL看起来像这样:

// Token: 0x06000002 RID: 2 RVA: 0x00002050 File Offset: 0x00000250
.method private final hidebysig newslot virtual 
    instance void ClassLibrary1.IX.M () cil managed 
{
    .override method instance void ClassLibrary1.IX::M()
    // Header Size: 1 byte
    // Code Size: 13 (0xD) bytes
    .maxstack 8

    /* 0x00000251 00           */ IL_0000: nop
    /* 0x00000252 7201000070   */ IL_0001: ldstr     "IX.M()"
    /* 0x00000257 280F00000A   */ IL_0006: call      void [mscorlib]System.Console::WriteLine(string)
    /* 0x0000025C 00           */ IL_000B: nop
    /* 0x0000025D 2A           */ IL_000C: ret
} // end of method Class1::ClassLibrary1.IX.M

// Token: 0x06000003 RID: 3 RVA: 0x0000205E File Offset: 0x0000025E
.method public hidebysig 
    instance void M () cil managed 
{
    // Header Size: 1 byte
    // Code Size: 13 (0xD) bytes
    .maxstack 8

    /* 0x0000025F 00           */ IL_0000: nop
    /* 0x00000260 720F000070   */ IL_0001: ldstr     "M()"
    /* 0x00000265 280F00000A   */ IL_0006: call      void [mscorlib]System.Console::WriteLine(string)
    /* 0x0000026A 00           */ IL_000B: nop
    /* 0x0000026B 2A           */ IL_000C: ret
} // end of method Class1::M

请注意不同的方法名称。

然后我在ClassLibrary1.IX.M中使用了生成的exe并编辑了M只是Class1(我已经使用dnSpy来执行此操作)。 PEVerify确实开始发布有关重复方法的相同问题,但是exe仍然可以按照预期正常打印M() IX.M()

问题是PEVerify在这里是否过于谨慎,或者是否存在我看不到的重合名称的问题?

1 个答案:

答案 0 :(得分:4)

两种方法共享相同的方法签名,这是不允许的。

  

对于CLR,方法签名由方法名称,泛型arity,形式参数arity,形式参数类型和种类以及返回类型组成。

Definition of a method signature

Serge Lidin在 .Net IL Assembler 方法表有效性规则下的第10章中说明:

  

除非可访问性标志是privatescope,否则不应存在属于同一TypeDef且具有相同名称和签名的重复记录。

当然,您可以在ECMA-335规范中找到此规则,分区II.22.1:

  

独特的行:   任何表都不应包含重复的行,其中定义了“重复”   就其而言   键    列或列的组合。