Method Injection example

623 views
Skip to first unread message

Tiago

unread,
Jul 12, 2009, 8:38:57 PM7/12/09
to mono-cecil
Hi all,

This is the third and final example. It was adapted from "Advanced
Code Injection with Mono.Cecil" posted on
http://www.dotnetsharp.com/Forums/dispbbs.aspx?i=2007&j=434 (quoting
http://www.wodka-fabrik.org/ilja/blog/?tag=cecil). Author is unknow
but post date June 25th, 2008.

The above example is very well commented (something quite unusual and
that's really a pitty and yes, I'm referring to Mono.Cecil).

Again the return type of the field can be whatever you like. Again
attributes are not handled. Again load and save symbols parts are
commented (see the previous post "Property injection example"
http://groups.google.pt/group/mono-cecil/browse_thread/thread/f2a3df3a34e68639).

using System;
using Mono.Cecil;
using Mono.Cecil.Cil;

namespace CustomFieldsInjection
{
public partial class Injector
{
public static void MethodInjection(string assemblyFilename,
string typeName, string methodName)
{
AssemblyDefinition assembly = AssemblyFactory.GetAssembly
(assemblyFilename);
// Compared to Reflection, Cecil doesn`t use a
AppDomain here,
// which also allows us to load incomplete or CAS-
prohibited assemblies.

//Load the debugger symbols file
// assembly.MainModule.LoadSymbols();

// Next we'd like to define our new Method. A method
in Cecil consists of
// the return type the signature and the body (code).

//Get a TypeReference for the return Type
TypeReference returnTypeReference =
assembly.MainModule.Import(typeof(void));

//Define Method signature "public static void" methodName
MethodDefinition methodDefinition = new MethodDefinition(
methodName, MethodAttributes.Public |
MethodAttributes.Static,
returnTypeReference);

// Now we got our method but it hasn`t got any code
in it`s body.
// The new method will write a message outputString
to the Console.

//Push string onto the stack
Instruction instruction1 =
methodDefinition.Body.CilWorker.Create(OpCodes.Nop);

//Push string onto the stack
Instruction instruction2 =
methodDefinition.Body.CilWorker.Create(OpCodes.Ldstr, methodName);

//Import external method reference to Console.WriteLine()
MethodReference writeline = assembly.MainModule.Import(
typeof(Console).GetMethod("WriteLine", new Type[]
{ typeof(string) }));

// We need to generate the defined code and append it
to our new method Body

//Generate stack-push
methodDefinition.Body.CilWorker.Append(instruction1);
methodDefinition.Body.CilWorker.Append(instruction2);

//Generate call to WriteLine()
methodDefinition.Body.CilWorker.InsertAfter(
instruction2, methodDefinition.Body.CilWorker.Create
(OpCodes.Call, writeline));

//Generate return
methodDefinition.Body.CilWorker.Append
(methodDefinition.Body.CilWorker.Create(OpCodes.Ret));

// That done, we need to inject the generated Method
into the assembly

assembly.MainModule.Inject(methodDefinition,
assembly.MainModule.Types[typeName]);

// At last we need to modify Main to call our new
Method

//Get Method reference with name like methodName,
MethodReference methodReference = null;

//Get all the methods of typeName
foreach (MethodDefinition method in
assembly.MainModule.Types[typeName].Methods)
{
if (method.Name == methodName)
{
methodReference = assembly.MainModule.Import
(method);
break;
}
}

//Create call to the reference
Instruction callTest =
methodDefinition.Body.CilWorker.Create(OpCodes.Call, methodReference);

if (assembly.EntryPoint != null)
{
//Insert reference
assembly.EntryPoint.Body.CilWorker.InsertBefore
(assembly.EntryPoint.Body.Instructions[0], callTest);
}

//Save the debugger symbols file
// assembly.MainModule.SaveSymbols();

//Save the patched assembly back to disk
AssemblyFactory.SaveAssembly(assembly, assemblyFilename);
}
}
}

Have fun.
Tiago Freitas Leal
Reply all
Reply to author
Forward
0 new messages