2009-06-06 13 views
22

Continuare il mio corso di ingegneria inversa Ho spesso desiderato poter copiare porzioni di codice assembly x86 e richiamarlo da un linguaggio di alto livello a mia scelta per il test.È possibile eseguire una sequenza di assemblaggio x86 da C#?

Qualcuno sa di un metodo per chiamare una sequenza di istruzioni x86 da un metodo C#? So che questo può essere fatto usando C++ ma sono curioso di sapere se può essere fatto in C#?

Nota: non sto parlando dell'esecuzione delle istruzioni MSIL. Sto parlando dell'esecuzione di una serie di istruzioni di assemblaggio x86 non elaborate.

+1

Esistono librerie per eseguire questa operazione più facilmente dei puntatori di funzione di marshalling 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

risposta

42

Proprio per contrastare l'affermazione di Brian, il codice riscritto da risposta di 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

Fantastico! Stavo pensando che sarebbe necessaria una dll esterna, ma sono corretto :) – leppie

+1

Assicurati di usare un blocco Finally per liberare la memoria, ma funziona (ed è terrificante :)) –

+2

Ho voluto mantenere un esempio il più piccolo possibile . – okutane

0

Credo, è possibile aggiungere un progetto C++ gestito alla soluzione ed esporre il metodo con l'utilizzo delle istruzioni asm. Puoi fare riferimento a quel progetto da qualsiasi progetto .Net (non solo C#), quindi puoi chiamare quel metodo da lì.

-1

No, ma è possibile scrivere assembly in C++ e chiamarlo da C#. Vedi this example.

+4

Se puoi scrivi un assembly C++ non gestito e chiamalo da C#, potresti anche non chiamare assembly dall'assembly C++? OMG Ho mal di testa ... –

+0

Ummm, non è quello che ho appena detto? – Brian

0

Sì.

Basta usare P/Invoke sulle funzioni winapi.

WriteProcessMemory o trova il puntatore sul tuo buffer. Abilita il bit di esecuzione sulla pagina (non ricordare la funzione per questo).

CreateThread sul puntatore. WaitForObject (se si desidera che sia a thread singolo).

2

Sì, vedere la mia risposta dettagliata here
La parte principale è: (Senza alcun P/Invoke o riferimento esterno)

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

che può essere usato come segue:

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 
Problemi correlati