2011-01-29 17 views
8

Il titolo dice più o meno tutto. Sulla base di this articolo, mi è venuta in mente questo:Come iniettare IL in un metodo in fase di esecuzione

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

Questo funziona davvero ... di tanto in tanto -.-

Ad esempio, questo funziona.

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

Tuttavia, questo non (SEHException). Tutto ciò che ho fatto è stato modificare l'ordine in cui sono state definite le funzioni.

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

Per quanto riguarda il codice nell'articolo ... non riuscivo a farlo funzionare affatto.

Qualche idea/alternative?

+0

Perché vuoi farlo? Sembra un'idea orribile. – Amy

+2

Non preoccuparti, niente di malevolo. Solo per motivi di conoscenza: D – YellPika

+0

Credo che l'unico modo sicuro per fare ciò sia iniettare il codice prima che l'assembly sia caricato. – porges

risposta

8

Questo sta facendo molte cattive ipotesi che ti morderanno nel culo.

Per prima cosa, la struttura restituita tramite riflessione non è in alcun modo garantita per indicare qualsiasi struttura di runtime. Come tale tentativo di modificare i puntatori che contiene o restituisce è semplicemente sbagliato.

In secondo luogo, se si desidera eseguire un'operazione come l'inserimento di invarianti di chiamata del metodo pre/post (ad esempio), è consigliabile creare oggetti proxy di runtime e iniettarli. O utilizzare la costruzione del metodo dinamico attraverso lo spazio dei nomi Emit. Il tentativo di manipolare le cose attraverso comportamenti non documentati/sconosciuti (come il codice precedente) non funzionerà.

È inoltre necessario rendersi conto che il JIT decide quando verrà eseguito. A volte funziona contro un'intera classe e talvolta funziona solo contro un singolo metodo. Il tuo codice non fa alcun tentativo per determinare se il metodo è stato ancora JITted e assume ciecamente che il puntatore della funzione restituito può essere modificato.

+0

Amo il nome e ho adorato lo spettacolo. Buona giornata! – Amy

+0

In tal caso ... a) Quindi cosa indica esattamente? b) Come faccio a capire se un metodo è stato JITted? – YellPika

+0

b) non è possibile, a meno che il programma non sia stato elaborato tramite NGen prima dell'esecuzione. – Amy

Problemi correlati