Cheatengine Pointer finden

03/06/2017 23:19 ByteDevil#1
Hallo Leute,

sicher runzeln bei dem Titel viele die Stirn und sagen "Bitte nicht noch so ein Thread" aber ich habe die "üblichen" Wege solch einen Basepointer zu finden schon durchgekaut. Falls es interessiert...es geht um das Halflife 1 Remake "Black Mesa" und ich versuche momentan einen funktionierenden Pointer auf zB. den Inhalt des Assault Rifle Magazins zu finden. Den bloßen Wert zu finden ist gar kein Problem...wenn ich einen Pointerscan durchführe, finde ich natürlich unglaublich viele Pointer...4 oder 5 rescans später mit mehreren neustarts des Spiels, ist die Liste leider leer... (bis Pointer Level 5 habe ich suchen lassen - ca 2 Milliarden mögliche Pointer findet man dann).

Wenn ich den Pointer auf die "gute alte Art" finden möchte (Find out what writes to this address), wird mir folgendes angezeigt:


5A4528E8 ist die Adresse die ich manuell gefunden habe und die gerade den Wert beinhaltet.

mov [eax],ecx ist ja der Code, der den neuen Wert setzt. Da ist schonmal kein Offset dabei...
Suche ich dann nach 5A4528E8, finde ich keine einzige Adresse die auf diese Adresse zeigt... und nun? Weiß nicht mehr weiter... Vielleicht komme ich mit einem noch tieferen Pointerscan weiter? Level 7 oder so? Dauert aber natürlich dann ewig...bestimmt 4 oder 5h und das obwohl mein PC alles andere als langsam ist und ich viele Pointer suchen muss.

Bei den HP und der Armor des Spielers bin ich mit dem Pointerscan erfolgreich gewesen.

Wäre sehr nett, wenn mir hier jemand helfen könnte :)

LG
ByteDevil
03/06/2017 23:36 Jeoni#2
Wie man sieht, wird der Speicher an besagter Adresse durch Dereferenzierung von EAX beschrieben. EAX wiederum, das kann man einer Instruktion vorher entnehmen, kommt aus [EBP + 10] (vermutlich ist 0x10 gemeint). EBP ist in der Regel der Frame Pointer (zeigt auf eine bestimmte Stelle im Stack) und [EBP + 0x10] enthält eines der Funktion übergebenen Argumente. An der Stelle würde ich hier ansetzen und schauen, von wo die Funktion aufgerufen wird (muss ebenfalls auf dem Stack stehen) und woher das Argument kommt, was hier verwertet wird.
Mit freundlichen Grüßen
Jeoni
03/06/2017 23:47 ByteDevil#3
Hi Jeoni :)

Danke für deine Antwort ;)

Ich habe die Adresse die hinter EBP+10 steht mal manuell hinzugefügt um zu sehen wo ich dann rauskomme. Der Inhalt springt aber ständig zwischen irgendwelchen random Werten hin und her :/ Ist das ein indikator dafür, dass es eine Sackgasse ist? Weiß nicht genau was ich sonst damit anfangen soll :/
03/06/2017 23:54 Jeoni#4
Nein, es ist keine Sackgasse, nur der falsche Ansatz. Es handelt sich hierbei um eine lokale Variable. Sie liegt auf dem Stack und sobald die Funktion, zu welcher der Code, den du oben gepostet hast returnt, kann die lokale Variable jederzeit wieder überschrieben werden. Daher muss man hier auch manuell ran und sich den Code ansehen (genauer gesagt den spezifischen Caller von obig geposteten Code), um zu schauen, wie bzw. von wo der Pointer kommt, der da als Argument (auch eine Art von lokaler Variable) übergeben wird. Die Returnadresse, also die Adresse des Callers solltest du standardmäßig bei [EBP + 4] finden. Nur aufpassen, dass du den Wert auch im richtigen Kontext abrufst, denn auch das ist natürlich lokal.
Mit freundlichen Grüßen
Jeoni
03/07/2017 00:02 ByteDevil#5
Okay, leider hab ich tatsächlich nur die Hälfte von dem Verstanden was du sagst^^ Ich weiß was der Stack und was der Heap ist und auch was eine lokale Variable ist. Bei Caller bin ich raus^^

Falls du das in kurzen Worten erklären kannst/willst wäre ich dankbar, verstehe aber auch wenn das jetzt zu weit führt^^

Finde es sehr schade das man in irgendwelchen Tutorials nie auf solche Probleme trifft und man da sofort den Pointer auf die 0815-Weise findet -.-
03/07/2017 03:07 florian0#6
Der Stack behinhaltet lokale Variablen. Dazu zählen auch übergebene Funktionsparameter!

Wir haben Beispielsweise diesen Funktionsaufruf:
Code:
push    edi
push    eax
mov     ecx, edi
call    sub_1000DC20
Die PUSH-Instruktionen legen die Parameter auf dem Stack ab. (Wenn du ein solches Konstrukt mit dem mov ecx, ... siehst, kannst du davon ausgehen, dass die Funktion, die aufgerufen wird, zu einem Objekt gehört. Ist aber erstmal nur nebensächlich).

Beim CALL wird zusätzlich die Rücksprungadresse abgelegt. Sonst weiß das Programm am Ende der Funktion nicht, wo es hin soll.

TLDR; Diese Stelle ist der "Caller". Die Stelle, an der die Funktion aufgerufen wird.

Der Stack sieht mit Betreten des CALLs dann so aus:

Code:
0 Rücksprungadresse
+4 <Wert von EAX>
+8 <Wert von EDI>
Wenn die Funktion nun noch lokale Variablen hat, werden diese oberhalb der Rücksprungaddresse abgelegt (Allerdings nicht via PUSH. Dieser Bereich wird normalerweise einfach Stumpf vorreserviert).
Mit zwei Variablen sähe das dann so aus.
Code:
-8 Variable v2
-4 Variable v1
0 Rücksprungadresse
+4 <Wert von EAX>
+8 <Wert von EDI>
An dieser Stelle sollte dir aufgefallen sein, dass ich alles um die Rücksprungaddresse herum addressiert habe. Das hat auch einen Grund: Am Anfang einer "klassischen Funktion" wird das Register EBP an dieser Stelle "fixiert". d.h. Mit EBP+4 kommst du immer an den ersten Parameter, mit EBP-4 immer an die erste lokale Variable.

("klassischen Funktion" deshalb, weil man es nicht generalisieren kann. Der Compiler macht viele Optimierungen, daher trifft das nicht einfach grundsätzlich auf alle Funktionen zu)

Soweit so gut.

Code:
mov eax,[ebp+10]
Wir suchen EBP+10. Das Plus sagt uns, dass es sich um einen Parameter handeln sollte. Zusammen mit 0x10 ergibt das den vierten Parameter. (Eine Addresse hat auf einem 32 Bit System 4 Byte. 0x10 sind 4x 4 Byte).

TL;DR: Wir suchen den Parameter, der durch den Caller an die Funktion übergeben wird, der dann in EBP+10 verfügbar ist.
03/07/2017 07:28 Dr. Coxxy#7
wenn ein stackframe erstellt wird sieht das meist folgendermaßen aus:
Code:
push ebp
mov ebp, esp
d.h. an 0 liegt der vorherige ebp wert, nicht die rücksprungadresse...
dementsprechend liegt der erste parameter auch immer an +0x8 und nicht +0x4, usw...
03/07/2017 07:47 ByteDevil#8
Hallo und vielen, vielen Dank für die Antwort :)

Okay, also ich habe es mir erneut angesehen und bemerkt das bei

Code:
mov ecx,[eax+04]
mov eax,[ebp+10]
mov [eax],ecx
EBP an dieser Stelle immer 0019D218 ist. Also auch nach einem Neustart des Spiels/PC's.
Nun ist aber völlig egal ob ich bei 0019D218+10, 0019D218+8 oder 0019D218+4 nachsehe - der Wert darin springt immer wild hin und her.
Wärt ihr so nett mich noch ein wenig weiter in die richtige Richtung zu schupsen? Ich möchte wirklich nur lernen wie das funktioniert, weil ich reverse engineering unglaublich interessant finde.

Kann ich vielleicht irgendwie eine Art Breakpoint auf diesen Code setzen, der auslöst und mitschneidet was in den Registern steht, wenn ich meinen Wert im Spiel gerade mit dem oben genannten OP-Code verändere?

PS: Habe nochmal einen Screenshot gemacht der es etwas übersichtlicher Anzeigt:

[Only registered and activated users can see links. Click Here To Register...]
03/07/2017 14:10 florian0#9
Quote:
Originally Posted by Dr. Coxxy View Post
d.h. an 0 liegt der vorherige ebp wert, nicht die rücksprungadresse...
dementsprechend liegt der erste parameter auch immer an +0x8 und nicht +0x4, usw...
:handsdown: Du hast vollkommen recht. Es war wohl schon etwas spät.


Die Addresse 0019D218 bezieht sich auf den Stack. Das erkennt man daran, dass sich der Inhalt konstant ändert, aber abundzu dein gewünschter Inhalt ist.
Es gibt nur einen Stack pro Thread. d.H. Alle Funktionen die sonst noch in diesem Thread aufgerufen werden, nutzen ebenfalls den selben Stack. Und das führt dann dazu, dass hier eben auch andere Daten abgelegt werden.


Deine Funktion ist folgende:
Code:
PUSH EBP
MOV EBP, ESP

MOV EAX, [EBP+08]
MOV ECX, [EAX+04]
MOV EAX, [EBP+10]
MOV [EAX], ECX

POP EBP
RETN
Wir suchen einen Pointer auf den Wert von EAX, richtig? EAX resultiert aus MOV EAX, [EBP+10]. Wir wissen, dass sich EBP auf den Stack bezieht, und wir wissen aus meinem vorherigen Post, dass es sich her um einen Parameter handeln sollte.

Wir müssen nun also rausfinden WO die Funktion aufgerufen wird (Caller finden).
Wie finden wir den? Easy. Wie wir ebenfalls bereits wissen, wird die Rücksprungaddresse (zum Caller) mit ausführen der CALL-Instruktion auf dem Stack abgelegt.

Den Stack sieht man, leicht eingequetscht, unten rechts in der Ecke. Dort sieht man:

Code:
0019D248
server.dll+XXX
21D10024
....
...
...
Wie Dr. Coxxy schon sagte und in dem Assemblycode von oben sichtbar:
Der oberste Wert im Stack resultiert aus dem "PUSH EBP". Da es keine weiteren PUSH-Instruktionen oder Schreiboperationen in das ESP-Register gab, hat sich der Stack auch nicht weiter verändert. Das heißt, der darauf folgende Eintrag im Stack, ist die Rücksprungaddresse.
Da war sich auch CheatEngine ziemlich sicher, schließlich hat es server.dll+xxxx hingeschrieben.

Und das ist der Ort, den du dir mal genauer ansehen solltest. Dort sollte genauer aufgelöst werden, wie der Pointer berechnet wird.

Gruß
florian0
03/07/2017 19:10 ByteDevil#10
Ah, okay ich habe größtenteils verstanden was du sagst. Hier mal ein neuer Screenshot wo mehr vom Stack zu sehen ist:

[Only registered and activated users can see links. Click Here To Register...]

4CE200D0 ist übrigens in diesem Fall gerade die Adresse zu der ich möchte und die meinen Wert beinhaltet.
Also ist nun 0EDB88B3 meine Rücksprungadresse der Funktion welcher ein Pointer auf meine Lebenspunkte/Munition etc. als Parameter übergeben werden?
Wenn ja, dann muss ich mir irgendwie sämtliche Parameter des Aufrufes anzeigen?