# C: Zugriff auf Speicher eines anderen Prozesses



## HoPi (5. Juli 2006)

Moinsen,
ich hab gesehen, dass die Jungs von Ocrana (Clan) einen ScoreBot für Pro Evolution Soccer 5 gebastelt haben. Das Programm läuft während des Spiels bei einem Spieler im Hintergrund, überprüft verschiedene Adressen auf Änderungen - und wenn sich dort ein Wert ändert, wird im IRC eine Nachricht ausgegeben. Z.B. ändert sich während des Spiels an Adresse 0x1BF820 der Wert 00 auf 01 und man weiß, dass Spieler 1 ein Tor geschossen hat. Soweit die Theorie.

Ich wollte nun sowas erstmal in klein für das Spiel Blobby Volley anfangen: ein C-Programm läuft in der Eingabeaufforderung und wenn im Spiel jemand einen Punkt macht, kriegt das C-Programm das wegen der Änderung des Wertes an einer bestimmten Adresse mit und gibt eine Statusmeldung aus.
Das Problem: ich kann vom C-Programm aus natürlich nicht einfach so auf den Adressraum des Spiels zugreifen, das unterbindet das OS (in meinem Fall WinXP Pro). Nebenbei: die Adressen sind mir bekannt.

Kennt ihr eine Möglichkeit, wie ich das hinkriege? Bei dem oben angesprochenem PES5-Bot funktioniert es ja schließlich genau so (weiß allerdings nicht, in welcher Sprache der geschrieben wurde).


----------



## RedWing (5. Juli 2006)

Hallo,
gleich vorweg: Ich kenne mich in der Windowsprogrammierung nicht wirklich aus,
aber normalerweise koennen Prozesse nicht einfach auf den Adressraum 
anderer Prozesse zugreifen, da jeder Prozess nur seinen eigenen Adressraum 
kennt.
Die einzigste Moeglichkeit, und das sollte fuer Windows AFAIK genauso gelten,
ist das Stichwort IPC, spezieller shared Memory. Dabei legt ein Prozess
einen shared Memory Bereich an, welcher dann der andere Prozess
der darauf zugreifen moechte den in seinen Adressraum mappen kann.
Wie man das nun unter Windows implementiert k.A. 
Aber schau dir doch mal die Seiten dazu an:
Windows IPC - The Code Project - Threads, Processes & IPC
Shared Memory with IPC with threads - The Code Project - Threads, Processes & IPC

Gruß,

RedWing


----------



## HoPi (5. Juli 2006)

IPC ist mir zwar ein Begriff, aber in diesem Fall kann ich damit wohl nichts anfangen, weil ich einen der Prozesse (in diesem Fall das Spiel) ja nicht einfach so umschreiben kann.


----------



## deepthroat (5. Juli 2006)

Hi.

Unter Windows gibt es die ReadProcessMemory und WriteProcessMemory Funktionen. Alles was du brauchst ist ein Handle von einem Prozess (mit OpenProcess oder CreateProcess zu holen) und die entsprechenden Rechte um auf den Prozess zugreifen zu können.

Google: HOW TO ACCESS THE MEMORY OF A PROCESS (i.e. Game Trainer, Process Patcher etc.)

Gruß


----------



## HoPi (5. Juli 2006)

²deepthroat: geil, sieht genau wie das aus, was ich gesucht hab. Vielen Dank!

//edit
Fein, es IST das, was ich gesucht habe. Danke für die schnelle Hilfe


----------



## HoPi (6. Juli 2006)

Nun hab ich ein anderes Problem... denn die Adresse ändert sich von System zu System. Mal ist es 0x13F8230, mal 0x1BF8230. Suche nach diesem Problem hat ergeben, dass ich mit Thread-Funktionen erstmal den Adressraum des Prozess ermitteln muss, dazu hab ich auch Beispiel-Code gefunden.
Erst hat Dev-Cpp (gcc) gemeckert, weil es OpenThread nicht gefunden hat - hab dann in der windows.h was editiert, damit OpenThread bekannt wird. Nun komme ich aber von dem Wert, den mir GetThreadSelectorEntry da zurückliefert, nicht auf den Adressraum oder finde einen sonstigen Anhaltspunkt. Verwirrend: auf 2 verschiedenen System bekam ich die gleiche Startadresse ausgespuckt (Zufall?).
Kann mir da noch jemand auf die Sprünge helfen?


----------



## deepthroat (7. Juli 2006)

HoPi hat gesagt.:
			
		

> Nun hab ich ein anderes Problem... denn die Adresse ändert sich von System zu System. Mal ist es 0x13F8230, mal 0x1BF8230. Suche nach diesem Problem hat ergeben, dass ich mit Thread-Funktionen erstmal den Adressraum des Prozess ermitteln muss, dazu hab ich auch Beispiel-Code gefunden.
> Erst hat Dev-Cpp (gcc) gemeckert, weil es OpenThread nicht gefunden hat - hab dann in der windows.h was editiert, damit OpenThread bekannt wird.


Das ist generell eine sehr schlechte Idee.

Du mußt die Variable WINVER definieren bevor du windows.h inludierst. Die Variable bestimmt welche Windows API Funktionen vorausgesetzt werden können. Definierst du diese Variable nicht, werden nur Funktionen deklariert die von Windows 95 bzw. WinNT unterstützt werden.
	
	
	



```
#define WINVER 0x0500    /* Windows Version >= Win Me */
#include <windows.h>
```

Gruß


----------



## HoPi (7. Juli 2006)

deepthroat hat gesagt.:
			
		

> Das ist generell eine sehr schlechte Idee.


Das war mir auch klar 



> Du mußt die Variable WINVER definieren bevor du windows.h inludierst. [...]



Danke für den Hinweis - aber das ändert nichts an der Tatsache, dass ich mit diesem SelectorEntry Probleme habe. Hier mal der Code (inkl. einiger Test-Ausgaben zum Anschauen):


```
#define WINVER 0x0500
#include <windows.h>
#include <ddk/ntapi.h>
#include <winnt.h>
#include <winbase.h>
#include <windef.h>
#include <stdio.h>

void error(const char msg[]) {
   printf("%s\n", msg);
   exit(-1);
}

void main(void) {
   /* GetThreadContext */
   CONTEXT Context;
   LDT_ENTRY SelEntry;
   HANDLE hThread;
   
   /* FindWindowA - check if process is already running, result is window handle */
   LPCTSTR lpClassName=NULL;
   LPCTSTR lpWindowName="Blobby Volley";
     
   /* GetWindowThreadProcessID - get ID from window handle */
   HWND hWnd;
   LPDWORD lpdwProcessId;
   
   /* OpenProcess */
   DWORD fdwAccess=PROCESS_VM_READ;
   BOOL fInherit=FALSE;
   DWORD IDProcess;
   
   /* ReadProcessMemory */
   HANDLE hProcess;
//   LPCVOID lpBaseAddress=0x1BF8280; // 0x13F8280;
   LPVOID lpBuffer;
   DWORD cbRead=1;
   
   CHAR vBuf[1], next[1];   
   FILE *fp;
   
   printf("lpBaseAddress: %d\n", 0x1BF8280);
   printf("0x1B...: %d, 0x13...: %d\n", 0x1BF8280, 0x13F8280);

   if((hWnd = FindWindowA(lpClassName, lpWindowName))==NULL)
      error("error: FindWindowA");
   printf("hWnd: %d\n", hWnd);

   GetWindowThreadProcessId(hWnd, &lpdwProcessId); /* sets lpdwProcessId */
   printf("lpdwProcessId: %d\n", lpdwProcessId);
   
   printf("\n\nThread-Kram\n");   
   hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, lpdwProcessId);
   Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
   GetThreadContext(hThread, &Context);
   GetThreadSelectorEntry(hThread, Context.SegFs, &SelEntry);
   DWORD dwFSBase = (SelEntry.HighWord.Bits.BaseHi << 24) |
                    (SelEntry.HighWord.Bits.BaseMid << 16) |
                     SelEntry.BaseLow;
   printf("dwFSBase: %x (%d)\n", dwFSBase);
   
   if((hProcess = OpenProcess(fdwAccess, fInherit, lpdwProcessId)) == NULL)
      error("error: OpenProcess");
   printf("hProcess: %d\n", hProcess);
   
      if(ReadProcessMemory(hProcess, 0x13F8280, vBuf, cbRead, 0)) {
         /* auskommentiert, unwichtig */
      } else
         error("error: ReadProcessMemory");

   CloseHandle(hProcess);
}
```

0x1B... bzw. 0x13 sind die beiden verschiedenen Adressen, die ich bei 2 System kriege, deswegen tauchen die im Code auf.


----------



## deepthroat (7. Juli 2006)

Ist die Funktion GetThreadSelectorEntry überhaupt erfolgreich? (=> Rückgabewert prüfen)

Du hast in dem printf Formatstring 2 Formatdirektiven drin. Da müssen dann auch in der Parameterliste genau 2 Argumente nach dem Formatstring übergeben werden.

Gruß


----------



## HoPi (7. Juli 2006)

deepthroat hat gesagt.:
			
		

> Ist die Funktion GetThreadSelectorEntry überhaupt erfolgreich? (=> Rückgabewert prüfen)


Jup, ist sie. Hier mal die Ausgabe des Programms:


```
lpBaseAddress: 29328000
0x1B...: 29328000, 0x13...: 20939392
hWnd: 72089848
lpdwProcessId: 1496


Thread-Kram
dwFSBase: 27c92
hProcess: 2004
```



> Du hast in dem printf Formatstring 2 Formatdirektiven drin. Da müssen dann auch in der Parameterliste genau 2 Argumente nach dem Formatstring übergeben werden.


Stimmt, hab's im Quellcode aber richtig. Hab hier beim Editieren des Codes nur Mist gebaut.

//edit
Gerade gesehen, dass ich keine Ausgabe von GetThreadSelectorEntry drin hab. Ist vom Typ BOOL und liefert 0 zurück.... ich schau's mir nachher nochmal in Ruhe an.


----------

