Mono Cecil 十分强大, 强大到可以静态注入程序集 (注入后生成新的程序集) 和动态注入程序集(注入后不改变目标程序集, 只在运行时改变程序集行为)
先看 Mono.Cecil 是如何读取程序集的
点这里 http://www.cnblogs.com/JamesLi2015/p/3172208.html
一个基本使用示例(此示例版本为 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 还可以用来破解商业组件(我勒个去的, 连程序都可以改, 去掉程序集签名, 改成自己生成的签名, 还有什么办不到的?)
下面的例子是去掉一个组件中的水印, 当然作者只不过是举个例子, 组件是自己写的,"破解" 起来比较容易, 真正的商业组件破解起来, 得花好多时间研究的
点这里
来源: http://www.bubuko.com/infodetail-2931894.html