¿Cómo escribir un programa Perl, Python o Ruby para cambiar la memoria de otro proceso en Windows?

StackOverflow https://stackoverflow.com/questions/1013828

Pregunta

Me pregunto si Perl, Python o Ruby se pueden usar para escribir un programa para que busque 0x12345678 en la memoria de otro proceso (probablemente el montón, tanto para datos como para datos de código) y luego si se encuentra , cámbielo a 0x00000000? Es algo similar a Cheat Engine , que puede hacer algo así en Windows.

¿Fue útil?

Solución

Al principio pensé que esto no era posible, pero después de ver el comentario de Brian, busqué en CPAN y he aquí, hay Win32 :: Process :: Memory :

C:\> ppm install Win32::Process::Info
C:\> ppm install Win32::Process::Memory

El módulo aparentemente usa la ReadProcessMemory función: este es uno de mis intentos:

#!/usr/bin/perl
use strict; use warnings;

use Win32;
use Win32::Process;
use Win32::Process::Memory;

my $process;

Win32::Process::Create(
    $process,
    'C:/opt/vim/vim72/gvim.exe',
    q{},
    0,
    NORMAL_PRIORITY_CLASS,
    q{.}
) or die ErrorReport();

my $mem = Win32::Process::Memory->new({
    pid => $process->GetProcessID(),
    access => 'read/query',
});

$mem->search_sub( 'VIM', sub {
    print $mem->hexdump(

Al principio pensé que esto no era posible, pero después de ver el comentario de Brian, busqué en CPAN y he aquí, hay Win32 :: Process :: Memory :

C:\> ppm install Win32::Process::Info
C:\> ppm install Win32::Process::Memory

El módulo aparentemente usa la ReadProcessMemory función: este es uno de mis intentos:

C:\Temp> proc
0052A580 : 56 49 4D 20 2D 20 56 69 20 49 4D 70 72 6F 76 65 : VIM - Vi IMprove
0052A590 : 64 20 37 2E 32 20 28 32 30 30 38 20 41 75 67 20 : d 7.2 (2008 Aug

0052A5F0 :       56 49 4D 52 55 4E 54 49 4D 45 3A 20 22 00 :   VIMRUNTIME: ".
0052A600 : 20 20 66 61 6C 6C 2D 62 61 63 6B 20 66 6F 72 20 :   fall-back for
0052A610 : 24 56                                           : $V

Salida:

<*>[0], 0x20), "\n"; }); sub ErrorReport{ Win32::FormatMessage( Win32::GetLastError() ); } END { $process->Kill(0) if $process }

Salida:

<*>

Otros consejos

Es posible hacerlo si ha adjuntado su programa como depurador al proceso, lo que debería ser posible en esos idiomas si existen envoltorios alrededor de las API apropiadas, o accediendo directamente a las funciones de Windows a través de algo como ctypes (para pitón). Sin embargo, puede ser más fácil hacerlo en un lenguaje de nivel más bajo, ya que en los de nivel superior tendrá que preocuparse por cómo traducir los tipos de datos de alto nivel a los de nivel inferior, etc.

Comience llamando a OpenProcess en el proceso para depurar, con el acceso apropiado solicitado (necesitará ser un administrador en la máquina / tener privilegios bastante altos para obtener acceso). Entonces debería poder llamar a funciones como ReadProcessMemory y WriteProcessMemory para leer y escribir en ese proceso memoria.

[Editar] Aquí hay una prueba rápida de concepto de Python de una función que lee con éxito la memoria del espacio de direcciones de otro proceso:

import ctypes
import ctypes.wintypes
kernel32 = ctypes.wintypes.windll.kernel32

# Various access flag definitions:
class Access:
    DELETE      = 0x00010000
    READ_CONTROL= 0x00020000
    SYNCHRONIZE = 0x00100000
    WRITE_DAC   = 0x00040000
    WRITE_OWNER = 0x00080000
    PROCESS_VM_WRITE = 0x0020
    PROCESS_VM_READ = 0x0010
    PROCESS_VM_OPERATION = 0x0008
    PROCESS_TERMINATE = 0x0001
    PROCESS_SUSPEND_RESUME = 0x0800
    PROCESS_SET_QUOTA = 0x0100
    PROCESS_SET_INFORMATION = 0x0200
    PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
    PROCESS_QUERY_INFORMATION = 0x0400
    PROCESS_DUP_HANDLE = 0x0040
    PROCESS_CREATE_THREAD = 0x0002
    PROCESS_CREATE_PROCESS = 0x0080

def read_process_mem(pid, address, size):
    """Read memory of the specified process ID."""
    buf = ctypes.create_string_buffer(size)
    gotBytes = ctypes.c_ulong(0)
    h = kernel32.OpenProcess(Access.PROCESS_VM_READ, False, pid)
    try:
        if kernel32.ReadProcessMemory(h, address, buf, size, ctypes.byref(gotBytes)):
            return buf
        else:
            # TODO: report appropriate error GetLastError
            raise Exception("Failed to access process memory.")
    finally:
        kernel32.CloseHandle(h)

Tenga en cuenta que tendrá que determinar dónde buscar cosas en la memoria: la mayor parte de ese espacio de direcciones no se asignará, aunque hay algunas compensaciones estándar para buscar cosas como el código del programa, dlls, etc.

Bueno, la parte divertida es obtener acceso a la memoria del otro proceso. CheatEngine lo hace ejecutando todo su sistema operativo en una máquina virtual que permite vencer la protección de la memoria. También existe el modelo de "ejecución bajo un depurador", que generalmente significa iniciar la aplicación de destino como un proceso secundario de la aplicación de modificación, con privilegios elevados. Consulte la API Win32 para muchas cosas divertidas sobre eso.

En Perl, una vez que tuvo el acceso requerido, probablemente quiera interactuar con él usando Win32 :: Security :: Raw .

Hay formas de hacer esto usando la inyección de proceso, la biblioteca de carga retardada, etc.

No te veo haciéndolo desde las herramientas que has enumerado. Este es el país C y ensamblador y está comenzando a meterlo en territorio de escritura de virus. Una vez que lo haga funcionar, cualquier paquete de antivirus lo vetará en ejecución e intentará aislarlo. Entonces es mejor que realmente quieras hacer esto.

" Con el poder viene mucho ... "

Buena suerte

Es posible implementar todo el proceso en uno de los idiomas enumerados, pero un lenguaje compilado sería mejor para el escaneo de memoria (consideraciones de velocidad, si nada más). Hay un dll (con fuente) llamado SigScan disponible que, aunque está diseñado para un juego específico, probablemente podría modificarse para satisfacer sus necesidades con un mínimo esfuerzo.

Basándose en la respuesta correcta de Brian, aquí hay un ejemplo rápido y sucio de usar un dll para obtener su dirección desde Python. Esto es, por supuesto, específico de la implementación de DLL. " Nombre del módulo " generalmente sería el nombre dll como se muestra en Cheat Engines " Enumerate DLLs and Symbols " cuadro de diálogo.

Con el ejemplo de Brian como guía y MSDN puede ampliar esto fácilmente con su propio método WriteProcessMemory.

import win32defines
import win32process
import win32gui
from ctypes import *
SigScan = cdll.SigScan
kernel32 = windll.kernel32
addresses = {"Value1" : {"sigArg1" : "b0015ec390518b4c24088d4424005068", 
                          "sigArg2" : 36, 
                          "address" : None,
                          "size"    : 32
                         },
            "Value2" :{"sigArg1" : "3b05XXXXXXXX741285c0",
                          "sigArg2" : None, 
                          "address" : None,
                          "size"    : 32
                        }
        }

def read_process_mem(pid, address, size):
    """Read memory of the specified process ID."""
    buf = create_string_buffer(size)
    gotBytes = c_ulong(0)
    h = kernel32.OpenProcess(win32defines.PROCESS_VM_READ, False, pid)
    try:
        if kernel32.ReadProcessMemory(h, address, buf, size, byref(gotBytes)):
            return buf
        else:
            # TODO: report appropriate error GetLastError
            raise Exception("Failed to access process memory.")
    finally:
        kernel32.CloseHandle(h)
if __name__ == "__main__":
    pid, id = None, None
    ## HWND 
    hwnd = win32gui.FindWindowEx(0, 0, 0, "Window Name here")
    ## pid
    pid = win32process.GetWindowThreadProcessId(hwnd)[-1]
    ## Initialize the sigscan dll
    SigScan.InitializeSigScan(pid, "Module Name")
    ## Find all the addresses registered
    for key in addresses.keys():
        addresses[key]["address"] = SigScan.SigScan(addresses[key]["sigArg1"],
            addresses[key]["sigArg2"])
    ## Allow the scanner to clean up
    SigScan.FinalizeSigScan()
    for key in addresses.keys():
        if addresses[key]["address"] != None:
            print repr(read_process_mem(pid, addresses[key]["address"],
                            addresses[key]["size"]).raw)

Escribí Proc :: Memory y su biblioteca subyacente libvas para este propósito. Simplemente llama a {Read, Write} ProcessMemory debajo del capó en Windows, pero también es compatible con otras plataformas. Ejemplo:

my $mem = Proc::Memory->new(pid => $); 
$mem->poke(0x12345678, 'L') = 12;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top