Замена метода выполнения .NET CLR - PullRequest
1 голос
/ 28 сентября 2019

Я много читал о возможностях перезаписи методов 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, пожалуйста, дайте мне знать.

Спасибо

1 Ответ

1 голос
/ 28 сентября 2019

Фактический указатель на код метода составляет 8 байт после адреса дескриптора метода.В первом примере вы сначала приводите к типу int (который равен 4 или 8 байтам), а затем необходимо сделать шаг 8 байт, поэтому вы можете добавить 1 или 2 ints , в зависимости от архитектуры.

Во втором примере вы сначала делаете шаг, используя байт *, добавляя 8 к указателю, и только потом приводите.Кстати, последний пример должен читаться как

...
int* inj = (int*)(a.MethodHandle.Value.ToPointer() + 8);
int* tar = (int*)(b.MethodHandle.Value.ToPointer() + 8);
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...