2009-06-18 9 views
8

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 tas, pour les données de données et de code), puis s'il est trouvé, le changer en 0x00000000? C'est quelque chose de similaire à Cheat Engine, qui peut faire quelque chose comme ça sur Windows.Comment écrire un programme Perl, Python ou Ruby pour changer la mémoire d'un autre processus sous Windows?

Répondre

13

Je pensais d'abord cela n'a pas été possible, mais après avoir vu le commentaire de Brian, je cherchai CPAN et voilà, il est Win32::Process::Memory:

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

Le module utilise apparemment la fonction ReadProcessMemory: Voici 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($_[0], 0x20), "\n"; 
}); 

sub ErrorReport{ 
    Win32::FormatMessage(Win32::GetLastError()); 
} 

END { $process->Kill(0) if $process } 

sortie:

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 
+1

Ce n'est pas vraiment vrai - avec des autorisations appropriées, il est possible d'accéder et de modifier un autre processus mémoire (ce qui est le fonctionnement des débogueurs) Ce n'est pas un trou de sécurité si vous êtes déjà administrateur. – Brian

4

Il existe des moyens de le faire en utilisant l'injection de processus, la bibliothèque de chargement de délai, etc.

Je ne vous vois pas à partir des outils que vous avez listés. C'est pays C et assembleur et commence à vous entrer dans le territoire d'écriture de virus. Une fois que vous l'aurez fait fonctionner, tous les paquets anti-virus mettront leur veto en cours d'exécution et essayeront de l'isoler. Donc tu ferais mieux de vraiment faire ça.

« Avec le pouvoir vient beaucoup .... »

Bonne chance

6

Eh bien, la partie amusante devient l'accès à la mémoire de l'autre processus. CheatEngine le fait en exécutant votre système d'exploitation entier sous une machine virtuelle qui permet de vaincre la protection de la mémoire. Il y a aussi le modèle 'running under a debugger', qui signifie généralement démarrer l'application cible en tant que processus enfant de l'application de modification, avec des privilèges élevés. Voir le Win32 API pour beaucoup de choses amusantes à ce sujet.

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

+0

est-ce que cela signifie que si je lance Cheat Engine et aussi une application tierce ou shareware, l'ordinateur est particulièrement vulnérable parce que l'ordinateur entier a désactivé la protection de la mémoire? (le shareware peut essentiellement modifier le code ou les données du processus IE ou Firefox) –

+0

Non, ce n'est pas aussi grave que ça. CheatEngine fait son affaire grâce à un ensemble d'opérations étendu et authentifie l'accès à l'aide d'une clé de hachage. Il ne s'agit donc pas simplement de désactiver la protection de la mémoire, mais de la contourner à l'aide d'un mécanisme doté d'au moins une certaine protection. – chaos

8

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 langages si des wrappers autour des API appropriées existent, ou en accédant directement aux fonctions de Windows par quelque chose comme ctypes (pour python). Cependant, il peut être plus facile de le faire dans un langage de plus bas niveau, car dans les langages de plus haut niveau, vous devrez vous préoccuper de la traduction des types de données de haut niveau vers les langages inférieurs. pour déboguer, avec l'accès approprié demandé (vous devrez être un administrateur sur la machine/avoir des privilèges assez élevés pour accéder). Vous devriez alors pouvoir appeler des fonctions comme ReadProcessMemory et WriteProcessMemory pour lire et écrire dans la mémoire de ce processus.

[Modifier] Voici une preuve python rapide du concept d'une fonction qui lit avec succès la mémoire d'un autre espace d'adressage de 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ù en mémoire de chercher choses - la plupart de cet espace d'adressage va être démappé, pensé qu'il y a des décalages standards pour rechercher des choses comme le code du programme, les DLL, etc.

+0

C'est incroyablement cool – UberJumper

0

Il est possible de mettre en œuvre l'ensemble du processus dans l'une des langues répertoriées, mais un langage compilé serait préférable pour l'analyse de la mémoire (considérations de vitesse si rien d'autre). Il existe un dll (avec source) appelé SigScan disponible qui, bien que conçu pour un jeu spécifique, pourrait probablement être modifié pour répondre à vos besoins avec un minimum d'effort. En se basant sur la bonne réponse de Brian, voici un exemple rapide et sale d'utilisation d'une DLL pour obtenir votre adresse depuis python. Ceci est, bien sûr, spécifique à l'implémentation des DLL. "Nom du module" correspond généralement au nom de la DLL tel qu'affiché dans la boîte de dialogue "Énumérer les DLL et les symboles" dans Cheat Engines. Avec l'exemple de Brian comme ligne directrice et MSDN, vous pouvez facilement étendre ceci 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)
0

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

my $mem = Proc::Memory->new(pid => $$); 
$mem->poke(0x12345678, 'L') = 12;