2011-01-29 2 views
8

Название более или менее говорит обо всем. На основании this статьи, я придумал это:Как внедрить IL в метод во время выполнения

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(); 
} 

Это на самом деле работает ... иногда -.-

Например, это работает.

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"); 
    } 
} 

Однако, это не (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"); 
    } 
} 

Что касается кода в статье ... Я не мог заставить его работать вообще.

Любые идеи/альтернативы?

+0

Зачем вы хотите это сделать? Это звучит как ужасная идея. – Amy

+2

Не волнуйся - ничего злонамеренного. Просто ради знания: D – YellPika

+0

Я считаю, что единственный безопасный способ сделать это - ввести код перед загрузкой сборки. – porges

ответ

8

Это делает много плохих предположений, которые укусят вас в задницу.

Прежде всего, структура, возвращаемая с помощью отражения, не гарантируется, в любом случае, указывать на любые структуры времени выполнения. Поскольку такая попытка изменить указатели, которые она содержит или возвращает, просто неверна.

Во-вторых, если вы хотите сделать что-то вроде инъецирования инвариантов вызова метода pre/post (в качестве примера), то вы, вероятно, должны построить объекты прокси-сервера во время выполнения и вместо этого ввести их. Или используйте динамическое построение метода через пространство имен Emit. Попытка манипулировать вещами через недокументированное/неизвестное поведение (например, приведенный выше код) просто не работает.

Вам также необходимо понять, что JIT решает, когда он будет работать. Иногда он работает против целого класса, а иногда он работает только против одного метода. В вашем коде не делается попыток определить, был ли еще метод JITted, и слепо предполагает, что возвращаемый указатель функции может быть изменен.

+0

Мне нравится имя, и мне понравилось шоу. Хорошего дня! – Amy

+0

В этом случае ... а) Итак, что именно это указывает на то? б) Как выяснить, был ли метод JITted? – YellPika

+0

b) вы не можете, если только программа не была обработана через NGen перед выполнением. – Amy

Смежные вопросы