Home of Gamehacking - Archiv

Normale Version: Kleine Hilfe zu WriteProcessMemory gesucht...
Sie sehen gerade eine vereinfachte Darstellung unserer Inhalte. Normale Ansicht mit richtiger Formatierung.
Seiten: 1 2 3 4 5 6 7
(06.09.2012, 17:22)sILeNt heLLsCrEAm schrieb: [ -> ]Also im Bezug auf diese Aussage frage ich mich ernsthaft wie Du es geschafft hast einen Trainer zu schreiben?!
In deinem Trainer nutzt Du doch auch die WriteProcess API. Damit lassen sich nicht nur einfache Adressen beschreiben...

So, da sind wir also an einer Stelle angekommen, von der ich keine Ahnung habe und zu der ich sehr gerne Hilfe annehme, wenn du mir da weiterhelfen kannst, nur zu Wink Wie ich schon sagte, habe ich keine Ahnung wie man mit Delphi eine Codecave bastelt und in deinen geposteten Tutorials stand dazu auch nicht wirklich was drin. Aber ich weiss zumindest jetzt, was damit gemeint ist.

(06.09.2012, 17:22)sILeNt heLLsCrEAm schrieb: [ -> ]Und wie willst Du das bei einem Spiel lösen wo Pointer nicht so ohne weiteres möglich sind???
Eine Adresse auslesen kann man auch durch eine Codecave. Man filtert die Adresse die man sucht und schreibt diese in eine "bestimmten" Speicherzelle. Und diese Speicherzelle wiederrum kann man mit dem Trainer auslesen. Also nichts mit extra Fenster in ASM Bauweise...

Zu diesem Thema kann ich nicht viel sagen, weil ich bisher einen solchen Fall noch nicht hatte, bzw. nur teilweise wo ich manche Pointer gefunden habe und andere wiederum nicht.
Meine Lösung: Ich habs aufgegeben, weil ich keine Ahnung hatte, wie ichs lösen kann...

Zu:
Zitat:Also im Bezug auf diese Aussage frage ich mich ernsthaft wie Du es geschafft hast einen Trainer zu schreiben?!
Ich weiss jetzt nicht genau, ob ich das als Angriff oder als Kompliment werten soll... Vielleicht kannst du dich dazu ja nochmal äussern...

Nochmal ein wenig Hintergrundwissen zu mir, bzw. meiner Erfahrung mit Delphi...
Ich habe Delphi weder in der Schule gehabt, noch sonstwie von irgendjemandem beigebracht bekommen, alles was ich mit Delphi mache, machen kann, habe ich mir selber beigebracht.
Angefangen, mich überhaupt mit Delphi auseinander zu setzen habe ich am:
01.07.2012
und zwar mit den Grundlagen...

Ich habe auch noch nie ernsthaft versucht, irgendwelche Games zu hacken oder mich sonstwie mit dieser ganzen Materie auseinandergesetzt. Ich habe mich da jetzt erst in letzter Zeit ein wenig reingelesen, viele Tutorials angeschaut und nachgebaut usw.

Pointertutorials findet man ja auch noch halbwegs gute im Netz, daher habe ich auch diesen Trainer zusammenbekommen, aber da hört es dann so langsam auch auf, zumindest, was meine bisherigen Quellen betrifft.

Ich bin über jede freundliche Hilfe wirklich dankbar und möchte anschliessend auch gerne etwas dafür zurückgeben, aber es ist gerade in diesem Bereich verdammt schwierig (zumindest für mich, weiss nicht ob es allgemein so ist) überhaupt Hilfe zu finden.

In dem Sinne hoffe ich weiterhin auf ein wenig Hilfestellung und vielleicht kann ich dann später auch mal dem ein oder anderen helfen, wer weiss.

LG Darius83

Hey,
also CodeCaves sind im Prinzip recht einfach.

Ich werde dir das mal am Beispiel meines Health Cheats für Unepic versuchen zu erklären.
Zunächst findet man die Healthadresse und findet dann via Debugger heraus, welche Befehle auch die Adresse zugreifen (Cheat Engine hat sehr elegante Lösungen dafür).
Also habe ich jetzt z.B folgenden Befehl:

Code:
Addresse        |  Bytes          |         Opcode
unepic.exe+12FC6|- D8 98 8C030000 |      - fcomp dword ptr [eax+0000038C]


Du kannt per WriteProcessMemory die Bytes verändern. Jede Reihenfolge von Bytes hat einen bestimmten Befehl zur Folge.
Würde an der oben genannten Adresse z.B lea eax,[ecx-0000E224] stehen, so hättest du als Bytes folgende Sequenz: 8D 81 DC1DFFFF
Ich hoffe bis hierhin ist alles klar?!

Okay, nun kommen wir zum eigentlichen Thema, den Caves.
Als erstes brauchen wir freien Speicher (Cheat Engine hat wieder elegante Lösungen dafür). Ich alloziiere meinen immer dynamisch (siehe meine Funktion im C++ Forum), aber um es hier zu verdeutlichen nehmen wir mal an, ich hätte freien Speicher an folgender Adresse gefunden: 00400288 (unepic.exe+288)
Hier kann ich meinen eigenen Code schreiben, also z.B:

Code:
pushfd //flags speichern
cmp [eax+424], 1 //wird die Healthadresse (Struktur) des Spielers gerade verwendet?
jne originalcode //wenn nicht -->originalcode ausführen
mov dword ptr [eax+38C], (float)99999 //wenn Spieler, dann "unendlich" viel Hp in die Healthadresse

originalcode:
popfd //flags wiederherstellen
fcomp dword ptr [eax+0000038C]

Die Bytes dieses Codes sind im Folgenden fett markiert:

unepic.exe+288 - 9C - pushfd
unepic.exe+289 - 83 B8 24040000 01 - cmp dword ptr [eax+00000424],01
unepic.exe+290 - 75 0A - jne unepic.exe+29C
unepic.exe+292 - C7 80 8C030000 804FC347 - mov [eax+0000038C],47C34F80
unepic.exe+29C - 9D - popfd
unepic.exe+29D - D8 98 8C030000 - fcomp dword ptr [eax+0000038C]

Nun überschreiben wir an unserer Ausgangsadresse (unepic.exe+12FC6) den fcomp Befehl mit einem Jump Befehl zu unserer Cave (einfach die Bytes per WriteProcessMemory schreiben)

unepic.exe+12FC6 - E9 BDD2FEFF - jmp unepic.exe+288

Da der Ausgangsbefehl 6 Bytes groß ist (D8 98 8C030000) und unserer Jump Befehl nur 5 (E9 BDD2FEFF), müssen wir noch den Nop Befehl (90) hinter unseren Jump schreiben.
Nun am Ende unserer Cave nur noch einen Sprung zurück zu 00412FCC (unepic.exe+12FCC), wo der eigentliche Code weitergeht und die Magie ist vollbracht.

(06.09.2012, 21:19)darius83 schrieb: [ -> ]Wie ich schon sagte, habe ich keine Ahnung wie man mit Delphi eine Codecave bastelt und in deinen geposteten Tutorials stand dazu auch nicht wirklich was drin. Aber ich weiss zumindest jetzt, was damit gemeint ist.
Die, bzw. eine Codecave wird ja im eigentlichen Sinne weder mit Delphi oder sonst irgendeiner Programmiersprache geschrieben. Das was durch Delphi und jeder anderen Programmiersprache geschrieben wird sind die entsprechenden Bytes der Codecave und bzw. oder der Sprung zur Codecave. In Delphi kann man das z.B. als Array an die WriteProcess API übergeben.
Das bzw. wie so eine Codecave geschrieben ist halt am einfachsten mit Cheat Engine zu realisieren. Denn damit sucht man sich die entsprechenden Adressen raus, schreibt die Codecave danach wie sie funktionieren soll und schließlich hat man die komplette Bytefolge (das Array) was letzenendlich durch die WriteProcess API geschrieben werden kann. Und das wiederrum kann man eben mit Delphi, VB, C++ etc...
Und da kann ich dir eben das Tutorial von Acubra wärmstens ans Herz legen. Diesem Tutorial liegt auch eine einfache TrainMe.exe bei damit das auch jeder nachvollziehen kann.

Du musst Dir das vielleicht so vorstellen wie Du das in deinem Trainer machst. Dein Trainer schreibt zwar nur 4 Bytes, also den Wert des Geldes, aber so wird auch eine Codecave oder im eigentlichen Sinne die Bytefolge in den Spieleprocess injeziert. Nur eben das die Bytefolge nicht nur 4 Zeichen groß ist. Die Codecave, wie sie im Tutorial von Acubra zu sehen ist, ist insgesamt 15 Bytes groß wenn man mal den NOP am Ende nicht mitzählt.


(06.09.2012, 21:19)darius83 schrieb: [ -> ]
(06.09.2012, 17:22)sILeNt heLLsCrEAm schrieb: [ -> ]Also im Bezug auf diese Aussage frage ich mich ernsthaft wie Du es geschafft hast einen Trainer zu schreiben?!
Ich weiss jetzt nicht genau, ob ich das als Angriff oder als Kompliment werten soll... Vielleicht kannst du dich dazu ja nochmal äussern...
Die Frage war durchaus ernst gemeint und weder als Angriff noch als Kompliment zu verstehen.
Immerhin ist die Frage durchaus berechtigt... Dein ursprünglicher Sourcecode sieht schon irgendwie nach Flickschusterei aus, wenn ich das mal so ausdrücken darf.
Z.B...
[code=Delphi]procedure TForm1.Button1Click(Sender: TObject);
var
Data: Integer;
begin
Data := 4;
try
ReadProcessMemory(Pidhandle, Pointer(Address), @lBuf, Data, Written);
ReadProcessMemory(Pidhandle, Pointer(lBuf), @lBuf, Data, Written);
ReadProcessMemory(Pidhandle, Pointer(lBuf), @lBuf, Data, Written);
[/code]

Warum deklarierst Du Data erst als Integer und weist diesem dann den Wert 4 zu? Schreib doch z.B. gleich...
[code=Delphi]ReadProcessMemory(Pidhandle, Pointer(Address), @lBuf, 4, Written);
ReadProcessMemory(Pidhandle, Pointer(lBuf), @lBuf, 4, Written);
ReadProcessMemory(Pidhandle, Pointer(lBuf), @lBuf, 4, Written);[/code]


In diesem Sinne...
Wer nach Hilfe fragt bekommt sie auch...
Übrigens - Nachträglich noch herzlich Willkommen hier bei uns im Forum. Cool

grEEtZ sILeNt heLLsCrEAm
(07.09.2012, 01:23)sILeNt heLLsCrEAm schrieb: [ -> ]Die Frage war durchaus ernst gemeint und weder als Angriff noch als Kompliment zu verstehen.
Immerhin ist die Frage durchaus berechtigt... Dein ursprünglicher Sourcecode sieht schon irgendwie nach Flickschusterei aus, wenn ich das mal so ausdrücken darf.
Z.B...
[code=Delphi]procedure TForm1.Button1Click(Sender: TObject);
var
Data: Integer;
begin
Data := 4;
try
ReadProcessMemory(Pidhandle, Pointer(Address), @lBuf, Data, Written);
ReadProcessMemory(Pidhandle, Pointer(lBuf), @lBuf, Data, Written);
ReadProcessMemory(Pidhandle, Pointer(lBuf), @lBuf, Data, Written);
[/code]

Warum deklarierst Du Data erst als Integer und weist diesem dann den Wert 4 zu? Schreib doch z.B. gleich...
[code=Delphi]ReadProcessMemory(Pidhandle, Pointer(Address), @lBuf, 4, Written);
ReadProcessMemory(Pidhandle, Pointer(lBuf), @lBuf, 4, Written);
ReadProcessMemory(Pidhandle, Pointer(lBuf), @lBuf, 4, Written);[/code]


In diesem Sinne...
Wer nach Hilfe fragt bekommt sie auch...
Übrigens - Nachträglich noch herzlich Willkommen hier bei uns im Forum. Cool

grEEtZ sILeNt heLLsCrEAm

Soo also erstmal danke an euch beiden,
Acubra und sILeNt heLLsCrEAm,
für die schönen Erklärungen, ich denke, ich habe das mit den Codecaves und wie man sie macht jetzt verstanden, aber ich glaub ich muss damit jetzt erstmal ein wenig rumprobieren, um das ganze auch umsetzen zu können...
Acubras Tutorial hatte ich mir übrigens schon angeschaut, bevor du den Link dazu gepostet hattest und mit CE hab ichs auch hinbekommen.
Ich hatte nur keine Ahnung, wie man das in Delphi umsetzt.
Muss ich nur noch irgendwo Infos finden, wie man von den Befehlen in ASM auf die entsprechend zu schreibenden Bytes kommt. Zeigt CE die direkt an? Hab da noch nicht so drauf geachtet. bzw nicht nachgeschaut, weil ich damit noch nichts anfangen konnte Wink

Zu deiner Aussage mit dem zusammenschustern geb ich dir vollkommen recht, ich hab mir den Code für das beschreiben einer Adresse aus einem Tutorial rausgesucht und damit rumprobiert. Hab mir mit CE dann nen Pointer rausgesucht und versucht diesen zu beschreiben.
Dazu habe ich mir den Code angeschaut, mir überlegt, wie ich die Offsets darin ubnterbringe(Der Code war im Tutorial nur zum beschreiben einer konkreten Adresse) und den Code ein wenig umgebaut.
Dann bin ich auf den Gamecrash gestoßen und hab hier nach Hilfe gefragt. Deswegen sah der Code da auch noch so nach Flickwerk aus und auch das Data stammt noch aus dem Tutorial...
Aber rein theoretisch finde ich das mit dem Data als Var schon garnicht so verkehrt, weil ich den Code so einfacher in eine Funktion auslagern und ggf erweitern kann... Ich habe bisher nur ein Data von 4 gebraucht, deswegen hab ich den Wert auch fest gesetzt, aber ich könnte ja jetzt in dem Code aus meinem späteren Post das Data:=4 entfernen und Data als Parameter übergeben lassen und die Funktion so auch für variable Werte verwenden.
Ist halt nur noch nicht umgesetzt XD
Hoffe, du verstehst es jetzt, wie ich den Trainer zusammengebastelt bekommen habe. Ich denke mal, wenn ich noch ein wenig mehr Erfahrung habe, wirds auch besser werden... Zumindest hoffe ich es Wink

So dann fällt mir noch ne Frage ein, und zwar zu
ReadProcessMemory(Pidhandle, Pointer(Result), @Result, Data, Written);
bzw auch bei WriteProcessMemory
da habe ich ja die Parameter Data und Written...
Ich habe noch nicht ganz die Bedeutung der beiden Parameter verstanden. Nur das der eine der beiden die Anzahl der zu lesenden/schreibenden Bytes angibt. Und die englische Erklärung in der msdn ist auch recht knapp. Könnte mir dazu mal jemand was erzählen? Wäre echt nice.

LG Darius83
Tag,

MSDN schrieb:BOOL WINAPI ReadProcessMemory(
_In_ HANDLE hProcess,
_In_ LPCVOID lpBaseAddress,
_Out_ LPVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesRead
);

Der vorletzte Parameter (nSize) gibt die Menge der Bytes an die du Lesen willst.
MSDN schrieb:The number of bytes to be read from the specified process.
Du willst ein Integer auslesen, was 4 Bytes sind - also gibst du 4 an.


Der letzte Parameter (lpNumberOfBytesRead) gibt die Menge der Bytes an, welche in lpBuffer geschrieben werden. Normalerweiße brauchst du diesen Parameter nicht und setzt ihn auf 0.
MSDN schrieb:A pointer to a variable that receives the number of bytes transferred into the specified buffer. If lpNumberOfBytesRead is NULL, the parameter is ignored.

Bei WPM genau dasselbe, nur eben mit der Menge an Bytes die geschrieben werden sollen und dann die Menge der Bytes die tatsächlich in den Prozess geschrieben wurden.


~Mydayyy
Besten Dank, bin ich wieder ein Stück schlauer geworden...
Jetzt müsste ich nur noch ne Methode finden, diese blöden gesuchten Adressen einfach und schnell zu finden XD Anschliessend die Pointer dahin zu finden, ist mitunter leichter als die Adresse selbst zu finden :/

LG Darius83
(07.09.2012, 20:25)darius83 schrieb: [ -> ]Zeigt CE die direkt an? Hab da noch nicht so drauf geachtet. bzw nicht nachgeschaut, weil ich damit noch nichts anfangen konnte Wink
Diese zeigt in der Regel jeder Debugger/Dissassembler an. So auch Cheat Engine...

(07.09.2012, 20:25)darius83 schrieb: [ -> ]Aber rein theoretisch finde ich das mit dem Data als Var schon garnicht so verkehrt, weil ich den Code so einfacher in eine Funktion auslagern und ggf erweitern kann... Ich habe bisher nur ein Data von 4 gebraucht, deswegen hab ich den Wert auch fest gesetzt, aber ich könnte ja jetzt in dem Code aus meinem späteren Post das Data:=4 entfernen und Data als Parameter übergeben lassen und die Funktion so auch für variable Werte verwenden.
Ich weiß jetzt nicht wie geübt Du mit Delphi bist aber z.B. das "Button - On Click" Ereignis ist ja nur eine Prozedur. Eine Funktion, oder in Delphi als "function..." bezeichnet sieht ja so aus wie z.B. deine "GetAdress" Funktion. Eine Funktion setzt sich demnach als "Bezeichnung (Übergabeparameter, ..., ... etc.): Ausgabeparameter" zusammen.
Somit wäre die Deklaration bei der Button Prozedur irrelevant. Zumindest so wie diese letztlich aufgebaut ist.
Zum anderen... Pointer sind immer (auf 32-Bit Systemen sicher) 4 zusammenhängende Bytes. Deshalb spricht man auch z.B. von 4 Bytes Aligned. Einzig der letzte Datentyp, also z.B. ein Geld- oder Healthwert im Spiel kann eine andere Größe haben. Und da Du bereits eine Funktion namens "GetAdress" hast, also quasi das Ganze trennst, kannst Du getrost bei dem bleiben wie ich es beschrieben hab. Das auslesen oder schreiben des Wertes könntest Du dann in eine andere Funktion auslagern und da dementsprechende Parameter über geben.
Eine Ausnahme bilden z.B. die FLOAT Werte. Werte mit einfacher Genauigkeit sind 4 Bytes lang. Werte mit doppelter Genauigkeit sind 8 Bytes lang. Diese sind also entweder als 2 zuammenhängende DWORD's zu sehen oder, wie sie durch die FPU angesprochen werden, als QWORD (Quad Word).


(07.09.2012, 20:25)darius83 schrieb: [ -> ]ReadProcessMemory(Pidhandle, Pointer(Result), @Result, Data, Written);
In deinem Falle...
Data = nSize (MSDN Quelle)
Dieser gibt an, wie Du schon richtig erkannt hast, wieviel Bytes ausgelesen werden.
Written = lpNumberOfBytesWritten
Wie auch aus der MSDN Datenbank zu entnehmen ist ist dies ein Ausgabeparameter. Ist quasi ein Pointer zu einer Variablen die die Anzahl der tatsächlich geschriebenen/gelesenen Bytes enthält.
(08.09.2012, 01:39)sILeNt heLLsCrEAm schrieb: [ -> ]Ich weiß jetzt nicht wie geübt Du mit Delphi bist aber z.B. das "Button - On Click" Ereignis ist ja nur eine Prozedur. Eine Funktion, oder in Delphi als "function..." bezeichnet sieht ja so aus wie z.B. deine "GetAdress" Funktion. Eine Funktion setzt sich demnach als "Bezeichnung (Übergabeparameter, ..., ... etc.): Ausgabeparameter" zusammen.
Somit wäre die Deklaration bei der Button Prozedur irrelevant. Zumindest so wie diese letztlich aufgebaut ist.

Ich glaube du hast da was verwechselt... Das Button-Ereignis besteht ja nur aus 4 Zeilen + Kopf und Rumpf... Ich wüsste nicht, was ich da anders machen sollte, ausser vielleicht wie schon diskutiert, den Timer direkt im onCreate-onDestroy der Form zu starten/stoppen...
Aber ich denke, ich hab verstanden, worauf du hinaus wolltest Wink

Jetzt bräuchte ich nur nochmal definitiv Nachhilfe beim Suchen/Finden von Adressen... Ich weiss nicht, ob ich irgendetwas falsch mache, oder es einfach noch andere möglichkeiten gibt, bestimmte Werte zu finden, jedenfalls hab ich böse Probleme damit, die richtigen Adressen, bzw. überhaupt irgendwelche Adressen zu finden...

Anschliessend die Pointer zu den entsprechenden Adressen zu finden, fällt mir da wesentlich leichter...

LG Darius83
Das mit dem Timer mach ich prinzipiell so.
Sobald der Trainer läuft hält dieser Ausschau nach dem Game Prozess.
Den Timer selbst brauchst Du nicht extra im OnCreate oder OnShow Ereignis aufrufen. Einfach den Timer auf die Mainform ziehen und Delphi weiß wie dieser zu verwenden ist.

Aber die Sache mit den Pointern ist die das es eben auch Spiele gibt wo das nicht so einfach bis garnicht möglich ist. Spätestens dann dürftest Du an die Grenzen stoßen wenn die Pointer dynamisch vom Stack geholt, oder "wild" gelesen und gespeichert werden.

Zum Beispiel bei meinem letzten Projekt "I am Alive" ist die Sache etwas kniffliger. Da sich dort sogar der Basispointer von Level zu Level ändert.
Wenn Du erstmal das Verständniss für eine Codecave/Codeinjection hast und damit dann auch umgehen kannst... Glaub mir, dann wirst Du kaum noch von Pointern Gebrauch machen. Es sei denn diese sind auf einfachste Weise realisierbar.
(09.09.2012, 00:42)sILeNt heLLsCrEAm schrieb: [ -> ]Das mit dem Timer mach ich prinzipiell so.
Sobald der Trainer läuft hält dieser Ausschau nach dem Game Prozess.
Den Timer selbst brauchst Du nicht extra im OnCreate oder OnShow Ereignis aufrufen. Einfach den Timer auf die Mainform ziehen und Delphi weiß wie dieser zu verwenden ist.

Aber die Sache mit den Pointern ist die das es eben auch Spiele gibt wo das nicht so einfach bis garnicht möglich ist. Spätestens dann dürftest Du an die Grenzen stoßen wenn die Pointer dynamisch vom Stack geholt, oder "wild" gelesen und gespeichert werden.

Zum Beispiel bei meinem letzten Projekt "I am Alive" ist die Sache etwas kniffliger. Da sich dort sogar der Basispointer von Level zu Level ändert.
Wenn Du erstmal das Verständniss für eine Codecave/Codeinjection hast und damit dann auch umgehen kannst... Glaub mir, dann wirst Du kaum noch von Pointern Gebrauch machen. Es sei denn diese sind auf einfachste Weise realisierbar.

Das mag ich dir ja gut und gerne glauben, aber helfen tuts auch nicht, wenn ich nichtmal die momentane Adresse für etwas Bestimmtes finde... denn ganz ohne gehts ja nun mal nicht, oder? Wink Ich meine, mir bringts ja nun nicht wirklich was, wenn ich weiss, wie ich eine Codecave bastel, wenn ich die Adresse, in der meinetwegen das Gold geschrieben wird, garnicht erst finden kann... Denn dann fehlt mir ja auch der Einstiegspunkt für die Cave, oder seh ich das jetzt falsch?

LG Darius83
Seiten: 1 2 3 4 5 6 7