How can I call a method outside the executing assembly in MSIL?

2

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.

c#
hook
clr
jit
cil
asked on Stack Overflow Nov 18, 2020 by Amon • edited Nov 19, 2020 by Amon

1 Answer

2

You need to add records to MemberRef and consecutively TypeRef or TypeSpec metadata tables to contain references to types and reference these tokens. This also involves properly writing signature blobs.

See Partition II 22.38, 22.25 of ECMA-335

answered on Stack Overflow Nov 24, 2020 by Daniel Balas

User contributions licensed under CC BY-SA 3.0