使用Mono Cecil对MSIL进行注入

Posted swdhywhd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Mono Cecil对MSIL进行注入相关的知识,希望对你有一定的参考价值。

Mono Cecil十分强大,强大到可以静态注入程序集(注入后生成新的程序集)和动态注入程序集(注入后不改变目标程序集,只在运行时改变程序集行为)

先看Mono.Cecil是如何读取程序集的

点这里

 

一个基本使用示例(此示例版本为0.6,后期版本AssemblyFactory已被去掉,改用AssemblyDefinition.ReadAssembly)

点这里

 

下面是网上的一个例子,我觉得比较典型,拿来收藏了

 

     有一个名为 MyLibrary.dll 的程序集,内有 Class1 类型,我们需要动态创建其对象,并调用 Test 方法。注入的要求是在执行 Test 内部代码前先执行一个外部程序集的方法 InjectMethod。

 

class Class1
{
   void Test()
  {
    Console.WriteLine("Hello, World!");
  }
}

注入代码

 

 

public class Program
{
  public static void InjectMethod()
  {
    Console.WriteLine("Haha...");
  }
  static void Main(string[] args)
  {
    AssemblyDefinition asm = AssemblyFactory.GetAssembly("MyLibrary.dll");
    foreach (TypeDefinition type in asm.MainModule.Types)
    {
      if (type.Name == "Class1")
      {
        foreach (MethodDefinition method in type.Methods)
        {
          if (method.Name == "Test")
          {
            Instruction ins = method.Body.Instructions[0];
            CilWorker worker = method.Body.CilWorker;
            MethodInfo m = typeof(Program).GetMethod("InjectMethod", BindingFlags.Static | BindingFlags.Public);
            MethodReference refernce = asm.MainModule.Import(m);
            Instruction insCall = worker.Create(OpCodes.Call, refernce);
            worker.InsertBefore(ins, insCall);
            Instruction insNop = worker.Create(OpCodes.Nop);
            worker.InsertAfter(insCall, insNop);
          }
        }
      }
    }
    Assembly testAssembly = AssemblyFactory.CreateReflectionAssembly(asm); 
    Type class1Type = testAssembly.GetType("MyLibrary.Class1");
    Object o = Activator.CreateInstance(class1Type);
    class1Type.InvokeMember("Test", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, o, null);
  }
}

输出:
Haha...
Hello, World!
  动态注入和静态注入不同,它不会修改目标程序集文件,因此不会有强类型签名等问题,也不易发生相关 "版权" 问题。可用来跳过某段验证代码,或者替换某些内部执行代码,用途有点像 "外挂"。使用动态注入实现 AOP 可能比较有意思,我们可以遍历添加了 "[AOP(aopMethodName=)]" 方法特性的所有类型,然后动态注入 AOP 拦截代码。

 

 

以上这种注入方式十分强大,居然可以注入到某一行代码之前,改变它的行为,一般的AOP实现恐怕也没有这么强大的。

 

另一个例子是直接把泛型约束给修改掉,例子中由于编译器不支持泛型约束中出现Enum类型,但在IL底层支持这么干,作者就用Mono.Ceil修改了程序集,让泛型约束直接支持Enum类型,详细看这里

点这里

 

Mono.Cecil 还可以用来破解商业组件(我勒个去的,连程序都可以改,去掉程序集签名,改成自己生成的签名,还有什么办不到的?)

下面的例子是去掉一个组件中的水印,当然作者只不过是举个例子,组件是自己写的,“破解”起来比较容易,真正的商业组件破解起来,得花好多时间研究的

点这里

 

 

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow








以上是关于使用Mono Cecil对MSIL进行注入的主要内容,如果未能解决你的问题,请参考以下文章

使用 Mono.Cecil 在 C# 程序集中注入方法

使用 Mono.Cecil 辅助 Unity3D 手游进行性能测试(续)

如何使用 Mono.Cecil 获取 IL 指令的源代码/行号

使用 Mono.Cecil 辅助 Unity3D 手游进行性能测试

使用MOno Cecil 的相关开源项目

csharp 使用Mono.Cecil和GLEE绘制函数依赖关系的一些代码