Heroes of Might und Magic IV: Tavernenfehler oder Patching-Klassiker

Diese Kurzgeschichte beschreibt eines der Projekte des Equilibris-Projekts , eines inoffiziellen Mods für Heroes of Might und Magic IV. Sowohl aus Sicht des Reverse Engineering als auch des Patches ist es nicht von besonderem Interesse - nur das Ende erwies sich als etwas witzig.



Bild


Wie Sie wissen, kann der Spieler in dieser Reihe von Spielen in jeder Taverne nur einen neuen Helden pro Woche einstellen. Aber…



Fehlerbeschreibung: Wenn in der externen Taverne keine Rekrutierung stattgefunden hat, können Sie ab dem 8. Tag innerhalb von zwei Tagen zwei Helden kaufen.



Die zerlegte Datei Heroes4.exe aus dem neuesten offiziellen Addon "Winds of War" wird für die Arbeit verwendet. Das Tavernenbetriebsverfahren wurde vom Team früher gefunden und befindet sich unter der Adresse 4705E0. Nach dem gesamten Algorithmus seiner Arbeit interessiert mich der Ort, an dem festgestellt wird, ob es derzeit möglich ist, einen Helden in der Taverne zu mieten, oder ob es notwendig ist, zu warten. Im Spiel manifestiert sich dies in der Ausgabe der entsprechenden Nachricht:





Aus programmatischer Sicht ist dies ein neues Fenster, das im Spiel mit der Funktion NewWindowCreate (720C80) erstellt wird (die im Disassembler erkannten Funktionen erhalten ihre eigenen Namen). Es gibt mehrere Aufrufe dieser Funktion in der Prozedur der Taverne, und der erste Herausforderer ist ein Aufruf an die Adresse 470823. Mit Hilfe des Debuggers stelle ich sicher, dass dieser Aufruf tatsächlich das gewünschte Dialogfeld erstellt. Der Code, der diesen Aufruf von NewWindowCreate steuert, befindet sich oben unter 470645:



00470638                 call    HeroesPricesInTavern_Lost
0047063D                 mov   al, [ebp+48h]  // 0 –   ; 1 –     ( 7 ).
00470640                 add     esp, 8
00470643                 test    al, al
00470645                jz      loc_470866 //   ,      470823


Ich kaufe in der Taverne des Helden und setze dann den "Haltepunkt", um in die an [ebp + 48h] adressierte Zelle zu schreiben. Danach warte ich 7 Tage im Spiel. Wenn die Taverne "geleert" ist, erscheint der Debugger unter der Adresse 470DFF. Sehen wir uns den umgebenden Code an:



00470DF0 TavernCountDays proc near               
00470DF0                 mov     dl, [ecx+48h] // ECX+48h –   :
DL=0 –   ;
DL=1 –     ( 7 )
00470DF3                 xor     eax, eax 
00470DF5                 cmp     dl, al
00470DF7                 jz      short loc_470E06
00470DF9                 cmp     dword ptr [ecx+4Ch], 7 //  [ECX+4Ch] -         .   7 – . 
00470DFD                 jl      short loc_470E06
00470DFF                mov     [ecx+48h], al  //   (AL=0)
00470E02                 mov     [ecx+4Ch], eax  //   
00470E05                 retn
00470E06
00470E06 loc_470E06:                             
00470E06                                         
00470E06                 inc     dword ptr [ecx+4Ch] //          
00470E09                 retn
00470E09 TavernCountDays endp


Diese kurze Prozedur überprüft die Anzahl der Tage, an denen die Taverne zur Miete geschlossen ist. Beachten Sie, dass es an jedem Spieltag für jede Taverne auf der Karte aufgerufen wird. Was verursacht den Fehler? Aus irgendeinem Grund zählt das Programm weiterhin die Anzahl der Tage, an denen der Held nicht in der Taverne eingestellt wurde und nach der Woche, in der die Taverne geschlossen wurde (siehe Schalter bei 470E06). Als Ergebnis erhalten wir das folgende Bild. Lassen Sie die erste Rekrutierung des Helden erst am achten Spieltag stattfinden. Am Eingang des Verfahrens ist der Wert des Tavernenverfügbarkeitsflags bei [ecx + 48h] gleich "1" (die Taverne ist geschlossen) und der Wert des Tageszählers bei [ecx + 4Ch] gleich "8". Nach dem Vergleich bei 470DF9 erhält die Steuerung jedoch bei 470DFF einen Code, der die Taverne zum Mieten wieder öffnet! Dadurch wird der Tageszähler zurückgesetzt.und nach der Einstellung des zweiten Helden wird der Algorithmus bereits wie von den Autoren beabsichtigt funktionieren. Aber nach zwei Wochen im Spiel wiederholt sich der gesamte Zyklus.



Der einfachste Weg, um den Fehler zu beheben, besteht darin, die Tage nicht mehr zu zählen. Lassen Sie den Zähler nur funktionieren, wenn die Taverne geschlossen ist (was logischer ist), und den Rest der Zeit setzen wir ihn auf Null. Dies wird sehr einfach erreicht - durch Ändern des Übergangs an der Adresse 00470DF7 zum Ende der Funktion:



00470DF5                 cmp     dl, al
00470DF7                 jz      short loc_470E09


Jetzt müssen Sie nur noch den vorhandenen Code patchen. Schauen Sie sich dazu das Original an





und modifiziert





Optionen.



Wie Sie sehen können, kann das gewünschte Ergebnis erzielt werden, indem 0D durch 10 an der Adresse 470DF8 ersetzt wird. Ein Klassiker des Genres: Beheben Sie einen Fehler, indem Sie nur ein Byte ersetzen!



All Articles