2009-04-23 9 views
6

¿Cómo es posible buscar una matriz de bytes [] en la memoria de otro proceso y luego obtener la dirección en el lugar donde se encuentra la matriz de bytes []?C#: Buscar una matriz de bytes [] en la memoria de otro proceso

Quiero escribir una matriz de bytes en la memoria de otro proceso (WriteProcessMemory()). Uno de los parámetros de esa llamada es uint Address.Well Quiero obtener la dirección buscando una matriz de bytes en el proceso.

Por ejemplo busco {0xEB, 0x20,0x68,0x21,0x27,0x65, ??, 0x21,0x64,0xA1}

suponemos que esta matriz se coloca solamente en un lugar en la memoria de el proceso al que me gustaría escribir la memoria.

Para obtener esa dirección, tengo que buscar esa matriz de bytes.

¿Se puede hacer en C#?

EDITAR:Esto es para aplicaciones nativas, NO .NET. No es necesario rechazar mi pregunta, hay componentes para C++ que hacen esto, solo quiero hacerlo en C#.

¡Gracias por su comprensión!

+0

Sólo por curiosidad, ¿por qué? – Lazarus

+1

No quiero usar dll externo de C++, porque requiere Runtime y me gustaría trabajar con la memoria en NET también. –

+1

John: no hay tiempo de ejecución que necesite para una aplicación nativa que no está incluida con Windows, y tendrá que trabajar con la memoria sin procesar de todos modos. – Richard

Respuesta

0

¿Se puede hacer en C#?

Sí. Pero muy duro. Es difícil desde una aplicación nativa donde no hay impedancia que no coincida con la vista no administrada de los procesos y sus mapas de memoria que necesitará usar.

Consideraciones:

  • Se necesitarán permiso para abrir el proceso de conseguir una manija.
  • Mientras que el espacio de memoria virtual de un proceso de 32 bits tiene entre dos y cuatro GB de tamaño (dependiendo del sistema operativo host y el interruptor/3GB), gran parte de este rango de direcciones no se asignará, y su lectura provocará un error de página. Realmente necesita saber qué páginas están asignadas y para qué evitar muchos accesos de página no válidos.

Sugerencias:

  • ¿Realmente realmente necesita hacer esto? En serio, esto será difícil.
  • Considere hacer una aplicación nativa, esto evitará trabajar en la cerca nativa/administrada (esto podría incluir una biblioteca nativa con una aplicación de controlador administrado).
  • ¿Realmente necesita hacer esto?
  • Considere hacer el trabajo dentro del proceso objetivo. Esto requerirá cierta astucia (documentada) para inyectar un hilo, pero debería ser mucho más rápida.
  • Comience leyendo en Windows cómo funciona la memoria de procesos (comience con Windows Internals y (no puede recordar su nombre en la última edición) Libro de Jeffrey Richter sobre desarrollo de aplicaciones Win32.
  • ¿Realmente necesita hacer esto? Tiene que haber algo más sencillo ... podrías automatizado un depurador
+0

Puedo obtener la dirección en el depurador, el problema es que la aplicación en la que estoy haciendo esto es comercial y se actualiza una vez por semana. Supongo que tengo que hacer esto. –

+0

@John: en ese caso, tanto VS como windbg tienen modelos de extensibilidad (VS es .NET) que deberían evitar todo el trabajo duro. – Richard

+0

¿Podría darme más información al respecto? –

-3

Si es posible, no lo creo. Y realmente espero que no, porque eso sería un grave riesgo de seguridad.

+0

Eso se puede hacer en C++, es para aplicaciones nativas, no para NET. –

+3

¿Por qué sería un riesgo de seguridad? ¿Cómo crees que funcionan los depuradores? :) –

+0

No es un riesgo para la seguridad, debe abrir el proceso y eso significa pasar por la ACL del otro proceso. Los no administradores solo pueden abrir sus propios procesos, los administradores (con elevación, incluido cualquier usuario con privilegios de depuración) pueden abrir cualquier proceso – Richard

6

Supongo que podría usar la llamada a la API de Windows ReadProcessMemory. Incluso hay un premade P/Invoke signature para que no tenga que molestarse en crearlo manualmente. Navega por la memoria del proceso, busca su patrón y listo.

+0

Necesito especificar la dirección a la que tengo que llamar (uno de sus parámetros es la dirección). Bueno, mi pregunta es: cómo obtener la dirección buscando en la memoria. Pensé en buscar toda la imagen, pero eso tomará mucho tiempo. –

+2

Supongamos que está haciendo eso en un entorno de 32 bits, tiene sentido usar páginas de 4096 bytes para su búsqueda, es decir, 1048576 en total. ReadProcessMemory devuelve falso si la dirección no es accesible, lo que acelera considerablemente el ciclo. No creo que tome mucho tiempo terminar especialmente, ya que es muy poco probable que su patrón sea más de 1GB. Y realmente no tienes otra opción tampoco. –

+1

@John: necesitará utilizar las API de memoria para leer solo la memoria legible (consulte VMMap.exe mostrando la memoria libre habilitada ... la mayor parte del mapa de la memoria virtual no se utiliza). – Richard

1

Esto puede ayudar a encontrar el camino correcto:?

private static int GetMemoryAddressOfString(byte[] searchedBytes, Process p) 
{ 
    //List<int> addrList = new List<int>(); 
    int addr = 0; 
    int speed = 1024*64; 
    for (int j = 0x400000; j < 0x7FFFFFFF; j+= speed) 
    { 
     ManagedWinapi.ProcessMemoryChunk mem = new ProcessMemoryChunk(p, (IntPtr)j, speed + searchedBytes.Length); 

     byte[] bigMem = mem.Read(); 

     for (int k = 0; k < bigMem.Length - searchedBytes.Length; k++) 
     { 
      bool found = true; 
      for (int l = 0; l < searchedBytes.Length; l++) 
      { 
       if(bigMem[k+l] != searchedBytes[l]) 
       { 
        found = false; 
        break; 
       } 
      } 
      if(found) 
      { 
       addr = k+j; 
       break; 
      } 
     } 
     if (addr != 0) 
     { 
      //addrList.Add(addr); 
      //addr = 0; 
      break; 
     } 
    } 
    //return addrList; 
    return addr; 
} 
+0

Me gusta este método mejor que buscar el patrón usando ReadProcessMemory(). Sin embargo, esto tiene un problema al buscar el patrón en la región de memoria no grabable. –

3

usted querrá utilizar estas API:

[DllImport("Kernel32.Dll")] 
    public static extern uint VirtualQueryEx(IntPtr ProcessHandle, uint Address, ref MEMORY_BASIC_INFORMATION MemInfo, int MemInfoLength); 
    [DllImport("Kernel32.Dll")] 
    public static extern bool ReadProcessMemory(IntPtr ProcessHandle, uint Address, byte[] Buffer, uint Size, ref uint BytesRead); 
    [DllImport("Kernel32.Dll")] 
    public static extern bool WriteProcessMemory(IntPtr ProcessHandle, uint Address, byte[] Buffer, uint Size, ref uint BytesRead); 

pinvoke.net es un gran recurso para las llamadas a la API de Windows. Escribí un entrenador para GTA: Vice City que usa estas llamadas si quieres ver el code en sourceforge. El código no es bonito, fue hace mucho tiempo y lo tiré todo, pero hay clases de ayuda para enumerar regiones de memoria para un proceso y buscar ciertos bytes o cadenas.

17

¿Se puede hacer en C#? Siempre es posible en C# (o en cualquier otro idioma), solo necesita averiguar cómo;

codificación duro aquí:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Diagnostics; 
using System.Runtime.InteropServices; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     [DllImport("kernel32.dll", SetLastError = true)] 
      static extern bool ReadProcessMemory(
      IntPtr hProcess, 
      IntPtr lpBaseAddress, 
      [Out] byte[] lpBuffer, 
      int dwSize, 
      out int lpNumberOfBytesRead 
     ); 

    [DllImport("kernel32.dll")] 
    public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool CloseHandle(IntPtr hObject); 
    static void Main(string[] args) 
    { 
     Process[] procs = Process.GetProcessesByName("explorer"); 
     if (procs.Length <= 0) //proces not found 
      return; //can replace with exit nag(message)+exit; 
     IntPtr p = OpenProcess(0x10 | 0x20, true, procs[0].Id); //0x10-read 0x20-write 

     uint PTR = 0x0; //begin of memory 
     byte[] bit2search1 = {0xEB ,0x20,0x68,0x21,0x27,0x65}; //your bit array until ?? 
     int k = 1; //numer of missing array (??) 
     byte[] bit2search2 = {0x21,0x64,0xA1};//your bit array after ?? 
     byte[] buff = new byte[bit2search1.Length+1+bit2search2.Length]; //your array lenght; 
     int bytesReaded; 
     bool finded = false; 

     while (PTR != 0xFF000000) //end of memory // u can specify to read less if u know he does not fill it all 
     { 
      ReadProcessMemory(p, (IntPtr)PTR, buff, buff.Length, out bytesReaded); 
      if (SpecialByteCompare(buff, bit2search1,bit2search2,k)) 
      { 
       //do your stuff 
       finded = true; 
       break; 
      } 
      PTR += 0x1; 
     } 
     if (!finded) 
      Console.WriteLine("sry no byte array found"); 
    } 

    private static bool SpecialByteCompare(byte[] b1, byte[] b2, byte[] b3, int k) //readed memory, first byte array, second byte array, number of missing byte's 
    { 
     if (b1.Length != (b2.Length + k + b3.Length)) 
      return false; 
     for (int i = 0; i < b2.Length; i++) 
     { 
      if (b1[i] != b2[i]) 
       return false; 
     } 

     for (int i = 0; i < b3.Length; i++) 
     { 
      if (b1[b2.Length + k + i] != b3[i]) 
       return false; 
     } 
     return true; 
    } 
} 

}

+1

@Danie - El ejemplo podría ayudar a otros - nice – Leons

+2

+1 Por responder realmente a la pregunta sin tratar de mantenerse elegante y ser moral. –

Cuestiones relacionadas