Cecil es una librería creada por Jean-Baptiste Evain que permite examinar y modificar los ensamblados .NET de manera sencilla, a su vez estos cambios pueden sobreescribir el original o ser almacenados en un ensamblado nuevo.
Veamos dos ejemplos sencillos que muestran como funciona Cecil:
-
Convertir una aplicación de consola a una aplicación Windows.- Si compilamos el siguiente código como una aplicación de consola, al ejecutarse mostrará 2 ventanas (una para la consola y otra para el formulario creado):
csharp:// console.cs
using System;
using System.Windows.Forms;class Program
{
static void Main(string[] args)
{
Form frm = new Form();
frm.Height = 100;
frm.Width = 100;
frm.ShowDialog();
}
}Para hacer la conversión usando Cecil, lo único que se tiene que hacer es:
csharp:using Mono.Cecil;
using Mono.Cecil.Cil;class Program
{
static void Main(string[] args)
{
AssemblyDefinition assembly = AssemblyFactory.GetAssembly("consola.exe");
assembly.Kind = AssemblyKind.Windows;
AssemblyFactory.SaveAssembly(assembly, "windows.exe");
}
}Si ejecutamos
windows.exe
, esta vez sólo se mostrará el formulario creado. -
Cambiar el espacio de nombres y modificadores de acceso: En este ejemplo se va a cambiar el espacio de nombres de las clases y los modificadores de acceso de un ensamblado denominado
ClassLibrary1.dll
csharp:namespace ClassLibrary1.Utility
{
public enum HashMethod
{
MD5,
SHA1
}internal class Security
{
public static string MD5(string password)
{
throw new System.Exception("The method or operation is not implemented.");
}
}
class Validation
{
public static bool IsEmail(string email)
{
throw new System.Exception("The method or operation is not implemented.");
}
private void IsUrl(string url)
{
throw new System.Exception("The method or operation is not implemented.");
}
private void IsIp(string ip)
{
throw new System.Exception("The method or operation is not implemented.");
}
}
}Para hacer realizar los cambios en el ensamblado de arriba:
csharp:using Mono.Cecil;
using Mono.Cecil.Cil;namespace CecilDemo
{
class Program
{
static void Main(string[] args)
{
string assemblyName = "ClassLibrary1.dll";/* Cargar el ensamblado */
AssemblyDefinition assembly = AssemblyFactory.GetAssembly(assemblyName);/* Iterar sobre los tipos del módulo principal */
foreach (TypeDefinition type in assembly.MainModule.Types)
{
/* Cambiar el espacio de nombres y el
* nivel de acceso a todas las clases
*/
if ("<Module>" != type.Name)
{
type.Namespace = type.Namespace.Replace("ClassLibrary1", "Buayacorp");
type.Attributes |= TypeAttributes.Public;
}
/* Hacer que todos los métodos de la clase Validation
* sean públicos y miembros de clase (static).
*/
if ("Validation" == type.Name)
{
foreach (MethodDefinition method in type.Methods)
{
/* Eliminar el atributo 'private' de cada uno de los métodos */
if ((method.Attributes & MethodAttributes.Private) == MethodAttributes.Private)
{
method.Attributes ^= MethodAttributes.Private;
}method.Attributes |= MethodAttributes.Public | MethodAttributes.Static;
}
}
}
/* Almacenar el nuevo ensamblado en CustomClassLibrary1.dll */
AssemblyFactory.SaveAssembly(assembly, "Custom" + assemblyName);
}
}
}Si observamos el ensamblado modificado con Reflector, veremos que se realizaron los cambios.
El uso de esta herramienta obviamente va a depender de las necesidades y posibles limitaciones de acceso al código fuente que tengamos, puesto que no sería nada productivo usar Cecil para hacer cosas parecidas a los ejemplos que muestro. 😀
2 replies on “Cecil: Examina y modifica ensamblados .NET al vuelo”
Yo creé no hace mucho una herramienta que usaba Cecil para modificar los ensamblados .Net, podéis echarle un vistazo en http://www.codeproject.com/useritems/NetDasm.asp
[...] un comentario del artículo donde mencionaba algunas características de Cecil, me hacían conocer la existencia [...]