项目地址:Mono.Cecil
项目描述:In simple English, with Cecil, you can load existing managed assemblies, browse all the contained types, modify them on the fly and save back to the disk the modified assembly.
类似项目:Microsoft CCI
Common Compiler Infrastructure: Metadata API
Common Compiler Infrastructure: Code Model and AST API
Common Compiler Infrastructure: Sample applications
Common Compiler Infrastructure - Contrib
对比评价:来自StackOverflow
Mono.Cecil has better, more understandable and easy in use object model. However, I had an ugly bug when used it in my program (reference to the wrong method was saved in the assembly; I think there was some bug with metadata tokens handling)
Microsoft.CCI has an ugly, utterly over-designed object model in the same time lacking many simple features; however, it‘s more mature than Mono.Cecil. Finally, I abandoned Mono.Cecil and used Microsoft.CCI for my program.
基本示例
Cecil是对已编译生成IL的程序集进行操作,所以先写一个简单的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");
            else
                Console.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);
            }
        }
    }
}
这个程序集的运行结果如下:

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结果如下:


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来修改这个程序集,其运行结果如下图:



//得到指令brfalse.s Instruction jmp = sayHello.Body.Instructions[1]; .... //把跳转的目标地址改成IL_0017 ldstr指令位置 jmp.Operand = ldstr;
原文:http://www.cnblogs.com/lonelyxmas/p/5568866.html