Mono.Cecil简介与示例
转载注明出处:点击打开链接
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简介与示例相关推荐
- Mono.Cecil使用示例之使指定程序集成为UnityEditor.dll的友元程序集
Mono.Cecil使用示例之使指定程序集成为UnityEditor.dll的友元程序集 Mono.Cecil是一个开源的库,使用Mono.Cecil可以非常方便的在代码中修改C#程序集.在Unity ...
- 使用Mono.Cecil辅助ASP.NET MVC使用dynamic类型Model
使用Mono.Cecil辅助ASP.NET MVC使用dynamic类型Model 2011-09-06 00:21 by 老赵, 8645 visits 这也是之前在珠三角技术沙龙上的示例之一,解决 ...
- python包NiBabel对医学影像文件格式进行读写:python包NiBabel简介集示例
python包NiBabel对医学影像文件格式进行读写:python包NiBabel简介集示例 目录 python包NiBabel对医学影像文件格式进行读写:python包NiBabel简介集示例
- 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习)
原文:利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习) Mono.Cecil是一个强大的MSIL的注入工具,利用它可以实现动态创建程序集,也可以实现拦截器横向切入动态方法,甚至还 ...
- faiss简介及示例
faiss简介及示例 原文:https://blog.csdn.net/kanbuqinghuanyizhang/article/details/80774609 版权声明:本文为博主原创文章,未经博 ...
- 巧用Mono.Cecil反射加载类型和方法信息
最近在做服务的细粒度治理,统一管理所有服务的方法.参数.返回值信息.方便后续的各个模块之间的对接和协作. 目前系统中所有的服务,管理到接口契约粒度,即服务接口声明和服务接口实现.要做服务的细粒度治理: ...
- 编译时MSIL注入--实践Mono Cecil(1)
紧接上两篇浅谈.NET编译时注入(C#-->IL)和浅谈VS编译自定义编译任务-MSBuild Task(csproject),在第一篇中我们简单研究了c#语法糖和PostSharp的MSIl注 ...
- RAID简介与示例演示
RAID简介与示例演示 一.RAID磁盘阵列 1.RAID 0(条带化存储) 2.RAID 1(镜像存储) 3.RAID 5 4.RAID 6 5.RAID 1 + 0(先做镜像,再做条带) 6.RA ...
- 运用Mono.Cecil 反射读取.NET程序集元数据
CLR自带的反射机智和API可以很轻松的读取.NET程序集信息,但是不能对程序集进行修改.CLR提供的是只读的API,但是开源项目Mono.Cecil不仅仅可以读取.NET程序集的元数据,还可以进行修 ...
- tomcat基础简介与示例
tomcat基础简介与示例 Tomcat服务器是一个免费的开放源代码的Web应用服务器.Tomcat是Apache软件基金会 的Jakarta项目中的一个核心项目,由Apache.Sun和其他一些公司 ...
最新文章
- 大赛归来的你们,依然青春少年
- 平衡二叉树平衡因子怎么计算_平衡二叉树(AVL Tree)旋转机制分析
- Springboot-application.properties
- nlp mrc的损失是什么_田渊栋从数学上证明ICLR最佳论文“彩票假设”,强化学习和NLP也适用...
- 项目中SQL语句的一些应用总结
- 有了这个开源项目,再也不会忘记 Linux 命令啦~
- Dell笔记本降低Bios版本简单而可靠的方法(1.15亦成功降级)
- python提取url的顶级域名及域名后缀
- 关于梯度下降与Momentum通俗易懂的解释
- 执法智能眼镜 android,警用AR智能眼镜解决方案
- php开发之Composer包
- Layui页面元素之导航
- Tab页面知识整理及其方法分析
- 电脑屏幕上计算机闪烁有框,电脑显示器有点闪烁该怎么解决
- 学术-几何:黑森错觉
- 7-14 输出大写英文字母 (15分) 瞎搞
- 计算机技术预测蛋白质结构,线上分享 | 同源建模预测蛋白质结构,中科院计算所ProALIGN研究解读...
- font awesome矢量字体使用
- c语言4位数求各位数的立方和,功能:使用循环结构求一个四位数的各位数字的立方和...
- PDF box 结合POI 将pdf转为PPT