3

アセンブリの難読化に取り組んでおり、難読化後に 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
    )

そして、ここに2番目のものがあります:

// 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 がサイレントになります。

そのうちの 1 つがインターフェイス メソッドの明示的なオーバーライドであり、もう 1 つがそうでない場合に、同じ名前が有効な 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

異なるメソッド名に注意してください。

次に、結果のexeを取得ClassLibrary1.IX.Mし、ちょうど入るように編集しMましたClass1dnSpyを使用してそれを行いました)。PEVerify は実際にメソッドの重複に関する同じ問題を発行し始めましたが、exe はまだ正常に機能してM() IX.M()おり、期待どおりに印刷されています。

問題は、PEVerify がここで慎重すぎるのか、それとも名前が一致しないことに本当に問題があるのか​​ということです。

4

1 に答える 1

4

どちらのメソッドも同じメソッド シグネチャを共有しており、それは単に許可されていません。

CLR の場合、メソッド シグネチャは、メソッド名、ジェネリック アリティ、仮パラメーター アリティ、仮パラメーターの型と種類、および戻り値の型で構成されます。

メソッド シグネチャの定義

Serge Lidin は、.Net IL Assemblerの第 10 章のMethod Table Validity Rulesで次のように述べています。

アクセシビリティ フラグが privatescope でない限り、同じ TypeDef に属し、同じ名前と署名を持つ重複レコードは存在してはなりません。

もちろん、このルールは ECMA-335 仕様のパーティション II.22.1 にあります。

一意の行: テーブルには重複する行が含まれてはならず、「重複」はそのキー列または列の組み合わせに関して定義されます。

于 2016-02-02T15:33:49.317 に答える