I have access to a function body Intermediate Language like this :
byte[] ilCodes = NestedFooInfo.GetMethodBody().GetILAsByteArray();
I am able to modify its IL code so that before executing the method body I call the following method named OnChangeField
:
public static void OnChangeField()
{
Console.WriteLine("VICTORY");
return;
}
So far I do it like this :
I define the call instruction to the method I want to call:
MethodInfo OnStfld = typeof(MethodBoundaryAspect).GetMethod("OnChangeField");
byte[] callIL = new byte[5];
callIL[0] = (byte)OpCodes.Call.Value;
callIL[1] = (byte)(OnStfld.MetadataToken & 0xFF);
callIL[2] = (byte)(OnStfld.MetadataToken >> 8 & 0xFF);
callIL[3] = (byte)(OnStfld.MetadataToken >> 16 & 0xFF);
callIL[4] = (byte)(OnStfld.MetadataToken >> 24 & 0xFF);
Notice that OnChangeField is located in the MethodBoundaryAspect Class. This class is located outside the assembly of the method beeing edited.
And this is how I alter the original(NestedFoo(...)
) method body :
byte[] ilCodes = NestedFooInfo.GetMethodBody().GetILAsByteArray();
InjectionHelper.UpdateILCodes(NestedFooInfo, callIL.Concat(ilCodes).ToArray());
And I get a :
System.BadImageFormatException: 'Index not found. (Exception from HRESULT: 0x80131124)'
But only if the hooking method OnChangeField
is outside (or so I understood) the executing assemly. If I move OnChangeField
in the same class as NestedFoo or in another class of NestedFoo
's assembly, it works perfectly.
I understand that the metadatatoken points towards a memory location which isn't valid. Is there a way to change that ?
For references here is : what the method body of the altered method looks like:
public class ExceptionHandlingService : IExceptionHandlingService
{
public static string var1 = "initialValue";
public static string Var2 { get; set; } = "initialValue";
public string var3 = "initialValue";
public string Var4 { get; set; } = "initialValue";
public string NestedFoo(SampleClass bar)
{
var1 = "value set in NestedFoo()";
Var2 = "value set in NestedFoo()";
var3 = "value set in NestedFoo()";
Var4 = "value set in NestedFoo()";
AddPerson("From", "NestedFoo", 2);
return Foo();
}
[...]
}
and how I call the altered method :
var a = new ExceptionHandlingService();
var b = new SampleClass("bonjour", 2, 3L); // Not really relevant
a.NestedFoo(b);
For those who wonder what magic happens in
InjectionHelper.UpdateILCodes(NestedFooInfo, newIlCodes);
you can check this link which shows how you can edit Il code at runtime.