0

I am using dotPeek and ILSpy to explore some compiled release C# code. Quite a lot of the methods are full of structures like this:

// Within method Class.foo()...
if (condition)
{
    label_2:
        switch (7)
        {
        case 0:
            goto label_2;
        default:
            if (false)
            {
                // ISSUE: method reference
                RuntimeMethodHandle runtimeMethodHandle = __methodref (Class.foo);
            }
            // Do things
            switch (3)
            {
            case 0:
                goto label_8;
            }
            break;
        }
    }
}

That is from dotPeek. ILSpy translates this as:

if (condition)
{
    while (true)
    {
        switch (7)
        {
        case 0:
            continue;
        }
        break;
    }
    if (1 == 0)
    {
        /*OpCode not supported: LdMemberToken*/;
    }
    // Do things
    while (true)
    {
        switch (3)
        {
        case 0:
            continue;
        }
        break;
    }
}

So just turning the gotos to a while loop and adding a comment about an unsupported OpCode. The actual IL code of this first switch is

// start of loop, entry point: IL_002f

// [736 9 - 736 19]
IL_002f: ldc.i4.7
IL_0030: switch       (IL_002f)
// end of loop

// [741 13 - 741 23]
IL_0039: ldc.i4.1
IL_003a: brtrue.s     IL_0042

// [744 15 - 744 98]
IL_003c: ldtoken      method void Class::foo(/* args */)
IL_0041: pop
IL_0042: ...

I believe I have read that while __methodref is legal in IL code, it is not legal in C#, so I'm assuming this is something added by the compiler or some other post-compilation tool, but I'm wondering why. The code is full of these, references to the method they are in that are unconditionally skipped over using some odd switch structure. I thought the while loop might have been part of some thread-safety check, but that doesn't make sense looking at the IL code. Could the __methodrefs be used for profiling, tracing, or debugging? If so, I'd expect at least one decompiler to recognize them. Are they intentional obfuscation. Can anyone tell me where these come from and what they are for?

Florian
  • 1,019
  • 6
  • 22
Joel Croteau
  • 1,682
  • 12
  • 17
  • 2
    I think it's intentional obfuscation, or at least, to prevent reverse-engineering in general. – Sweeper May 12 '23 at 01:47
  • 2
    You will see field / property handles like this in `Expression<>` tree's, even in debug builds (eg https://sharplab.io/#v2:D4AQTAjAsAUCAMACEEB0AZAlgOwI6oFEAPABwCcBTAZyswHtsqBuWEAZmTEQGFEBvWIiHIOOAC6IAGv0QBzCmKaIqCpQF9Bw9onGIAmixjCRyACyIAsgAoAlP03GhxctVoMAPCACs78QD4/RCJEAF5EW1DA6QBqfUNjDRg1IA===). Release builds will move code around and change the type of jump instructions. Which makes it much harder to reverse engineer back into readable code. An obfuscator might create even more mess deliberately, `if (1 == 0)` / `switch (7)` looks like dead code, which might be an obfuscation. – Jeremy Lakeman May 12 '23 at 01:49

0 Answers0