在C#中执行.NET IL代码

时间:2014-10-11 07:03:50

标签: c# .net il

有没有办法在C#中执行IL代码数组,如C / C ++中的shell代码?

我想创建一个方法,将其转换为IL代码,对其进行模糊处理并存储在一个字节数组中,最后要执行它来解密数组内容并执行IL代码。

例如,这是我的C#代码:

 static int MyMethod(string A, int B)
 {
    B += 10;
    if (A.Equals("A"))
        B = 0;
    return B;
 }

现在我将其转换为IL代码:

 private static int MyMethod(string A, int B)
  {
    locals: int local_0,
            bool local_1

    /* 0000025C 00             */ nop
    /* 0000025D 03             */ ldarg_1 // int B
    /* 0000025E 1F 0A          */ ldc_i4_s 10
    /* 00000260 58             */ add
    /* 00000261 10 01          */ starg_s arg_1 // int B
    /* 00000263 02             */ ldarg_0 // string A
    /* 00000264 72 01 00 00 70 */ ldstr "A"
    /* 00000269 6F 11 00 00 0A */ callvirt System.String::Equals(string) // returns bool
    /* 0000026E 16             */ ldc_i4_0
    /* 0000026F FE 01          */ ceq
    /* 00000271 0B             */ stloc_1 // bool local_1
    /* 00000272 07             */ ldloc_1 // bool local_1
    /* 00000273 2D 03          */ brtrue_s loc_28
    /* 00000275 16             */ ldc_i4_0
    /* 00000276 10 01          */ starg_s arg_1 // int B
loc_28:
    /* 00000278 03             */ ldarg_1 // int B
    /* 00000279 0A             */ stloc_0 // int local_0
    /* 0000027A 2B 00          */ br_s loc_32
loc_32:
    /* 0000027C 06             */ ldloc_0 // int local_0
    /* 0000027D 2A             */ ret
  }

最后这是一个字节数组:

private byte[] ilcode = 
{
   0x00, 0x03, 0x1F, 0x0A, 0x58, 0x10, 0x01, 0x02, 0x72, 0x01, 0x00, 0x00, 0x70, 0x6F, 0x11, 0x00, 0x0, 0x0A, 0x16,
   0xFE, 0x01, 0x0B, 0x07, 0x2D, 0x03, 0x16, 0x10, 0x01, 0x03, 0x0A, 0x2B, 0x00, 0x06, 0x2A
};

1 个答案:

答案 0 :(得分:22)

您需要在System.Reflection.Emit命名空间中使用基础结构。具体来说,您应该查看MethodBuilder.CreateMethodBody class Program { static void Main(string[] args) { // opcodes for pushing two arguments to the stack, adding, and returning the result. byte[] ilcodes = { 0x02, 0x03, 0x58, 0x2A }; var method = CreateFromILBytes(ilcodes); Console.WriteLine(method(2, 3)); } private static Func<int, int, int> CreateFromILBytes(byte[] bytes) { var asmName = new AssemblyName("DynamicAssembly"); var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave); var module = asmBuilder.DefineDynamicModule("DynamicModule"); var typeBuilder = module.DefineType("DynamicType"); var method = typeBuilder.DefineMethod("DynamicMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new[] { typeof(int), typeof(int) }); method.CreateMethodBody(bytes, bytes.Length); var type = typeBuilder.CreateType(); return (Func<int, int, int>)type.GetMethod("DynamicMethod").CreateDelegate(typeof(Func<int, int, int>)); } } ,其中RunAndSave采用表示MSIL指令的字节数组。这里有一个完整的例子,但下面是它的使用的简短片段。在这里,我还将创建动态方法的委托。

我会注意到这只是以非常有限的方式支持,在文档中提到:

  

目前尚未完全支持此功能。用户无法提供令牌修复和异常处理程序的位置。

问题是IL中用于引用类型,方法,字符串文字等的元数据标记在模块级别得到解决。因此,IL不是完全可移植的,因为您不能从一个模块中的方法中获取任意的原始IL,只是将其放入另一个模块中的另一个方法中。您需要在新模块中使用正确的元数据标记。但是,如果您知道您的IL不包含元数据令牌,则可以执行此操作,但这严重限制了您可以执行的操作。 (HT:svick,Simon Svensson)

RunAndCollect

请注意使用{{1}}选项。这会将动态程序集保存到临时位置的磁盘中。可能更希望使用{{1}},它将仅在内存中生成程序集,并允许稍后在对它的所有引用都已死时收集它。但是,所谓的收藏集会有一些警告,详细docs