Comment écrire un programme Perl, Python ou Ruby pour changer la mémoire d'un autre processus sous Windows?

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

Question

Je me demande si Perl, Python ou Ruby peuvent être utilisés pour écrire un programme afin qu'il recherche 0x12345678 dans la mémoire d'un autre processus (probablement le segment de mémoire, à la fois pour les données et les données de code), puis s'il est trouvé. , changez-le en 0x00000000? C'est quelque chose de similaire à Cheat Engine , qui peut faire quelque chose comme ça sous Windows.

Était-ce utile?

La solution

Au départ, j’ai pensé que cela n’était pas possible, mais après avoir lu le commentaire de Brian, j’ai cherché CPAN et voilà, il y a Win32 :: Process :: Memory :

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

Le module utilise apparemment le ReadProcessMemory > fonction: Voici l'une de mes tentatives:

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

Au départ, j’ai pensé que cela n’était pas possible, mais après avoir lu le commentaire de Brian, j’ai cherché CPAN et voilà, il y a Win32 :: Process :: Memory :

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

Le module utilise apparemment le ReadProcessMemory > fonction: Voici l'une de mes tentatives:

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

Sortie:

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

Sortie:

<*>

Autres conseils

Il est possible de le faire si vous avez attaché votre programme en tant que débogueur au processus, ce qui devrait être possible dans ces langues si des wrappers existent autour des API appropriées, ou en accédant directement aux fonctions de Windows à l'aide de ctypes (par exemple). python). Cependant, il peut être plus facile de le faire dans un langage plus bas niveau, car dans les langages de plus haut niveau, vous devrez vous préoccuper de la façon de traduire les types de données de haut niveau en types inférieurs, etc.

Commencez par appeler OpenProcess sur le processus. pour déboguer, avec l'accès approprié demandé (vous devez être un administrateur sur la machine / avoir des privilèges assez élevés pour y accéder). Vous devriez alors pouvoir appeler des fonctions telles que ReadProcessMemory et WriteProcessMemory pour lire et écrire dans ce processus mémoire.

[Modifier] Voici une preuve de concept python rapide d'une fonction qui lit avec succès la mémoire dans l'espace d'adressage d'un autre processus:

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)

Notez que vous aurez besoin de déterminer où dans la mémoire chercher, la majeure partie de cet espace d'adressage ne sera pas mappé, même s'il existe des décalages standard pour rechercher des éléments tels que le code de programme, les dlls, etc.

La partie amusante consiste à accéder à la mémoire de l’autre processus. CheatEngine le fait en exécutant l'intégralité de votre système d'exploitation sous une machine virtuelle permettant de désactiver la protection de la mémoire. Il existe également le modèle "en cours d'exécution sous un débogueur", ce qui signifie généralement que l'application cible doit démarrer en tant que processus enfant de l'application de modification, avec des privilèges élevés. Voir l'API Win32 pour de nombreuses activités amusantes. à ce sujet.

En Perl, une fois que vous avez eu l'accès requis, vous souhaiterez probablement interagir avec lui en utilisant Win32 :: Security :: Raw .

Vous pouvez le faire en utilisant l'injection de processus, la bibliothèque de chargement différé, etc.

Je ne vous vois pas le faire à partir des outils que vous avez énumérés. C'est C et pays assembleur et commence à vous entrer dans l'écriture de virus. Une fois que vous l'avez fait fonctionner, tous les packages anti-virus vont lui opposer son veto et essayer de l'isoler. Donc, vous feriez mieux de vouloir faire cela.

"Avec le pouvoir vient beaucoup…"

Bonne chance

Il est possible d'implémenter l'intégralité du processus dans l'un des langages répertoriés, mais un langage compilé serait préférable pour l'analyse de la mémoire (considérations de rapidité si rien d'autre). Il existe une dll (avec source) appelée SigScan disponible qui, bien que conçue sur mesure pour un jeu spécifique, pourrait probablement être modifiée pour répondre à vos besoins avec un minimum d'effort.

S'appuyant sur la bonne réponse de Brian, voici un exemple rapide et compliqué d'utilisation d'une dll pour obtenir votre adresse à partir de python. Ceci est bien sûr spécifique à l'implémentation des DLL. " Nom du module " serait généralement le nom de la DLL affiché dans Cheat Engines "Enumerate DLLs and Symbols" dialogue.

Avec l'exemple de Brian comme référence et MSDN , vous pouvez facilement l'étendre avec votre propre méthode 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)

J'ai écrit Proc :: Memory et sa bibliothèque sous-jacente libvas à cet effet. Il appelle simplement {Read, Write} ProcessMemory sous le capot de Windows, mais il prend également en charge d'autres plates-formes. Exemple:

my $mem = Proc::Memory->new(pid => $); 
$mem->poke(0x12345678, 'L') = 12;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top