Obfuscate and optimize method IL code

Performs advanced targeted transformations on method instructions which obfuscate control flow and make compiler constructs hard to infer and decompile. Rummage will never insert unnecessary branches (which can slow down code), but instead reorders code blocks and replaces instruction sequences with equivalents. In many cases Rummage eliminates redundancy and local variables.

BeforeAfter
for (int i = 0; i < count; i++)
    Console.WriteLine(i);
object arg_01_0 = 0;
while (true)
{
    object expr_01 = arg_01_0;
    if (expr_01 >= count)
        break;
    Console.WriteLine(expr_01);
    arg_01_0 = expr_01 + 1;
}

Normally the decompiler would have been able to deduce the for loop structure, but after Rummage it fails to do so, and also chooses the wrong type for the locals (so its output wouldn't compile). Moreover, the obfuscated IL has no locals at all (the i got eliminated completely):

Before (IL)After (IL)
.locals init (
         [0] int32 i
)
         ldc.i4.0
         stloc.0
         br.s IL_000e
IL_0004: ldloc.0
         call WriteLine(int32)
         ldloc.0
         ldc.i4.1
         add
         stloc.0
IL_000e: ldloc.0
         ldarg.0
         blt.s IL_0004
         ret
         ldc.i4.0
IL_0001: dup
         ldarg.0
         blt.s IL_0007
         pop
         ret
IL_0007: dup
         call WriteLine(int32)
         ldc.i4.1
         add
         br.s IL_0001

Observe that while the decompiled code looks longer than the original, the actual underlying IL code was significantly shortened by Rummage.

Rummage makes irreversible changes that make the code very hard — even for a human — to express in a source language such as C# or Visual Basic.NET.

Decompilers, out of necessity, assume that the IL is the result of a compiler; however, the modified IL is structured in a way that no compiler would output.

Rummage uses a mathematical proof technique to guarantee that the changes are safe and make no difference to the program semantics.