Come scrivere un programma Perl, Python o Ruby per cambiare la memoria di un altro processo su Windows?

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

Domanda

Mi chiedo se Perl, Python o Ruby possano essere usati per scrivere un programma in modo che cercherà 0x12345678 nella memoria di un altro processo (probabilmente l'heap, sia per i dati che per i dati del codice) e quindi se viene trovato , cambiarlo in 0x00000000? È qualcosa di simile a Cheat Engine , che può fare qualcosa del genere su Windows.

È stato utile?

Soluzione

Inizialmente pensavo che ciò non fosse possibile ma dopo aver visto il commento di Brian, ho cercato CPAN ed ecco, c'è Win32 :: Process :: Memory :

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

Apparentemente il modulo utilizza ReadProcessMemory funzione: ecco uno dei miei tentativi:

#!/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(

Inizialmente pensavo che ciò non fosse possibile ma dopo aver visto il commento di Brian, ho cercato CPAN ed ecco, c'è Win32 :: Process :: Memory :

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

Apparentemente il modulo utilizza ReadProcessMemory funzione: ecco uno dei miei tentativi:

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

Output:

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

Output:

<*>

Altri suggerimenti

È possibile farlo se hai collegato il tuo programma come debugger al processo, cosa che dovrebbe essere possibile in quelle lingue se esistono wrapper attorno alle API appropriate, o accedendo direttamente alle funzioni di Windows attraverso qualcosa come ctypes (per pitone). Tuttavia, potrebbe essere più facile farlo in una lingua di livello più basso, poiché in quelle di livello superiore dovrai preoccuparti di come tradurre i tipi di dati di alto livello in quelli di livello inferiore ecc.

Inizia chiamando OpenProcess sul processo per eseguire il debug, con l'accesso appropriato richiesto (devi avere un amministratore sulla macchina / avere privilegi abbastanza alti per ottenere l'accesso). Dovresti quindi essere in grado di chiamare funzioni come ReadProcessMemory e WriteProcessMemory per leggere e scrivere su quel processo la memoria.

[Modifica] Ecco una rapida dimostrazione di pitone del concetto di una funzione che legge correttamente la memoria dallo spazio degli indirizzi di un altro processo:

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)

Nota che dovrai determinare dove in memoria cercare le cose - la maggior parte di quello spazio degli indirizzi sarà non mappato, pensando che ci siano alcuni offset standard per cercare cose come il codice del programma, le dll ecc.

Bene, la parte divertente è ottenere l'accesso alla memoria dell'altro processo. CheatEngine lo fa eseguendo l'intero sistema operativo in una macchina virtuale che consente di annullare la protezione della memoria. Esiste anche il modello "running under a debugger", che in genere significa avviare l'applicazione di destinazione come processo figlio dell'applicazione di modifica, con privilegi elevati. Vedi API Win32 per tante cose divertenti a tale proposito.

In Perl, una volta ottenuto l'accesso richiesto, probabilmente vorrai interagire con esso usando Win32 :: Security :: Raw .

Ci sono modi per farlo usando l'iniezione di processo, la libreria di caricamento ritardato ecc.

Non ti vedo farlo dagli strumenti che hai elencato. Questo è il paese C e assemblatore e sta iniziando a portarti nel territorio di scrittura dei virus. Una volta che funziona, tutti i pacchetti anti-virus lo porranno in esecuzione e proveranno a isolarlo. Quindi è meglio che tu voglia davvero farlo.

" Con il potere arriva molto .... "

Buona fortuna

È possibile implementare l'intero processo in una delle lingue elencate ma una lingua compilata sarebbe migliore per la scansione della memoria (considerazioni sulla velocità se non altro). Esiste una dll (con sorgente) chiamata SigScan disponibile che, sebbene su misura per un gioco specifico, potrebbe probabilmente essere modificata per soddisfare le tue esigenze con il minimo sforzo.

Basandoci sulla risposta corretta di Brian, ecco un esempio veloce e sporco dell'uso di una dll per ottenere il tuo indirizzo da Python. Questo è, ovviamente, specifico per l'implementazione delle DLL. " Nome del modulo " sarebbe generalmente il nome della dll come visualizzato in Cheat Engines "Enumerate DLLs and Symbols" finestra di dialogo.

Con l'esempio di Brian come linea guida e MSDN puoi facilmente estenderlo con il tuo metodo 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)

Ho scritto Proc :: Memory e la sua libreria sottostante libvas a questo scopo. Chiama semplicemente {Read, Write} ProcessMemory sotto il cofano di Windows, ma supporta anche altre piattaforme. Esempio:

my $mem = Proc::Memory->new(pid => $); 
$mem->poke(0x12345678, 'L') = 12;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top