首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在C#中执行.NET IL代码

在C#中执行.NET IL代码
EN

Stack Overflow用户
提问于 2014-10-11 15:03:50
回答 1查看 3.6K关注 0票数 18

有没有办法像C/C++中的外壳代码一样,在C#中执行一组IL代码?

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

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

代码语言:javascript
复制
 static int MyMethod(string A, int B)
 {
    B += 10;
    if (A.Equals("A"))
        B = 0;
    return B;
 }

现在我把它转换成IL代码:

代码语言:javascript
复制
 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
  }

最后这是一个字节数组:

代码语言:javascript
复制
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
};
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-10-11 15:14:47

您将需要使用System.Reflection.Emit名称空间中的基础结构。具体地说,您应该查看MethodBuilder.CreateMethodBodydocs,它采用一个表示MSIL指令的字节数组。这里有一个完整的示例,但下面是它的用法的简短片段。在这里,我也将创建一个动态方法的委托。

我要指出的是,这只以一种非常有限的方式得到支持,这在文档中被称为:

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

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

代码语言:javascript
复制
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选项的用法。这会将动态程序集保存到磁盘的临时位置。使用RunAndCollect可能更可取,它将只在内存中生成程序集,并允许稍后在对它的所有引用都已死时收集它。然而,对于所谓的可收集的程序集,详细的here,有一些警告。

票数 22
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26312026

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档