2011-01-29 20 views
8

Título más o menos lo dice todo. Sobre la base de this artículo, me he llegado con esto:Cómo inyectar IL en un método en tiempo de ejecución

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

Esto funciona realmente ... de vez en cuando -.-

Por ejemplo, esto funciona.

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

Sin embargo, esto no (SEHException). Todo lo que hice fue cambiar el orden en que se definieron las funciones.

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

En cuanto al código en el artículo ... No pude conseguir que funcione en absoluto.

¿Alguna idea/alternativa?

+0

¿Por qué quieres hacer esto? Esto suena como una idea horrible. – Amy

+2

No se preocupe, nada malicioso. Solo por el conocimiento: D – YellPika

+0

Creo que la única forma segura de hacerlo es inyectar el código antes de que se cargue el ensamblaje. – porges

Respuesta

8

Esto está haciendo un montón de suposiciones malas que te morderán en el trasero.

Lo primero es lo primero, la estructura devuelta por reflexión no está garantizada, de ninguna manera, para apuntar a ninguna estructura de tiempo de ejecución en absoluto. Como tal, intentar modificar los punteros que contiene o devuelve es simplemente erróneo.

En segundo lugar, si desea hacer algo como inyectar invariantes de llamadas al método pre/post (como ejemplo), entonces probablemente debería construir objetos proxy en tiempo de ejecución e inyectarlos en su lugar. O utilice la construcción de métodos dinámicos a través del espacio de nombres Emitir. Intentar manipular cosas a través de comportamientos indocumentados/desconocidos (como el código anterior) simplemente no funcionará.

También debe tener en cuenta que el JIT decide cuándo se ejecutará. A veces se ejecuta en contra de una clase completa, y a veces simplemente se ejecuta en contra de un único método. Su código no intenta determinar si el método ha sido JITted aún, y ciegamente asume que el puntero a la función devuelto puede ser modificado.

+0

Me encanta el nombre y me encantó el espectáculo. ¡Que tengas un buen día! – Amy

+0

En ese caso ... a) Entonces, ¿a qué se refiere exactamente? b) ¿Cómo averiguo si un método ha sido JITted? – YellPika

+0

b) no se puede, a menos que el programa se haya procesado a través de NGen antes de la ejecución. – Amy

Cuestiones relacionadas