Benutzer-Werkzeuge

Webseiten-Werkzeuge


Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen gezeigt.

Link zu der Vergleichsansicht

Beide Seiten, vorherige Überarbeitung Vorherige Überarbeitung
Nächste Überarbeitung
Vorherige Überarbeitung
skripten:engineforschung [2018/09/09 17:10]
mud-freak [Register]
skripten:engineforschung [2018/09/09 17:38] (aktuell)
mud-freak [IDA Interface]
Zeile 37: Zeile 37:
 Das ist grundsätzlich alles was wir brauchen. Das ist grundsätzlich alles was wir brauchen.
  
-{{ :​skripten:​engineforschung:​layout791.png |}}+{{ :​skripten:​engineforschung:​layout791.png?​nolink ​IDA Fenster ​}}
 ===== IDA View (Disassembly) ===== ===== IDA View (Disassembly) =====
  
Zeile 46: 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:
  
-{{ :​skripten:​engineforschung:​instruction.png |}}+{{ :​skripten:​engineforschung:​instruction.png?​nolink ​Zeile aus IDA }}
  
 ==== Adresse ==== ==== Adresse ====
Zeile 91: Zeile 91:
 ==== ESP ==== ==== ESP ====
  
-{{  :​skripten:​engineforschung:​stack.png?​400| Maschinenstack und ESP }}+{{  :​skripten:​engineforschung:​stack.png?​400&nolink| 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.
Zeile 126: Zeile 128:
  
 ===== Teil I ===== ===== Teil I =====
 +
 +{{ :​skripten:​engineforschung:​focus.png?​150&​nolink| Focussuche wie in alten Zeiten }}
 +
 Wo fangen wir an? Ein erster Gedanke ist //"​Vielleicht passiert das in irgendeiner Funktion die sich mit dem '​Focus'​ beschäftigt."//​. Geben wir also in den Quick-Filter des //​Names//​-Fensters //Focus// ein und schauen in einige der gelisteten Funktionen. Dort können wir ein bisschen im //IDA View// herumscrollen und nach verdächtigen Funktionsaufrufen Ausschau halten: Wo fangen wir an? Ein erster Gedanke ist //"​Vielleicht passiert das in irgendeiner Funktion die sich mit dem '​Focus'​ beschäftigt."//​. Geben wir also in den Quick-Filter des //​Names//​-Fensters //Focus// ein und schauen in einige der gelisteten Funktionen. Dort können wir ein bisschen im //IDA View// herumscrollen und nach verdächtigen Funktionsaufrufen Ausschau halten:
  
 Denn ab und zu werden andere Funktionen aus einer Funktion mit der Instruktion ''​call''​ aufgerufen. IDA sucht dazu den Namen der referenzierten Funktion und schreibt ihn in die selbe Zeile. Das ermöglicht es, uns an den Namen der aufgerufenen Funktionen zu orientieren,​ was die Engine an der Stelle vermutlich so macht. Denn ab und zu werden andere Funktionen aus einer Funktion mit der Instruktion ''​call''​ aufgerufen. IDA sucht dazu den Namen der referenzierten Funktion und schreibt ihn in die selbe Zeile. Das ermöglicht es, uns an den Namen der aufgerufenen Funktionen zu orientieren,​ was die Engine an der Stelle vermutlich so macht.
 +
 +{{ :​skripten:​engineforschung:​playerstatus_names.png?​150&​nolink|}}
  
 In den Funktionen hier geht es aber scheinbar einfach viel darum den Focus zu ermitteln und einzugrenzen usw. Das ist für unsere Absichten also eine Sackgasse. In den Funktionen hier geht es aber scheinbar einfach viel darum den Focus zu ermitteln und einzugrenzen usw. Das ist für unsere Absichten also eine Sackgasse.
  
-Ein weiterer Gedanke: Es gibt ja das [[http://​forum.worldofplayers.de/​forum/​threads/​1495001?​p=25717008|hidePlayerStatus-Skript]],​ das alle On-Screen Informationen,​ inklusive der Bars ausschalten kann. Darin wird sich der Enginefunktion ''​oCGame::​SetShowPlayerStatus''​ bedient, die das kontrolliert. Also suchen wir doch mal im //​Names//​-Fenster nach Funktionen mit //"​PlayerStatus"//​ im Namen. ''​oCGame::​UpdatePlayerStatus''​ hört sich gut an. Da dies eine %%__%%thiscall-Funktion ist, wissen wir, dass (zumindest am Anfang der Funktion) ECX auf das oCGame-Objekt zeigt, in dem die Bars referenziert werden (siehe oCGame Klasse, dokumentiert in Ikarus).+Ein weiterer Gedanke: Es gibt ja das [[http://​forum.worldofplayers.de/​forum/​threads/​1495001?​p=25717008|hidePlayerStatus-Skript]],​ das alle On-Screen Informationen,​ inklusive der Bars ausschalten kann. Darin wird sich der Enginefunktion ''​oCGame::​SetShowPlayerStatus''​ bedient, die das kontrolliert. Also suchen wir doch mal im //​Names//​-Fenster nach Funktionen mit //"​PlayerStatus"//​ im Namen. ''​oCGame::​UpdatePlayerStatus''​ hört sich gut an. 
 + 
 +Da dies eine %%__%%thiscall-Funktion ist, wissen wir, dass (zumindest am Anfang der Funktion) ECX auf das oCGame-Objekt zeigt, in dem die Bars referenziert werden (siehe oCGame Klasse, dokumentiert in Ikarus). 
 + 
 +{{ :​skripten:​engineforschung:​updateplayerstatus.png?​nolink |}} 
  
 Der Zeiger auf das Objekt wird ein paar Zeilen nach Beginn der Funktion (Adresse 0x6C3163) mit ''​mov esi, ecx''​ in das Register ESI umgespeichert,​ das behalten wir mal im Hinterkopf: ESI = Zeiger auf oCGame-Objekt. Kurz darauf wird vier mal hintereinander die Funktion ''​zCView::​RemoveItem(zCView *)''​ aufgerufen. Dabei wird in ECX (this) immer der Zeiger auf das globale zCView-Objekt ''​screen''​ gespeichert und als Argument (auch ein Zeiger auf ein zCView-Objekt) wird jeweils ''​ESI+etwas''​ (erst in EAX gespeichert und von da aus) auf den Stack gelegt (''​ESI+8Ch'',​ ''​ESI+90h'',​ ''​ESI+94h''​ und ''​ESI+98h''​). Wir erinnern uns, dass ESI auf das oCGame-Objekt zeigt. Ein Blick in die dokumentierten Klassen aus Ikarus verrät, dass diese Offsets die vier Bars (''​hpBar'',​ ''​manaBar'',​ ''​swimBar'',​ ''​focusBar''​) in der oCGame-Klasse sind! Das scheint also die richtige Stelle; Hier werden alle Bars vom screen-Object entfernt, bevor sie vermutlich gleich darauf aktualisiert neu gezeichnet werden. Der Zeiger auf das Objekt wird ein paar Zeilen nach Beginn der Funktion (Adresse 0x6C3163) mit ''​mov esi, ecx''​ in das Register ESI umgespeichert,​ das behalten wir mal im Hinterkopf: ESI = Zeiger auf oCGame-Objekt. Kurz darauf wird vier mal hintereinander die Funktion ''​zCView::​RemoveItem(zCView *)''​ aufgerufen. Dabei wird in ECX (this) immer der Zeiger auf das globale zCView-Objekt ''​screen''​ gespeichert und als Argument (auch ein Zeiger auf ein zCView-Objekt) wird jeweils ''​ESI+etwas''​ (erst in EAX gespeichert und von da aus) auf den Stack gelegt (''​ESI+8Ch'',​ ''​ESI+90h'',​ ''​ESI+94h''​ und ''​ESI+98h''​). Wir erinnern uns, dass ESI auf das oCGame-Objekt zeigt. Ein Blick in die dokumentierten Klassen aus Ikarus verrät, dass diese Offsets die vier Bars (''​hpBar'',​ ''​manaBar'',​ ''​swimBar'',​ ''​focusBar''​) in der oCGame-Klasse sind! Das scheint also die richtige Stelle; Hier werden alle Bars vom screen-Object entfernt, bevor sie vermutlich gleich darauf aktualisiert neu gezeichnet werden.
Zeile 140: Zeile 152:
 Wir sind aber nicht an der Stelle interessiert,​ wo die Focus-Bar entfernt wird, denn das wird sie scheinbar jedes Frame, sondern wo sie neu gezeichnet wird. Das sollte nämlich nur der Fall sein, wenn der Spieler einen NPC im Fokus hat. Wir sind aber nicht an der Stelle interessiert,​ wo die Focus-Bar entfernt wird, denn das wird sie scheinbar jedes Frame, sondern wo sie neu gezeichnet wird. Das sollte nämlich nur der Fall sein, wenn der Spieler einen NPC im Fokus hat.
 Da ''​[esi+98h]''​ die Focus-Bar referenziert (oCGame* + 0x98 = ''​oCGame.focusBar''​),​ markieren wir ''​esi+98h''​ an Adresse 0x6C31AF. Dank der Highlightingfunktion wird jedes weitere ''​esi+98h''​ auch gelb hervorgehoben. Nach vorsichtigem Herunterscrollen,​ entdecken wir an Adresse 0x6C3707 das ''​esi+98h''​ wieder: Hier wird etwas mit der Focus-Bar gemacht! Da ''​[esi+98h]''​ die Focus-Bar referenziert (oCGame* + 0x98 = ''​oCGame.focusBar''​),​ markieren wir ''​esi+98h''​ an Adresse 0x6C31AF. Dank der Highlightingfunktion wird jedes weitere ''​esi+98h''​ auch gelb hervorgehoben. Nach vorsichtigem Herunterscrollen,​ entdecken wir an Adresse 0x6C3707 das ''​esi+98h''​ wieder: Hier wird etwas mit der Focus-Bar gemacht!
 +
 +{{ :​skripten:​engineforschung:​updateplayerstatus_02.png?​nolink |}}
  
 //Weitere kleine Bemerkung: Das Funktioniert nicht immer, weil die Inhalte der Register manchmal in andere Register verschoben werden. Bei keinem Fund, hätten wir nur ''​+98h''​ markiert (ohne "​esi"​) und gesucht.// //Weitere kleine Bemerkung: Das Funktioniert nicht immer, weil die Inhalte der Register manchmal in andere Register verschoben werden. Bei keinem Fund, hätten wir nur ''​+98h''​ markiert (ohne "​esi"​) und gesucht.//
skripten/engineforschung.1536505806.txt.gz · Zuletzt geändert: 2018/09/09 17:10 von mud-freak