Speicheradresse auslesen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
anymagical
User
Beiträge: 33
Registriert: Montag 2. April 2012, 15:34

Servus,

ich habe vor einen Trainer für Solitär zu schreiben :D
Laut eines MemoryViewer weiß ich das in ADDRESS1 592978 steht. Er schreibt garnichts in ADDRESS2, obwohl er den Wert aus ADDRESS1 in ADDRESS2 schreiben "soll".

Code: Alles auswählen

# -*- coding: cp1252 -*-
import ctypes, win32ui, win32process ,win32api

PROCESS_ALL_ACCESS = 0x1F0FFF
HWND = win32ui.FindWindow(None,"Solitär").GetSafeHwnd()
PID = win32process.GetWindowThreadProcessId(HWND)[1]
PROCESS = win32api.OpenProcess(PROCESS_ALL_ACCESS,0,PID)

rPM = ctypes.windll.kernel32.ReadProcessMemory
wPM = ctypes.windll.kernel32.WriteProcessMemory

ADDRESS1 = 0x00E97074
ADDRESS2 = 0
rPM(PROCESS.handle,ADDRESS1,ADDRESS2,4,0)
print(ADDRESS2)#gibt 0
Zuletzt geändert von Anonymous am Mittwoch 3. Oktober 2012, 12:57, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
BlackJack

@anymagical: Du musst als Zielargument einen Zeiger auf den Speicherbereich angeben wohin die Bytes geschrieben werden sollen. Ein Zeiger ist eine Zahl, nämlich die Adresse im Speicher. Du versuchst da also was an Adresse 0 zu schreiben. Ich bin ein wenig überrascht, dass Dir dabei der Prozess nicht einfach mit einer Speicherzugriffsverletzung abschmiert.

Du müsstest erst einmal Speicher bereitstellen, in Python in Form eines `ctypes`-Objektes, das diesen Speicher „wrapped” und dann einen Zeiger auf *den* Speicher übergeben, also auch hier in Form eines `ctypes`-Objekte, dass einen Zeiger als Python-Objekt repräsentiert.
anymagical
User
Beiträge: 33
Registriert: Montag 2. April 2012, 15:34

Hallo blackjack,

mich wundert das ich weder True noch False als rückmeldung von ReadProcessMemory erhalte. Als würde es garnicht ausgeführt werden.

ADDRESS2 = ctypes.c_char_p("target") damit müsste ich doch dann einen Speicherplatz erstellt haben

Code: Alles auswählen

import ctypes, win32ui, win32process ,win32api

PROCESS_ALL_ACCESS = 0x1F0FFF
HWND = win32ui.FindWindow(None,"Solitär").GetSafeHwnd()
PID = win32process.GetWindowThreadProcessId(HWND)[1]
print(PID)
PROCESS = win32api.OpenProcess(PROCESS_ALL_ACCESS,0,PID).handle

rPM = ctypes.windll.kernel32.ReadProcessMemory
wPM = ctypes.windll.kernel32.WriteProcessMemory

ADDRESS1 = 0x00E97074
ADDRESS2 = ctypes.c_char_p("Target")
pi = ctypes.pointer(ADDRESS2)
rPM(PROCESS,ADDRESS1,ADDRESS2,4,0) #da spielts keine Rolle ob pi oder ADDRESS2 ausgabe bleibt gleich...
print(ADDRESS2)

Die Ausgabe in der cmd lautet

4052 #stimmt
# hier müsste noch eine 1 oder 0 erscheinen...
c_char_p('Target')

//
Habe mal ans Ende einen GetlastError gesetzt und erhalte den Code 6

"Invalid Handle"
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Geraten: Hast du die benötigten Rechte? Evt. mal als "Administrator" starten.
the more they change the more they stay the same
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Der Typ sieht doch auch falsch aus. Du übergibst gerade einen Pointer auf einen Char-Pointer. Du willst aber einen Pointer auf irgend etwas, was vier Bytes groß ist. Wie kommst du eigentlich auf die 4? Die Signatur von ReadProcessMemory ist doch gut beschrieben, die musst du nur noch mittels ctypes umsetzen.
Das Leben ist wie ein Tennisball.
anymagical
User
Beiträge: 33
Registriert: Montag 2. April 2012, 15:34

Der Pointer wird ja nicht einmal benutzt. Ich kam auf die 4 weil im Memoryviewer die größe mit 4bytes angegeben wurde. Ob jetzt 4,32 oder 64 die größe ist ändert nichts daran das ich einen "Wrong Handle" Error bekomme.

Natürlich habe ich die benötigten Rechte, hier am Windowssystem wohl mehr als ich benötige ;D

//
ich habs jetzt hinbekommen das "Only part of a ReadProcessMemory or WriteProcessMemory request was completed." erhalte
BlackJack

@anymagical: Woher weisst Du was der Aufruf zurück gibt? In dem gezeigten Quelltext machst Du mit dem Rückgabewert ja nichts. Warum denkst Du dass da eine 1 oder 0 erscheinen sollte?

Bist Du sicher das `OpenProcess()` überhaupt funktioniert hat? Ein Nachteil von Low-Level-Programmierung auf C-Ebene ist ja, dass es keine netten Ausnahmen gibt wenn etwas schief läuft, sondern man immer sorgfältig an jeder Stelle selbst auf Fehler prüfen muss.
anymagical
User
Beiträge: 33
Registriert: Montag 2. April 2012, 15:34

An der Adresse 0x00E97074 müsste der Wert für die nächste Adresse stehen wenn ich das richtig verstanden habe.

Ich habe im Memoryviewer eine Adresse für einen Wert gefunden und habe diese dann zu ihrem Basepointer zurückverfolgt. Also müsste doch in in 0x00E97074 (das ist der Basepointer) der Wert für die nächste Adresse beinhalten.

Wie ich darauf komme das mir ReadProcessMemory eine Rückgabe liefern sollte?
If the function succeeds, the return value is nonzero.
If the function fails, the return value is 0 (zero).
...und das tat sie normalerweise auch immer. In der Kommandozeile von Python macht sie es sogar noch.

Sicher ob OpenProcess funktioniert hat bin ich nicht, ich gehe davon aus das ich einen Error erhalten hätte wenn dies nicht der Fall gewesen wäre.
Ich denke mal ein zuverlässiger Hinweiß ist das TerminateProcess(PROCESS.handle,0) nach dem OpenProcess() funktioniert.

Ich hab in MV die Adresse für die Punkte gefunden zu ihrem Basepointer zurückverfolgt über 2 Addressen. Habe dabei noch 2 offsets gehabt. Jetzt möchte ich den Wert aus der Adresse lesen den Offset addieren ... und am ende dann eine beliebe Punktzahl an die Zieladresse schreiben.
BlackJack

@anymagical: Die Funktion gibt natürlich einen Wert zurück, aber wie kommst Du darauf, dass etwas *ausgegeben* werden sollte wenn *Du* das nicht *tust*‽ In der Kommandozeile wird 6 ausgegeben wenn Du einfach 5 + 1 eintippst, aber Du würdest doch hoffentlich nicht erwarten, dass das auch passiert wenn Du einfach so 5 + 1 irgendwo in ein Programm schreibst. Wo sollte Python denn dann die Grenze ziehen was auf magische Weise ausgegeben wird und was nicht? Und wofür wäre dann ``print`` gut, wenn einfach so alle Rückgabewerte/Ergebnisse von Ausdrücken „automagisch” ausgegeben würden?

Was ist „die nächste Adresse”, Memoryviewer, ein Basepointer in diesem Kontext?

Was heisst einen „Error erhalten”? Auf C-Ebene liefert `OpenProcess()` den Wert ``null`` zurück wenn der Aufruf nicht geklappt hat. Darauf muss man dann prüfen. Wandelt `win32api` das automatisch in eine Ausnahme um?
anymagical
User
Beiträge: 33
Registriert: Montag 2. April 2012, 15:34

0x87ED75F(Basepointer) enthält 98455 (hex: 0x64FE84[nächste Adresse])
0x64FE84 enthält 98745 (hex: 0x913C5A5)
0x913C5A5 enthält die Punkteanzahl im Spiel

Der Basepointer ist die Adresse auf welche nicht von einer anderen Adresse gezeigt wird.

und das macht mir der Memoryviewer sichtbar.

Okay das mit den Rückgabewerten war töricht von mir. Also sollte meine Frage lauten wie Prüfe ich ob meine aufgerufen Funktionen erfolgreich ausgeführt worden sind.

Bisher war das meine Vorstellung von einem "Error erhalten":

Code: Alles auswählen

win32api.OpenProcess(PROCESS_ALL_ACCESS,False,8524)
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
error: (87, 'OpenProcess', 'Falscher Parameter.')
BlackJack

@anymagical: Dann wandelt `win32api` Fehlerrückgabewerte also in Ausnahmen um.
anymagical
User
Beiträge: 33
Registriert: Montag 2. April 2012, 15:34

Der Fehler wurde aber simuliert und hat nichts mit meinem aufgerufen Programm zu tun!
Ich habe statt der PID von Solitär eine eigene beliebige hingeschriebenund dadurch diesen Error erhalten.

Da ich aber einen Error ausgeben bekommen habe, kann ich davon ausgehen das OpenProcess() erfolgreich ist.
Benutzeravatar
sparrow
User
Beiträge: 4501
Registriert: Freitag 17. April 2009, 10:28

Hast du dir das mal hier angeschaut?
Die Importe und die Verwendung von OpenProcess scheinen sich von deinem zu unterscheiden.

http://stackoverflow.com/questions/1794 ... in-windows


Edit: Oh, und der 5. Parameter bei ReadProcessMemory scheint ebenfalls falsch zu sein.
anymagical
User
Beiträge: 33
Registriert: Montag 2. April 2012, 15:34

@ sparrow

Was genau unterscheidet den sein OpenProcess() von meinem? Ich erkenne einen einzigen Unterschied und der wäre das ich eine 0 statt False benutze. Das ich statt über ctypes über die winapi OpenProcess() hat bis auf das .handle in meinem Code keine weitere Auswirkungen.

Ob ich als 5. Parameter 0 angebe und dieser ignoriert wird, oder ctypes.byref() verwende ändert nichts an der Ausgabe. Auf seinen Code bin ich übrigens gestoßen als ich das weite des Internets durchsucht habe bevor ich hier gepostet habe 8)

Gruß
Anymagical
Benutzeravatar
sparrow
User
Beiträge: 4501
Registriert: Freitag 17. April 2009, 10:28

Hast du das mit dem Handle schon einmal mit der verlinkten Weise versucht? Du hast ja oben geschrieben, das du "Wrong Handle" als Fehler bekommen hast.

Bist du dir sicher, dass der 5. Parameter ignoriert wird, wenn er "0" ist? In der API steht nämlich, dass er nur dann ignoriert wird, wenn er NULL ist, was etwas komplett anderes ist.

Hast du den Code aus dem Link schonmal ausprobiert? Vielleicht liefert dir dein Aufruf wirklich ein falsches Handle, oder 0 und "False" sind genauso unterschiedlich wie "0" und NULL?
anymagical
User
Beiträge: 33
Registriert: Montag 2. April 2012, 15:34

Ja habe ich schon probiert. Wenn ich es verlinke bekomme ich den gleichen Error: 299

Ob 0 oder 0L spielt auch hier keine Rolle es wird automatisch in einen Nullzeiger umgewandelt.

Ja ich hatte den Code aus dem Link probiert. Gleiches spiel.

und das 0 und False etwas unterschiedliches in meinem Programm sind möchte ich mit etwas Python erklären:

Code: Alles auswählen

0 == False
True
//
Win7 32bit, Python32

und den Wrong Handle Error erhalte ich wenn das .handle an die falsche stelle positioniere!
Zuletzt geändert von anymagical am Donnerstag 4. Oktober 2012, 09:46, insgesamt 1-mal geändert.
BlackJack

@sparrow: NULL kann theoretisch etwas anderes als 0 sein, ist es aber auf den meisten Systemen nicht.

Ich würde trotzdem `None` für ``NULL``, und `True` oder `False` statt 1 oder 0 verwenden, auch wenn es keinen Unterschied für den Rechner macht, so macht es einem menschlichem Leser verständlicher was dort erwartet und übergeben wird. Das es sich eben nicht um beliebige Zahlenwerte handelt, sondern eben um einen NULL-Pointer/„Nichts” beziehungsweise Wahrheitswerte.
anymagical
User
Beiträge: 33
Registriert: Montag 2. April 2012, 15:34

In der PythonWin idle ausgeführt :shock:
Natürlich findet er das "Solitär" fenster auf diese Weise nicht wegen des Ä

Code: Alles auswählen

import ctypes, struct, win32api, win32process
>>> import win32ui
>>> PROCESS_ALL_ACCESS = 0x1F0FFF
>>> HWND = win32ui.FindWindow(None,"Soldat").GetSafeHwnd()
>>> PID = win32process.GetWindowThreadProcessId(HWND)[1]
>>> PROCESS = win32api.OpenProcess(PROCESS_ALL_ACCESS, 0, PID)
>>> readProcessMemory = ctypes.windll.kernel32.ReadProcessMemory
>>> STATUSBAR_TEXT = 0x0076D928
>>> status_text = ctypes.create_string_buffer(64)
>>> readProcessMemory(PROCESS.handle,STATUSBAR_TEXT,status_text,64,0)
1
>>> 
und das gleiche für Solitär! Lediglich die PID habe ich manuell zugewiesen.

Code: Alles auswählen

PID = 2136
>>> PROCESS = win32api.OpenProcess(PROCESS_ALL_ACCESS, 0, PID)
>>> readProcessMemory = ctypes.windll.kernel32.ReadProcessMemory
>>> STATUSBAR_TEXT = 0x0076D928
>>> status_text = ctypes.create_string_buffer(64)
>>> readProcessMemory(PROCESS.handle,STATUSBAR_TEXT,status_text,64,0)
0
Dieser Code:

Code: Alles auswählen

import ctypes, win32ui, win32process 

PROCESS_ALL_ACCESS = 0x1F0FFF
HWND = win32ui.FindWindow(None,"Soldat").GetSafeHwnd()
PID = win32process.GetWindowThreadProcessId(HWND)[1]
PROCESS = ctypes.windll.kernel32.OpenProcess(PROCESS_ALL_ACCESS,False,PID)

rPM = ctypes.windll.kernel32.ReadProcessMemory
wPM = ctypes.windll.kernel32.WriteProcessMemory

ADDRESS1 = 0x00B97D5C
ADDRESS2 = ctypes.create_string_buffer(64)
rPM(PROCESS,ADDRESS1,ADDRESS2,64,None)
print(ADDRESS2)
input()
Gibt diese Ausgabe: Der Wert der Adresse aus ADDRESS1 beträgt 31 laut des Memoryviewers. Alt +31 = ▼ :)
WIe wandel ich diesen Zeichen in eine Hexzahl oder Integer um? Warum bekomme ich überhaupt ein Ascii zeichen statt des Hexcodes ausgegeben?

Warum das ganze mit SOlitär nicht funktioniert ist mir ein Rätsel!
BlackJack

@anymagical: Das ist ganz sicher kein ASCII-Zeichen, eher CP437. Das wird ausgegeben weil Du da eine Zeichenkette hast. Wenn Du eine Zahl haben möchtest musst Du eben den entsprechenden Typen mit der entsprechenden Grösse und der entsprechenden Anzahl von Bytes beim Kopieren nehmen.
anymagical
User
Beiträge: 33
Registriert: Montag 2. April 2012, 15:34

Wie kann ich den dem Programm mitteilen welchen Typen er kopieren soll? Die größe verändere ich ja dann einfach in create_string_buffer und in der rPM auf 4 bytes statt der bisherigen 64.

Wenn ich statt des create_string_buffer ein c_ulong() nehme scheint er mir nichts an die Addresse zu schreiben.

//
Okay habe jetzt
ADDRESS2 = ctypes.c_ulong(4) #denke mal größe wäre dann 4bytes
Apointer = ctypes.pointer(ADDRESS2)

Ist zwar "noch" nicht das Spiel Solitär doch das ist schon einmal ein kleiner Erfolg, wenn dann WriteProcessMemory wieder solche Probleme bereitet werde ich Windows verbannen :evil: :D

// Noch einer:

Ich habe jetzt meinen ersten Trainer geschrieben, welcher lediglich eine Anzeige in einem Spiel verändert und dadurch etwas die Statistik manipuliert.

Vielen Dank an alle Hinweise, Anregungen, Hilfen und sonstige Einwürfe!

Code: Alles auswählen

import ctypes, win32ui, win32process 

PROCESS_ALL_ACCESS = 0x1F0FFF
HWND = win32ui.FindWindow(None,"Soldat").GetSafeHwnd()
PID = win32process.GetWindowThreadProcessId(HWND)[1]
PROCESS = ctypes.windll.kernel32.OpenProcess(PROCESS_ALL_ACCESS,False,PID)

rPM = ctypes.windll.kernel32.ReadProcessMemory
wPM = ctypes.windll.kernel32.WriteProcessMemory

ADDRESS1 = 0x00B97D5C
ADDRESS2 = ctypes.c_ulong(4)
Apointer = ctypes.pointer(ADDRESS2)
rPM(PROCESS,ADDRESS1,Apointer,4,None)
print(ADDRESS2)
new = ctypes.c_ulong(55)
Bpointer = ctypes.pointer(new)
wPM(PROCESS,ADDRESS1,Bpointer,4,None)
print(ADDRESS2)
Was mich dennoch interessieren würde ist wieso das ganze nicht mit Solitär funktioniert, falls da jemand noch die ein oder andere Idee hat würde ich sie gerne erfahren 8)
Zuletzt geändert von anymagical am Freitag 5. Oktober 2012, 13:19, insgesamt 2-mal geändert.
Antworten