Benutzer-Werkzeuge

Webseiten-Werkzeuge


Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen gezeigt.

Link zu der Vergleichsansicht

Nächste Überarbeitung
Vorherige Überarbeitung
Nächste Überarbeitung Beide Seiten, nächste Überarbeitung
skripten:engineforschung [2018/09/08 22:58]
mud-freak angelegt
skripten:engineforschung [2018/09/09 17:12]
mud-freak [Register]
Zeile 37: Zeile 37:
 Das ist grundsätzlich alles was wir brauchen. Das ist grundsätzlich alles was wir brauchen.
  
 +{{ :​skripten:​engineforschung:​layout791.png |}}
 ===== IDA View (Disassembly) ===== ===== IDA View (Disassembly) =====
  
-Hier sehen wir die gesamte EXE von Anfang bis Ende. Die Zeilen werden von oben nach unten vom Prozessor abgearbeitet (solange nicht ein Jump eine neue Position diktiert).+Hier sehen wir die gesamte EXE von Anfang bis Ende. Die Zeilen werden von oben nach unten vom Prozessor abgearbeitet (solange nicht ein Jump eine neue Position diktiert; der "​Entrypoint"​ ist allerdings nicht am Anfang).
  
 Ein wertvoller Tipp ist, dass man mit ''​G''​ zu bestimmten Adressen springen kann. Ein wertvoller Tipp ist, dass man mit ''​G''​ zu bestimmten Adressen springen kann.
Zeile 45: Zeile 46:
 Jede Zeile enthält eine Instruktion. Die vier Spalten von links nach rechts sind: Jede Zeile enthält eine Instruktion. Die vier Spalten von links nach rechts sind:
  
-^ Adresse ^ Stackoffset ^ Opcode ^ Assembly-Code ^ +{{ :​skripten:​engineforschung:​instruction.png |}}
-.text:​006C31C3 | 080 | 8B CE | mov  ecx, esi |+
  
 ==== Adresse ==== ==== Adresse ====
Zeile 63: Zeile 63:
  
 ===== Strings-Fenster ===== ===== Strings-Fenster =====
-Fast ebenso wichtig ist die Suche nach Strings (also den Inhalt von Strings). Hier sollten wir auch mit ''​STRG''​+''​F''​ den Quick-Filter öffnen. Dieses Fenster ist extrem hilfreich, wenn wir irgendwo im Spiel eine Textausgabe haben und herausfinden wollen, wo in der Engine diese Ausgabe erstellt wird. In den meisten Fällen lässt sich das durch einen Doppelklick auf den entsprechend gesuchten String heraus finden. Suchen wir aber z.B. nach //"​Unknown command"//​ sehen wir dass uns ein Doppelklick auf den gefundenen String nicht an eine Adresse in einer Funktion führt, sondern in einem Datensegment. IDA listet aber freundlicherweise alle Referenzen zu dieser Adresse darunter auf. Falls es zu viele sind, so dass IDA die Liste mit ''​...''​ abkürzt, hilft ein Rechtsklick mit ''​List cross references to...''​. Die Referenzen zeigen direkt den Namen der Funktion, die den String verwendet. Mit erneutem Doppelklick auf eine dieser Referenzen gelangen wir an die entsprechende Adresse.+Fast ebenso wichtig ist die Suche nach Strings (also den Inhalt von Strings). Hier sollten wir auch mit ''​STRG''​+''​F''​ den Quick-Filter öffnen. Dieses Fenster ist extrem hilfreich, wenn wir irgendwo im Spiel eine Textausgabe haben und herausfinden wollen, wo in der Engine diese Ausgabe erstellt wird. In den meisten Fällen lässt sich das durch einen Doppelklick auf den entsprechend gesuchten String heraus finden. 
 + 
 +{{ :​skripten:​engineforschung:​strings791.png?​400|}} 
 + 
 +Suchen wir aber z.B. nach //"​Unknown command"//​ sehen wir dass uns ein Doppelklick auf den gefundenen String nicht an eine Adresse in einer Funktion führt, sondern in einem Datensegment. IDA listet aber freundlicherweise alle Referenzen zu dieser Adresse darunter auf. Falls es zu viele sind, so dass IDA die Liste mit ''​...''​ abkürzt, hilft ein Rechtsklick mit ''​List cross references to...''​. Die Referenzen zeigen direkt den Namen der Funktion, die den String verwendet. Mit erneutem Doppelklick auf eine dieser Referenzen gelangen wir an die entsprechende Adresse.
  
 Die Referenzen werden übrigens genauso in ausführbaren Segmenten angezeigt und sind dort ebenso nützlich, um zwischen aufgerufenen und aufrufenden Funktionen oder Jumps zu springen. Die Referenzen werden übrigens genauso in ausführbaren Segmenten angezeigt und sind dort ebenso nützlich, um zwischen aufgerufenen und aufrufenden Funktionen oder Jumps zu springen.
Zeile 86: Zeile 90:
  
 ==== ESP ==== ==== ESP ====
 +
 +{{  :​skripten:​engineforschung:​stack.png?​400| Maschinenstack und ESP }}
 +
 ESP zeigt auf den derzeitigen [[#​Maschinenstack|Stackanfang]]. Den brauchen wir also um an auf dem Stack abgelegte Daten heran zu kommen. Deshalb finden wir in Hookfunktionen in Daedalus-Skripten ESP recht häufig. So kann die Hookfunktion Daten auslesen, die zum Zeitpunkt des Hooks auf dem Stack liegen sind. //"​Derzeitigen Stackanfang"//​ deshalb, weil beim Ablegen (push) auf den Stack der Stackpointer um die abgelegte Anzahl an Bytes verringert wird (der Maschinenstack wächst nach unten) und beim Herunternehmen (pop) wieder entsprechend erhöht wird. In IDA finden wir häufig ''​ESP+X''​. Das ''​X''​ steht dabei für den [[#​Stackoffset|Stackoffset]],​ den wir auch in IDA in der zweiten Spalte der Zeile einsehen können. Jedes mal wenn etwas auf den Stack gelegt wird (mit der Instruktion ''​push''​),​ wird ESP entsprechend verringert und der Stackoffset erhöht. Nach beliebig vielen neuen Werten auf dem Stack können wir später trotzdem immer (solange unserer Wert nicht gepoppt ist) mit Hilfe des Stackoffsets ''​X''​ an die Daten kommen: ''​ESP+X''​. ESP zeigt auf den derzeitigen [[#​Maschinenstack|Stackanfang]]. Den brauchen wir also um an auf dem Stack abgelegte Daten heran zu kommen. Deshalb finden wir in Hookfunktionen in Daedalus-Skripten ESP recht häufig. So kann die Hookfunktion Daten auslesen, die zum Zeitpunkt des Hooks auf dem Stack liegen sind. //"​Derzeitigen Stackanfang"//​ deshalb, weil beim Ablegen (push) auf den Stack der Stackpointer um die abgelegte Anzahl an Bytes verringert wird (der Maschinenstack wächst nach unten) und beim Herunternehmen (pop) wieder entsprechend erhöht wird. In IDA finden wir häufig ''​ESP+X''​. Das ''​X''​ steht dabei für den [[#​Stackoffset|Stackoffset]],​ den wir auch in IDA in der zweiten Spalte der Zeile einsehen können. Jedes mal wenn etwas auf den Stack gelegt wird (mit der Instruktion ''​push''​),​ wird ESP entsprechend verringert und der Stackoffset erhöht. Nach beliebig vielen neuen Werten auf dem Stack können wir später trotzdem immer (solange unserer Wert nicht gepoppt ist) mit Hilfe des Stackoffsets ''​X''​ an die Daten kommen: ''​ESP+X''​.
 ==== ECX ==== ==== ECX ====
 ECX ist zwar ein Zählerregister für Schleifen, ist aber hier aus anderem Grund für uns interessant. Die //Calling Conventions//,​ die man evtl. aus C und C++ kennt, sind verschiedene Arten wie eine Funktion aufgerufen wird (z.B. wird der Stack von der Funktion selbst aufgeräumt oder muss das der Aufrufer machen?, usw.). Eine dieser //Calling Conventions//​ ist %%__%%thiscall. Während normale Argumente immer auf den Stack (siehe [[#​ESP|ESP]]) gelegt und so der aufgerufenen Funktion bereitgestellt werden, wird ''​this''​ für eine solche Funktion in ECX abgelegt. ECX ist zwar ein Zählerregister für Schleifen, ist aber hier aus anderem Grund für uns interessant. Die //Calling Conventions//,​ die man evtl. aus C und C++ kennt, sind verschiedene Arten wie eine Funktion aufgerufen wird (z.B. wird der Stack von der Funktion selbst aufgeräumt oder muss das der Aufrufer machen?, usw.). Eine dieser //Calling Conventions//​ ist %%__%%thiscall. Während normale Argumente immer auf den Stack (siehe [[#​ESP|ESP]]) gelegt und so der aufgerufenen Funktion bereitgestellt werden, wird ''​this''​ für eine solche Funktion in ECX abgelegt.
 +
 +{{:​skripten:​engineforschung:​getname.png?​400 | oCNpc::​GetName }}
  
 Speziell bedeutet das, dass in der Funktion ''​oCNpc::​GetName''​ der NPC in Frage in ECX zur Verfügung steht. ECX ist in diesem Falle also ein Zeiger auf ein oCNpc-Objekt. Schauen wir in die Funktion sehen wir, dass an Adresse ''​0x72F825''​ auf ''​ecx+124h''​ Bezug genommen wird. 124h ist hexadezimal für 292. In der Klasse oCNpc (dokumentiert in Ikarus) finden wir an Offset 292 die Klassenvariable ''​name''​. Die Funktion tut also was sie verspricht: Sie holt den Namen eines des NPC. Würden wir ''​oCNpc::​GetName''​ hooken (aus welchem irrsinnigen Grund auch immer) könnten wir in Daedalus über ECX an den NPC herankommen. Speziell bedeutet das, dass in der Funktion ''​oCNpc::​GetName''​ der NPC in Frage in ECX zur Verfügung steht. ECX ist in diesem Falle also ein Zeiger auf ein oCNpc-Objekt. Schauen wir in die Funktion sehen wir, dass an Adresse ''​0x72F825''​ auf ''​ecx+124h''​ Bezug genommen wird. 124h ist hexadezimal für 292. In der Klasse oCNpc (dokumentiert in Ikarus) finden wir an Offset 292 die Klassenvariable ''​name''​. Die Funktion tut also was sie verspricht: Sie holt den Namen eines des NPC. Würden wir ''​oCNpc::​GetName''​ hooken (aus welchem irrsinnigen Grund auch immer) könnten wir in Daedalus über ECX an den NPC herankommen.
skripten/engineforschung.txt · Zuletzt geändert: 2018/09/09 17:38 von mud-freak