Mono.Cecil,你所听过的最强大的工具
使用 Mono.Cecil,IL 操控库的实验
引言
在我目前的公司,需要能够向程序集“签名”一些额外的信息。 作为一个选项,我可以一直创建一个 CustomAttribute
用于程序集,并且在每次需要的时候重新编译,或者实际上在事后注入一些数据。
我偶然发现了一个几乎没有文档的名为 Cecil
(Mono.Cecil)的项目。Cecil
是一个 IL 修改库,非常强大。 使用 Cecil
,可以打开任何现有的 .NET 程序集,修改 IL,绑定事件,删除功能,添加新功能等,然后继续将新的程序集写入磁盘或 byte[]
。
基本上,当归结到这一点时,为了找到一个简单问题的解决方案,我发现了一个比我听过的任何工具都更强大的工具。
我打算从一些非常基本的例子开始,并最终深入到一些更复杂的例子,所以请继续关注!
自定义 "签名" 示例
对于这个例子,我将使用一些 CustomAttributes
在编译后为简单的控制台应用程序签名。
我对编译后任务并不太熟悉,但基本上你首先需要编译 dummyapp
,并将生成的 EXE 复制到 AppSigner
项目的 bin 路径(Program.cs)。
using System;
using System.Collections.Generic;
using System.Text;
using Mono.Cecil;
namespace AppSigner
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Signing DummyApp.exe");
// create an Assembly definition from target assembly...
// in this case I'll pass in full path to DummyApp.exe
AssemblyDefinition sourceAssembly
= AssemblyFactory.GetAssembly("DummyApp.exe");
//Next, we'll need to "Import" a reference of the new
//CustomAttribute (which happens to exist in my signing
//app for the moment.)
//typeof(string) denotes what the constructor parameter
//type is. If your attribute was of Guid you could use
//typeof(Guid) etc.
CustomAttribute ca =
new CustomAttribute(sourceAssembly.MainModule.Import(
typeof(AssemblyExtendedInfo).GetConstructor(
new Type[] { typeof(string) })));
//Assign the parameters value of specified type
ca.ConstructorParameters.Add("This is some extended information!");
//go ahead and now add this customattribute instance
// back to the target assembly's CustomAttributes collection.
sourceAssembly.CustomAttributes.Add(ca);
//finally go ahead and persist back to disk. In this case
//for clarity, I went ahead and just wrote a new file out.
AssemblyFactory.SaveAssembly(sourceAssembly, "newassembly.exe");
Console.WriteLine("Signing Complete!");
Console.WriteLine("Verifying...");
//now just to verify, we'll open the new assembly back up,
//and loop through custom attributes...
AssemblyDefinition targetAssembly
= AssemblyFactory.GetAssembly("newassembly.exe");
foreach (CustomAttribute eca in targetAssembly.CustomAttributes)
{
if (eca.Constructor.DeclaringType.Name ==
"AssemblyExtendedInfo")
{
Console.WriteLine(
"newassembly.exe's ApplicationExtendedInformation attribute:");
Console.WriteLine(eca.ConstructorParameters[0].ToString());
}
}
Console.ReadLine();
}
}
}
您还需要定义 AssemblyExtendedInfo
类,其中将包含您的程序集的额外信息(AssemblyExtendedInfo.cs)。
using System;
using System.Collections.Generic;
using System.Text;
namespace AppSigner
{
//mark this attribute as applicable to Assemblies
[AttributeUsage(AttributeTargets.Assembly)]
public sealed class AssemblyExtendedInfo : Attribute
{
private string extendedInfo = string.Empty;
public string ExtenededInfo
{
get
{
return extendedInfo;
}
}
//this will be the constructor we'll be referring to later
public AssemblyExtendedInfo(string extendedInfo)
{
this.extendedInfo = extendedInfo;
}
public override string ToString()
{
return extendedInfo;
}
}
}
关注点
现在你们中的许多人会想知道这个练习的意义何在,考虑到新的 Attribute
在 Windows 资源管理器等程序集信息中是不可见的。 好吧,您可以轻松使用简单的反射来确定此值,或者继续使用 Mono.Cecil
库重新打开。 我希望这能让你对这个库有多强大,以及你可以在不反编译或反射出一堆源代码的情况下对现有程序集进行什么样的修改有一些了解。
未来会发生什么?
我打算至少再写两篇文章,解释 Mono.Cecil
的功能以及进一步的可能用途等。在即将发布的文章中,我计划深入研究重写功能,以及将跟踪信息注入到现有程序集中。 我对 Mono.Cecil
还不太熟悉,所以请多多包涵,我会尽力回答我能回答的任何问题!
文章历史
- 2007年2月19日 - 初次发表