2009-06-06 65 views
22

Continuando con mi educación de ingeniería inversa, a menudo he querido poder copiar partes del código de ensamblaje x86 y llamarlo desde un lenguaje de alto nivel de mi elección para realizar pruebas.¿Es posible ejecutar una secuencia de ensamblaje x86 desde C#?

¿Alguien sabe de un método para llamar a una secuencia de instrucciones x86 desde un método C#? Sé que esto se puede hacer usando C++ pero tengo curiosidad si se puede hacer en C#?

Nota: No estoy hablando de ejecutar instrucciones MSIL. Estoy hablando de ejecutar una serie de instrucciones de ensamblaje x86 en bruto.

+1

Existen bibliotecas para hacer esto más fácilmente que los punteros a mano: [http://www.edgeofnowhere.cc/viewtopic.php?t=429219](http://www.edgeofnowhere.cc/ viewtopic.php? t = 429219) [http://www.edgeofnowhere.cc/viewtopic.php?t=429220](http://www.edgeofnowhere.cc/viewtopic.php?t=429220) – Cthulhon

Respuesta

42

Sólo para contrarrestar la afirmación de Brian, el código reescrito de la respuesta de leppie link:

using System; 
using System.Collections.Generic; 
using System.Runtime.InteropServices; 

namespace DynamicX86 
{ 
    class Program 
    { 
     const uint PAGE_EXECUTE_READWRITE = 0x40; 
     const uint MEM_COMMIT = 0x1000; 

     [DllImport("kernel32.dll", SetLastError = true)] 
     static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); 

     private delegate int IntReturner(); 

     static void Main(string[] args) 
     { 
      List<byte> bodyBuilder = new List<byte>(); 
      bodyBuilder.Add(0xb8); 
      bodyBuilder.AddRange(BitConverter.GetBytes(42)); 
      bodyBuilder.Add(0xc3); 
      byte[] body = bodyBuilder.ToArray(); 
      IntPtr buf = VirtualAlloc(IntPtr.Zero, (uint)body.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 
      Marshal.Copy(body, 0, buf, body.Length); 

      IntReturner ptr = (IntReturner)Marshal.GetDelegateForFunctionPointer(buf, typeof(IntReturner)); 
      Console.WriteLine(ptr()); 
     } 
    } 
} 
+0

¡Genial! Pensaba que se necesitaría una dll externa, pero estoy corregido :) – leppie

+1

Asegúrate de usar un bloque Finally para liberar la memoria, pero eso funciona (y es aterrador :)) –

+2

Quería mantener el ejemplo lo más pequeño posible . – okutane

0

Creo que puede agregar un proyecto administrado de C++ a su solución y exponer el método con el uso de instrucciones asm. Puede hacer referencia a ese proyecto desde cualquier proyecto .Net (no solo C#), por lo que puede llamar a ese método desde allí.

-1

No, pero puede escribir el ensamblado en C++ y llamarlo desde C#. Ver this example.

+4

Si puede escribe un ensamblado de C++ no administrado y lo llama desde C#, ¿no podrías llamar también al ensamblado desde el ensamblado de C++? Dios mío, tengo un dolor de cabeza ... –

+0

Ummm, ¿no es eso lo que acabo de decir? – Brian

0

Sí.

Simplemente use P/Invoke en las funciones de winapi.

WriteProcessMemory o encuentre el puntero a su búfer. Habilite el bit de ejecución en la página (no recuerdo la función para esto).

CreateThread en el puntero. WaitForObject (si desea que sea de un solo hilo).

2

Sí, véase mi respuesta detallada here
La parte principal es: (Sin ningún tipo P/Invoke o referencia externa)

public static unsafe int? InjectAndRunX86ASM(this Func<int> del, byte[] asm) 
{ 
    if (del != null) 
     fixed (byte* ptr = &asm[0]) 
     { 
      FieldInfo _methodPtr = typeof(Delegate).GetField("_methodPtr", BindingFlags.NonPublic | BindingFlags.Instance); 
      FieldInfo _methodPtrAux = typeof(Delegate).GetField("_methodPtrAux", BindingFlags.NonPublic | BindingFlags.Instance); 

      _methodPtr.SetValue(del, ptr); 
      _methodPtrAux.SetValue(del, ptr); 

      return del(); 
     } 
    else 
     return null; 
} 

que puede ser utilizado de la siguiente manera:

Func<int> del =() => 0; 
byte[] asm_bytes = new byte[] { 0xb8, 0x15, 0x03, 0x00, 0x00, 0xbb, 0x42, 0x00, 0x00, 0x00, 0x03, 0xc3 }; 
// mov eax, 315h 
// mov ebx, 42h 
// add eax, ebx 
// ret 

int? res = del.InjectAndRunX86ASM(asm_bytes); // should be 789 + 66 = 855 
Cuestiones relacionadas