5

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?

johnny 5
  • 19,893
  • 50
  • 121
  • 195
  • It looks like you're just calculating some pointers. If I were to try to append code after a function, I would make some service that would execute a provided action, then execute some callback. You don't really need reflection for that – Zakk Diaz Dec 19 '19 at 22:58
  • Nvm I see now the line that should swap the code execution entry point *tar = *inj; AFAIK I've never seen this done in C#. This beckons back to some of my c++ lectures... – Zakk Diaz Dec 19 '19 at 23:01
  • @ZakkDiaz yeah currently I'm just swapping the method pointers. I mostly want to swap the return statement with a jump to my code. They use to have a class specific for this but .net core is missing a few things still – johnny 5 Dec 20 '19 at 01:29

1 Answers1

0

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);
        
johnny 5
  • 19,893
  • 50
  • 121
  • 195
  • 1
    would be great if you added actual code, particularly a the swapping part. Note that the code in the OP swaps the method pointer but if you ever want to revert that operation by reversing the arguments, the method would remain swapped. – Denis Stepanenko Dec 24 '20 at 06:49