Search code examples
c#reflectionemit

Dynamically Append Code to a method .Net-Core


I'm interested in dynamically appending code in .Net-Core. Note: This is for education purposes only.

Currently I have a class which swaps methods:

public static void Inject<TTarget, TInject>(string targetFuncName, string injectFuncName)
{
    MethodInfo methodToReplace = typeof(TTarget).GetMethod(targetFuncName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
    MethodInfo methodToInject = typeof(TInject).GetMethod(injectFuncName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
    RuntimeHelpers.PrepareMethod(methodToReplace.MethodHandle);
    RuntimeHelpers.PrepareMethod(methodToInject.MethodHandle);

    unsafe
    {
        if (IntPtr.Size == 4)
        {
            int* inj = (int*)methodToInject.MethodHandle.Value.ToPointer() + 2;
            int* tar = (int*)methodToReplace.MethodHandle.Value.ToPointer() + 2;
#if DEBUG
            Console.WriteLine("\nVersion x86 Debug\n");

            byte* injInst = (byte*)*inj;
            byte* tarInst = (byte*)*tar;

            int* injSrc = (int*)(injInst + 1);
            int* tarSrc = (int*)(tarInst + 1);

            *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
            Console.WriteLine("\nVersion x86 Release\n");
            *tar = *inj;
#endif
        }
        else
        {
            long* inj = (long*)methodToInject.MethodHandle.Value.ToPointer() + 1;
            long* tar = (long*)methodToReplace.MethodHandle.Value.ToPointer() + 1;
#if DEBUG
            Console.WriteLine("\nVersion x64 Debug\n");
            byte* injInst = (byte*)*inj;
            byte* tarInst = (byte*)*tar;

            int* injSrc = (int*)(injInst + 1);
            int* tarSrc = (int*)(tarInst + 1);

            *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
 #else
            Console.WriteLine("\nVersion x64 Release\n");
            *tar = *inj;
#endif
        }
    }
}

This Code swaps the method fine, However, if you're debugging it seems like to original code is never hit. Instead I would like to swap the return statements from the method bytes and replace it with a jump statement to another function with the same parameters.

However, .Net Core doesn't currently support the MethodRental.SwapMethodBody How Can dynamically append code to the end of a function?


Solution

  • I figured out a cheat way to do it. I haven't written all the code yet but I'll explain in pseudo code

    Say we have a method:

    public class ValuesController: ControllerBase
    {
        [HttpGet("Seven")]
        public int Seven(string id)
        {
            return 7;
        }
    }
    

    We want to swap it with another method

    public int Eight(int retValue)
    {
        return retValue + 1;
    }
    

    We can generate a Func in a dynamic assembly. Which looks like so:

    public int Dummy(string id)
    {}
    
    public int DummyFuncContainer(string id)
    {
        var result = Dummy(id);
        return Eight(result);
    }
    

    Then all you need to do is.

    Swap the Dummy() method with the func we want Seven() and then we swap Seven()(Which is now pointing at Dummy()) with DummyFuncContainer().

    EDIT: Sorry for clarification you just need to grab the methods like so to pass this. I don't have the full example in front of me at the moment.

    var methodToReplace = typeof(ValuesController).GetMethod("Seven", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);