I have access to a function body Intermediate Language like this :
byte[] ilCodes = NestedFooInfo.GetMethodBody().GetILAsByteArray();
I want to be able to modify its IL code so that whenever there is a stfld
IL command I call the following method named OnChangeField
:
public static void OnChangeField(object obj, object value)
{
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);
And I alter the original(NestedFoo(...)
) method body code like this :
byte[] ilCodes = NestedFooInfo.GetMethodBody().GetILAsByteArray();
var stfldOpCode = (byte)OpCodes.Stfld.Value;
for (int i = 0; i < ilCodes.Length; i++)
{
if (ilCodes[i] == stfldOpCode)
{
byte[] newIlCodes = ilCodes.Take(i).Concat(callIL).Concat(ilCodes.Skip(i)).ToArray(); // Insert the call instruction before the s
InjectionHelper.UpdateILCodes(NestedFooInfo, newIlCodes); // Explanation below
break; // Currently I just want to hook the first stfld as a PoC
}
}
The method body altered in my test case is this :
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();
}
[...]
}
I call the method like this :
var a = new ExceptionHandlingService();
var b = new SampleClass("bonjour", 2, 3L); // Not really relevant
a.NestedFoo(b);
And i get a :
System.InvalidProgramException: 'Common Language Runtime detected an invalid program.'
or a
System.BadImageFormatException: 'Index not found. (Exception from HRESULT: 0x80131124)'
If I remove postsharp and the services Interface from ExceptionHandlingService
I suppose that I edited the Il code in a way that lead to an invalid codeflow but looking at the call
and stfld
documentation here (p368 and p453) I don't know what I did wrong.
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.