在C#中执行.NET IL代码 [英] Execute .NET IL code in C#

查看:62
本文介绍了在C#中执行.NET IL代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is there any way to execute an array of IL codes in C# like shell codes in C/C++?

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

I want to create a method, convert it to IL code, obfuscate it and store in an array of bytes and finally want to execute it decrypt the array content and execute IL code.

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

For example this is my C# code:

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

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

Now I convert it to IL code :

 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
  }

最后这是一个字节数组:

And finally this is a byte array :

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
};


推荐答案

您将需要使用系统中的基础结构。 Reflection.Emit命名空间。具体来说,您应该查看 docs 表示 MethodBuilder.CreateMethodBody ,它接受表示MSIL指令的字节数组。那里有一个完整的示例,但是下面是其用法的简短摘要。在这里,我还将创建一个动态方法的委托。

You will need to use the infrastructure in the System.Reflection.Emit namespace. Specifically, you should look at the docs for MethodBuilder.CreateMethodBody which takes an array of bytes representing MSIL instructions. There is a full example there, but below is short snippet of its use. Here, I will create a delegate to the dynamic method as well.

我会注意到,这仅在非常有限的方式下得到支持,这在文档中已提到。 :

I will note that this is only supported in a very limited way, which is called out in the docs:


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

This is currently not fully supported. The user cannot supply the location of token fix ups and exception handlers.

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

The issue is that metadata tokens used in IL to reference types, methods, string literals, etc are resolved at the module level. Thus IL is not completely portable in the sense that you can't take arbitrary, raw IL from a method in one module and just drop it into another method in another module. You need the proper metadata tokens in the new module. However, if you know that your IL contains no metadata tokens you can do it, but this severely limits what you can do with this. (HT: svick, Simon Svensson)

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 ,它仅在内存中生成程序集,并允许在以后对它的所有引用均失效时收集该程序集。但是,在所谓的可收集程序集方面有一些警告,请在此处详细了解>。

Note the use of the RunAndSave option. This will save the dynamic assembly to disk in a temporary location. It may be more desirable to use RunAndCollect which will generate the assembly in memory only and allow it to be collected later when all references to it are dead. However, there are some caveats to so called collectible assemblies, detailed here.

这篇关于在C#中执行.NET IL代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆