.NET CLR 运行时方法替换

.NET CLR Runtime Method Replacement

我已经阅读了很多有关在运行时覆盖 C#/.NET 方法的可能性的内容。在查看了一些示例代码后,有一个问题我无法回答。 非常 用于运行时方法替换的简单 PoC 可能如下所示:

    class Program
    {
        public static void A(int x)
        {
            Console.WriteLine("A: " + x);
        }

        public static void B(int x)
        {
            Console.WriteLine("B: " + x);
        }

        internal static void Main(string[] args)
        {

            MethodInfo a = null;
            MethodInfo b = null;

            foreach(MethodInfo mi in typeof(Program).GetMethods())
            {
                if (mi.Name == "A" || mi.Name == "B")
                {
                    // make sure methods are jitted
                    RuntimeHelpers.PrepareMethod(mi.MethodHandle);
                }

                if (mi.Name == "A") a = mi;
                if (mi.Name == "B") b = mi;
            }

            unsafe
            {
                if (IntPtr.Size == 4) // x86
                {
                    int* inj = (int*)a.MethodHandle.Value.ToPointer() + 2;
                    int* tar = (int*)b.MethodHandle.Value.ToPointer() + 2;
                    *tar = *inj;
                }
                else  // x64
                {
                    ulong* inj = (ulong*)a.MethodHandle.Value.ToPointer() + 1;
                    ulong* tar = (ulong*)b.MethodHandle.Value.ToPointer() + 1;
                    *tar = *inj;
                }
            }

            Program.A(0);
            Program.B(1);

            Console.ReadLine();

        }
    }

正如人们所期望的那样,对 A(0) and B(1) 的调用现在打印:

A: 0
A: 1

到目前为止一切顺利。 但是,我也看到了一个例子,x86/x64 代码之间似乎没有区别:

...
int* inj = (int*)(a.MethodHandle.Value.ToPointer() + 8);
int* tar = (int*)(b.MethodHandle.Value.ToPointer() + 8);
...

在这种情况下,8 被添加到指针。有人可以解释这背后的原因吗?另外,这个指针偏移到底是什么意思?如果有人可以推荐有关 C#/.NET/CLR 内部原理的好的阅读材料,请告诉我。

谢谢

实际指向方法代码的指针在方法句柄地址后8 字节。 在您的第一个示例中,您首先转换为 int(4 或 8 个字节),然后需要跨 8 个字节,因此您可以添加 1 或 2 ints,具体取决于关于架构。

在您的第二个示例中,您首先使用 byte* 向指针添加 8,然后才强制转换。 顺便说一句,后面的例子应该是

...
int* inj = (int*)(a.MethodHandle.Value.ToPointer() + 8);
int* tar = (int*)(b.MethodHandle.Value.ToPointer() + 8);
...