如何在运行时将IL注入方法

Yel*_*ika 8 .net c# il code-injection

标题或多或少都说明了一切.根据这篇文章,我想出了这个:

public static unsafe void Replace(this MethodBase destination, MethodBase source)
{
    IntPtr srcHandle = source.MethodHandle.GetFunctionPointer();
    IntPtr dstHandle = destination.MethodHandle.GetFunctionPointer();

    int* dstPtr = (int*)dstHandle.ToPointer();
    *dstPtr = srcHandle.ToInt32();
}
Run Code Online (Sandbox Code Playgroud)

这实际上有效...偶尔--.-

例如,这是有效的.

public static class Program
{
    public static void Main(string[] args)
    {
        MethodInfo methodA = typeof(Program).GetMethod("A", BindingFlags.Public | BindingFlags.Static);
        MethodInfo methodB = typeof(Program).GetMethod("B", BindingFlags.Public | BindingFlags.Static);

        methodA.Replace(methodB);

        A();
        B();
    }

    public static void A()
    {
        Console.WriteLine("Hai World");
    }

    public static void B()
    {
        Console.WriteLine("Bai World");
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这不是(SEHException).我所做的就是改变定义函数的顺序.

public static class Program
{
    public static void Main(string[] args)
    {
        MethodInfo methodA = typeof(Program).GetMethod("A", BindingFlags.Public | BindingFlags.Static);
        MethodInfo methodB = typeof(Program).GetMethod("B", BindingFlags.Public | BindingFlags.Static);

        methodA.Replace(methodB);

        A();
        B();
    }

    public static void B()
    {
        Console.WriteLine("Bai World");
    }

    public static void A()
    {
        Console.WriteLine("Hai World");
    }
}
Run Code Online (Sandbox Code Playgroud)

至于文章中的代码......我根本无法让它工作.

任何想法/替代品?

Was*_*shu 8

这会产生许多糟糕的假设,这些假设会让你陷入困境.

首先,通过反射返回的结构无论如何都不能保证指向任何运行时结构.因此,尝试修改它包含或返回的指针是完全错误的.

其次,如果您希望执行类似注入前/后方法调用不变量(作为示例)的操作,那么您应该构造运行时代理对象并注入它们.或者通过Emit命名空间使用动态方法构造.试图通过无证件/未知行为(例如上面的代码)来操纵事物就行不通.

您还需要意识到JIT决定它何时运行.有时它会针对整个类运行,有时它只针对单个方法运行.您的代码不会尝试确定方法是否已经过JIT,并且盲目地假设可以修改返回的函数指针.