Komplexere Memory Adressen finden

09/04/2015 02:28 MrLovaLovaBean#1
Hallo,

kann mir einer bitte erklären wie ich komplexere Memory Adressen finde?

Ich meine jetzt nicht sowas wo man den Wert verändern kann und dann einfach die ganze zeit nach dem exakten Wert sucht, so weit bin ich auch schon gekommen :P Aber ich hab z.B. keinen Plan wie ich nun die Position von anderen Spielern finde oder z.B. welche Waffe gerade bei ihm ausgerüstet ist.

Ich bedanke mich schon mal im voraus und nun endlich ab ins Bett :D

Freundliche Grüsse
09/04/2015 02:42 alpines#2
Bei so etwas kannst du ja nach dem Pointer suchen der auf die Spielerliste zeigt. Von dort aus kannst du Offsets dazu addieren die HP auslesen, Waffen auslesen etc.
09/04/2015 02:48 MrLovaLovaBean#3
Quote:
Originally Posted by alpines View Post
Bei so etwas kannst du ja nach dem Pointer suchen der auf die Spielerliste zeigt. Von dort aus kannst du Offsets dazu addieren die HP auslesen, Waffen auslesen etc.
Genau das ist es ja was ich nicht verstehe. Wie finde ich den Pointer? Wie fange ich danach an zu suchen? Es geht jetzt nicht nur speziell um diesen einen Fall sondern um das allgemeine Finden von solchen Pointers. Ich will ja schliesslich nicht jedes mal hier nachfragen müssen :D

Vielen dank schon mal! :)
09/04/2015 13:23 Shadow992#4
Quote:
Originally Posted by MrLovaLovaBean View Post
Genau das ist es ja was ich nicht verstehe. Wie finde ich den Pointer? Wie fange ich danach an zu suchen? Es geht jetzt nicht nur speziell um diesen einen Fall sondern um das allgemeine Finden von solchen Pointers. Ich will ja schliesslich nicht jedes mal hier nachfragen müssen :D

Vielen dank schon mal! :)
Bevor du meiner Antwort blind vertraust möchte ich anmerken, dass ich noch nie nach Klassen/Strukturen gesucht habe. Meine Erklärungen sind jetzt also rein auf Wissens-/Erfahrungsbasis.
Ein bisschen C/C++ Grundwissen schadet bei dem Thema nicht und ist meiner Meinung nach Voraussetzung, um wirklich durchzublicken, deswegen werde ich auch ein klein wenig C/C++ Wissen in meine Erklärung mit einfließen lassen.

Vermutlich werden die gegnerischen Spieler in einem Array gespeichert, welches vielleicht sogar dynamisch in der Größe veränderbar ist.
Das heißt die erste Aufgabe, die es für dich zu tun gibt, ist es dieses Array zu finden.
Nur das Ganze Array kannst du natürlich nicht einfach so suchen.
Was du aber machen kannst ist nach speziellen Werten suchen, die ein gegnerischer Spieler haben kann.
Besonders bieten sich dafür HP/Mana/X-Koordinate/Y-Koordinate an, weil sich diese entweder leicht eingrenzen lassen (Werte zwischen +-10000) oder weil sie sich dauernd/nicht dauernd verändern.
Damit hast du dann also die HP-Adresse dieses einen Spielers gefunden. Damit alleine kannst du erst einmal wenig anfangen. Du könntest jetzt natürlich die umliegenden Speicheradressen durchsuchen auf bekannte/interessant Werte, bei kleinen Spielen geht das sicher auch einfach.
Aber meiner Meinung nach sollte man sich als nächstes einen 2., 3., 4. Spieler schnappen und ebenfalls deren wichtige Werte auslesen.

Mit diesen Informationen können wir dann abschätzen wie die Datenstruktur zum Verwalten der Klassen aussieht.
Fragen, die wir dabei beantworten müssen sind folgende:

Haben wir ein dynamisches Array? Z.B. std::vector/malloc/new ?
Haben wir ein statisches Array? Also mit fester Größe?
Haben wir überhaupt ein Array oder ist es eine Liste? Z.B. std::list
Wie viele Pointer-Ebenen sind zwischen unserem "Array" und der "fertigen" Klasse? Haben wir vielleicht ein Array von Arrays von Klassen?

Ein paar Fragen können wir mit unseren paar Werten klären.
Hätten wir ein statisches/dynamisch Array, dann müssten alle Abstände zwischen den Arrays durch denselben "Wert" teilbar sein, weil ja alle Objekte gleich groß sind.
Dabei müssen wir aber erst einmal die Mindestgröße eines Objekts schätzen, dabei geht man ganz intuitiv vor:
X-/Y-Koordinate jeweils min. 2 Bytes
HP/Mana ebenfalls jeweils min. 2 Bytes
Gold/Geld min. 4 Bytes
Diverse Pointer (z.b. Pointer zum Rucksack/ausgerüstete Waffen etc.) veranschlagen wir mal grob mit 20 Byte
Sonstige Sachen, die wir finden im Game (z.B. Größe der Figur, Lauf/Angriffsgeschwindigkeit, etc.) schätzen wir mal mit 8 Bytes ab

Insgesamt ist unsere Klasse also wahrscheinlich mindestens 40 Bytes groß.
Das heißt, wenn unsere Objekte "einfach" hintereinander abgespeichert werden, muss es eine Zahl größer 40 Bytes geben, die die Abstände zwischen den gefundenen Spielern ohne Rest teilt.
Wenn wir eine derartige Zahl gefunden haben, können wir die Größe einer Klasse noch genauer abschätzen, wahrscheinlich sogar ganz genau.
Wenn das der Fall ist, suchen wir einfach noch ein paar Spieler und holen uns die genaue Abschätzung der Klassen-Größe.

Kniffeliger wird es, wenn die Klassen in einer Liste verwaltet werden oder eine Pointer Schicht dazwischen liegt.

Gehen wir einmal von nur Pointer-Schichten aus (also ohne Liste):
Hier sollte eine Analyse nach dem Prinzip "Show me what access this value" erste Anhaltspunkte liefern.
Damit sollten wir die Pointer finden, auch hier wollen wir natürlich wieder das Pointer-Array finden, Pointer sind bei x86-Exen 4 Byte groß (so viel ich weiß gibt es da keine Ausnahmen).
Das heißt was wir jetzt machen ist einfach alle Pointer zu den Objekten anzuschauen und die rauszusuchen, die "einigermaßen" nah bei einander liegen und deren Abstände vielfache von 4 sind.
Bei 64 Bit-Exen können Pointer soweit ich weiß sowohl 8 Byte groß sein als auch 4 Byte. Das heißt auch hier suchen wir nach den Adressen mit Abstand vielfaches von 4.
Wenn jedoch jeder Abstand auch durch 8 teilbar ist, sollten wir wohl zuerst 8 näher betrachten.

Bei dieser Methode können wir zwar auch die Größe der Objekte herausfinden, das ist jedoch viel kniffeliger, deswegen würde ich empfehlen nur das Offset zu den jeweiligen Werten vom Startpointer aus anzuschauen.
Damit können wir zwar nicht eindeutig identifizieren was noch zu unserer Klasse gehört und was nicht, aber alles andere dürfte mega hässlich werden.

Aber alles noch machbar, wenn man nicht die komplette Objekte "finden" will, kann man auch schon bei dem einfachsten Fall (statische Arrays ohne Pointer) nur das Offset speichern, ich bin jetzt aber davon ausgegangen, dass wir immer so viel wie möglich haben wollen, wenn es "einfach" funktioniert.

Lustig wird es erst wenn man Eine Liste von Pointern hat also in etwa std::list<Class*>, in der freien Natur dürfte man das (für Spielerarrays) wohl selten antreffen und wenn doch, ist wohl die einzige Möglichkeit sich ins Eck zu verkriechen und zu heulen. :D
Nein Spaß bei Seite möglich ist es natürlich auch, läuft im Grunde ähnlich ab, wie bei Arrays mit Pointern, nur dass man jetzt im Hinterkopf haben muss wie eine Liste im Normalfall aufgebaut ist.
Da das Ganze meiner Meinung nach aber selten auftreten wird und es echt hässlich ist, spar ich mir dazu nähere Ausführungen.
09/04/2015 15:59 warfley#5
Was man nicht vergessen darf, bei einem Array oder einem Record (struct) ist der Speicher nicht unbedingt direkt Linear angeordnet, der Compiler setzt zwischen den Elementen teilweise Lücken ein, damit diese einfacher zu verwalten sind. Das lässt sich zwar per packed Records und Arrays verhindern, diese sind aber nicht unerheblich langsamer in der Nutzung, wodurch, grade bei spielen, das eigentlich nicht verwendet wird.

Im Klartext heißt das, dass z.B. Struct: Word(2 Byte), Char(1), Char(1) so aufgeteilt sein Kann:
Word(2B), Lücke(2B), Char1(1B), Lücke(1B), Char(1B), Lücke(1B).

Genauso kann es sein, wenn der Speicher für den Record nicht vorher gecleared wurde, dass Daten in diesen Lücken stehen, was entsprechend sehr verwirrend sein kann

Das heißt selbst wenn du die Startadresse von dem Record hast, kannst du dennoch nicht sagen wo welches element ist, und musst erst durchsuchen, und dabei nicht auf die Lücken reinfallen.

PS:
Quote:
Haben wir ein dynamisches Array? Z.B. std::vector?
Haben wir ein statisches Array? Also per malloc/new angelegt?
per New/Malloc legt man auch Dynamische Arrays an, Statische Arrays sind Arrays bei welchen die Größe bereits zur Compilezeit feststeht, und welche daher auf dem Statischen Speicher abgelegt werden können statt auf dem Dynamischen.
vector ist einfach nur eine Klasse um den Array drum herum gebaut um die Nutzung zu vereinfachen intern nutzt dieser auch nur malloc, realloc und free
09/04/2015 17:20 Shadow992#6
Quote:
Originally Posted by warfley View Post
PS:

per New/Malloc legt man auch Dynamische Arrays an, Statische Arrays sind Arrays bei welchen die Größe bereits zur Compilezeit feststeht, und welche daher auf dem Statischen Speicher abgelegt werden können statt auf dem Dynamischen.
vector ist einfach nur eine Klasse um den Array drum herum gebaut um die Nutzung zu vereinfachen intern nutzt dieser auch nur malloc, realloc und free
Da hast du natürlich vollkommen Recht, hatte die Wörter beim Schreiben aus irgendeinem Grund falsch benutzt. Ich habs mal ausgebessert.