转载注明出处:点击打开链接

CLR自带的反射机智和API可以很轻松的读取.NET程序集信息,但是不能对程序集进行修改。CLR提供的是只读的API,但是开源项目Mono.Cecil不仅仅可以读取.NET程序集的元数据,还可以进行修改。

先写一个简单的Console exe程序,这里项目名称使用Cecil.Program:

using System;
using System.Reflection;
namespace Cecil.Program
{class Program{static void Main(string[] args){TestType tt = new TestType();tt.SayHello();tt.AboutMe();Console.ReadKey();}}public class TestType{[Obsolete]public void SayHello(){Console.WriteLine("\tHello Cecil !");}public void AboutMe(){Type type = typeof(TestType);MethodInfo method = type.GetMethod("SayHello");if (method.IsVirtual)Console.WriteLine("\tI'm a virtual method");elseConsole.WriteLine("\tI'm a non-virtual method");object[] attributes = method.GetCustomAttributes(false);if (attributes != null && attributes.Length > 0){Console.WriteLine("\tI have the following attributes:");foreach (object attr in attributes)Console.WriteLine("\t\t" + attr.GetType().Name);}}}
}

这个程序集的运行结果如下:
    

方法SayHello的IL代码如下:
    

接下来使用另外一个Console exe程序来修改Cecil.Program.exe,项目名称使用Cecil:

using Mono.Cecil;
using Mono.Cecil.Cil;
AssemblyDefinition assembly = AssemblyFactory.GetAssembly("Cecil.Program.exe");
TypeDefinition type = assembly.MainModule.Types["Cecil.Program.TestType"];
MethodDefinition sayHello = null;
foreach (MethodDefinition md in type.Methods)if (md.Name == "SayHello") sayHello = md;
//Console.WriteLine(string value)方法
MethodInfo writeLine = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
//Console.WriteLine方法导入MainModule,并返回在AssemblyDefinition中的引用方式
MethodReference writeLineRef = assembly.MainModule.Import(writeLine);
//在SayHello方法开始位置插入一条trace语句
//  Console.WriteLine(">>Intercepting ");
//如果插入的语句需要使用函数入参,则必须插入在OpCodes.Ldarg等指令之后
CilWorker worker = sayHello.Body.CilWorker;
Instruction ldstr = worker.Create(OpCodes.Ldstr, ">>Intercepting " + sayHello.Name);
Instruction call = worker.Create(OpCodes.Call, writeLineRef);
Instruction first = sayHello.Body.Instructions[0];
worker.InsertBefore(first, call);
worker.InsertBefore(call, ldstr);
//在SayHello方法结束位置插入一条trace语句
//  Console.WriteLine(">>Intercepted ");
//语句必须插入在OpCodes.Ret指令的前面
int offset = sayHello.Body.Instructions.Count - 1;
Instruction last = sayHello.Body.Instructions[offset--];
while (last.OpCode == OpCodes.Nop || last.OpCode == OpCodes.Ret)last = sayHello.Body.Instructions[offset--];
ldstr = worker.Create(OpCodes.Ldstr, ">>Intercepted " + sayHello.Name);
worker.InsertAfter(last, ldstr);
worker.InsertAfter(ldstr, call);
//把SayHello方法改为虚方法
sayHello.IsVirtual = true;
//给SayHello方法添加一个SerializableAttribute
CustomAttribute attribute = new CustomAttribute(assembly.MainModule.Import(typeof(SerializableAttribute).GetConstructor(Type.EmptyTypes)
));
sayHello.CustomAttributes.Add(attribute);
AssemblyFactory.SaveAssembly(assembly, "Cecil.Program.modified.exe");
Console.WriteLine("Assembly modified successfully!");
Console.ReadKey();

编译生成Cecil.exe,然后把Cecil.Program.exe拷贝到这个目录下,运行Cecil.exe,便会在当前目录生成Cecil.Program.modified.exe,运行Cecil.Program.modified.exe结果如下:
    
修改后的方法SayHello的IL代码如下:
    

从上面的基本使用方法可以看出,Cecil的确是易于使用,对象模型结构非常实用,这里是官方网站的一个主要对象结构图:
    

IL指令的复杂性
在assembly、type、method级别上对程序集做修改是非常简单的,但是如果要修改方法体的IL代码,则可能会遇到一些较麻烦的事情,需要细致的处理
例如上面的SayHello方法如果是这样:

public void SayHello(bool print)
{if (print)Console.WriteLine("\tHello Cecil !");
}

测试代码这样来调用:

TestType2 tt2 = new TestType2();
tt2.SayHello(true);
tt2.SayHello(false);
Console.ReadKey();

其运行结果只会输出一条Hello Cecil !消息,仍然使用Cecil.exe来修改这个程序集,其运行结果如下图:
    
调用tt2.SayHello(false);时,应该也会有一个>>Intercepted SayHello消息,但是没有输出,对比一下IL代码就清楚了:
    
修改后的IL代码如下:
    
IL_000b那一句,为false时就直接跳转到IL_0021这个返回指令上了,不会输出Intercepted的消息

使用Mono.Cecil也可以修改这个跳转地址,例如:

//得到指令brfalse.s
Instruction jmp = sayHello.Body.Instructions[1];
....
//把跳转的目标地址改成IL_0017 ldstr指令位置
jmp.Operand = ldstr;

Mono.Cecil简介与示例相关推荐

  1. Mono.Cecil使用示例之使指定程序集成为UnityEditor.dll的友元程序集

    Mono.Cecil使用示例之使指定程序集成为UnityEditor.dll的友元程序集 Mono.Cecil是一个开源的库,使用Mono.Cecil可以非常方便的在代码中修改C#程序集.在Unity ...

  2. 使用Mono.Cecil辅助ASP.NET MVC使用dynamic类型Model

    使用Mono.Cecil辅助ASP.NET MVC使用dynamic类型Model 2011-09-06 00:21 by 老赵, 8645 visits 这也是之前在珠三角技术沙龙上的示例之一,解决 ...

  3. python包NiBabel对医学影像文件格式进行读写:python包NiBabel简介集示例

    python包NiBabel对医学影像文件格式进行读写:python包NiBabel简介集示例 目录 python包NiBabel对医学影像文件格式进行读写:python包NiBabel简介集示例

  4. 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习)

    原文:利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习) Mono.Cecil是一个强大的MSIL的注入工具,利用它可以实现动态创建程序集,也可以实现拦截器横向切入动态方法,甚至还 ...

  5. faiss简介及示例

    faiss简介及示例 原文:https://blog.csdn.net/kanbuqinghuanyizhang/article/details/80774609 版权声明:本文为博主原创文章,未经博 ...

  6. 巧用Mono.Cecil反射加载类型和方法信息

    最近在做服务的细粒度治理,统一管理所有服务的方法.参数.返回值信息.方便后续的各个模块之间的对接和协作. 目前系统中所有的服务,管理到接口契约粒度,即服务接口声明和服务接口实现.要做服务的细粒度治理: ...

  7. 编译时MSIL注入--实践Mono Cecil(1)

    紧接上两篇浅谈.NET编译时注入(C#-->IL)和浅谈VS编译自定义编译任务-MSBuild Task(csproject),在第一篇中我们简单研究了c#语法糖和PostSharp的MSIl注 ...

  8. RAID简介与示例演示

    RAID简介与示例演示 一.RAID磁盘阵列 1.RAID 0(条带化存储) 2.RAID 1(镜像存储) 3.RAID 5 4.RAID 6 5.RAID 1 + 0(先做镜像,再做条带) 6.RA ...

  9. 运用Mono.Cecil 反射读取.NET程序集元数据

    CLR自带的反射机智和API可以很轻松的读取.NET程序集信息,但是不能对程序集进行修改.CLR提供的是只读的API,但是开源项目Mono.Cecil不仅仅可以读取.NET程序集的元数据,还可以进行修 ...

  10. tomcat基础简介与示例

    tomcat基础简介与示例 Tomcat服务器是一个免费的开放源代码的Web应用服务器.Tomcat是Apache软件基金会 的Jakarta项目中的一个核心项目,由Apache.Sun和其他一些公司 ...

最新文章

  1. 大赛归来的你们,依然青春少年
  2. 平衡二叉树平衡因子怎么计算_平衡二叉树(AVL Tree)旋转机制分析
  3. Springboot-application.properties
  4. nlp mrc的损失是什么_田渊栋从数学上证明ICLR最佳论文“彩票假设”,强化学习和NLP也适用...
  5. 项目中SQL语句的一些应用总结
  6. 有了这个开源项目,再也不会忘记 Linux 命令啦~
  7. Dell笔记本降低Bios版本简单而可靠的方法(1.15亦成功降级)
  8. python提取url的顶级域名及域名后缀
  9. 关于梯度下降与Momentum通俗易懂的解释
  10. 执法智能眼镜 android,警用AR智能眼镜解决方案
  11. php开发之Composer包
  12. Layui页面元素之导航
  13. Tab页面知识整理及其方法分析
  14. 电脑屏幕上计算机闪烁有框,电脑显示器有点闪烁该怎么解决
  15. 学术-几何:黑森错觉
  16. 7-14 输出大写英文字母 (15分) 瞎搞
  17. 计算机技术预测蛋白质结构,线上分享 | 同源建模预测蛋白质结构,中科院计算所ProALIGN研究解读...
  18. font awesome矢量字体使用
  19. c语言4位数求各位数的立方和,功能:使用循环结构求一个四位数的各位数字的立方和...
  20. PDF box 结合POI 将pdf转为PPT

热门文章

  1. 微信小程序进度条组件自定义数字_微信小程序小技巧系列《十三》多级联动,自定义圆形进度条 ... ......
  2. ESX通过命令行重启虚拟机
  3. shell grep正则匹配汉字
  4. 嘻哈说:设计模式之工厂方法模式
  5. choose标签使用
  6. 明争暗斗 京东阿里智能家居大战一触即发
  7. 阿里高频面试题:如何快速判断元素是不是在集合里?
  8. 近两年最快上市房企,祥生控股究竟是在控制负债,还是饮鸩止渴?
  9. LeetCode——自除数
  10. 修行漫谈——说说中年危机