Crack für LOOM / Deutsch
Beim Stöbern in meinen alten DOS-Spielen bin ich unlängst wieder auf das bekannte Adventure LOOM gestoßen. Der “Kopierschutz” des Spiels besteht aus einem Doccheck, also der Abfrage von bestimmten Werten, welche im Handbuch abgedruckt sind.
Nachdem es doch etwas lästig ist, immer im Handbuch nachzuschlagen, wurde mein sportlicher Ehrgeiz geweckt und ich habe mich daher etwas näher mit der SCUMM-Engine beschäftigt. Nachdem der nachgebaute SCUMM-Interpreter SCUMMVM die Handbuchabfrage auch umgeht (zumal der Hersteller dies bei einigen Versionen sogar selbst gemacht hat) habe ich hier eigentlich keine Bedenken, meine Untersuchungsergebnisse zu veröffentlichen.
Mithilfe der SCUMMVM kann man im Debug-Modus die interpretierten VM-Kommandos mitschreiben lassen und bekommt damit ungefähr eine Idee, wo die Abfrage für den Kopierschutz zu finden ist. Zuerst muss SCUMMVM mitgeteilt werden, dass sie den Kopierschutz nicht umgehen soll, sonst wird dieser stillschweigend übersprungen. Dies geschieht mittels des Eintrags copy_protection=true in %APPDATA%\ScummVM\scummvm.ini Danach kann man die Ausgabe von SCUMMvm auf STDOUT in eine Protokolldatei umleiten, indem man scummvm >log.txt startet. Jetzt muss noch der DEBUG-Modus aktiviert werden, damit die Kommandos mitgeschrieben werden. Dies geschieht mit CRTL+D. Auf der Debug-Konsole aktiviert man die Protokollierung mittels debug +opcodes Nun noch ein continue und einmal den falschen Code eingegeben. Analysiert man das Protokoll, so erkennt man folgende Abfrage:
(69:203:0×1670): Script 203, offset 0×1670: [62] o5_stopScript()
(69:203:0×1672): Script 203, offset 0×1672: [2C] o5_cursorCommand()
(69:203:0×1674): Script 203, offset 0×1674: [2C] o5_cursorCommand()
(69:203:0×1676): Script 203, offset 0×1676: [A8] o5_notEqualZero()
(69:203:0×167B): Script 203, offset 0×167b: [46] o5_increment()
(69:203:0×167E): Script 203, offset 0×167e: [48] o5_isEqual()
(69:203:0×1685): Script 203, offset 0×1685: [2A] o5_startScript()
Nun benötigt man noch einen Vergleichswert, was passiert, wenn man den richtigen Code eingibt:
(69:203:0×1670): Script 203, offset 0×1670: [62] o5_stopScript()
(69:203:0×1672): Script 203, offset 0×1672: [2C] o5_cursorCommand()
(69:203:0×1674): Script 203, offset 0×1674: [2C] o5_cursorCommand()
(69:203:0×1676): Script 203, offset 0×1676: [A8] o5_notEqualZero()
(69:203:0×17C3): Script 203, offset 0×17c3: [48] o5_isEqual()
(69:203:0×17CA): Script 203, offset 0×17ca: [2A] o5_startScript()
Offensichtlich wird also an Offset 0×1676 in der Datei 69.lfl auf die Gültigkeit der Eingabe geprüft und dementsprechend erfolgt dann ein Sprung ins Spiel.
Sucht man nun an besagtem Offset die von SCUMMvm gelisteten Kommandos, so wird man nicht wirklich fündig:
166F: 9D 33 D3 FD D3 FB 57 90 72 B7 FE B9 9C FF B7
Merkwürdig… Des Rätsels Lösung findet sich dann nach einigem Suchen im SCUMMVM Wiki: In der Version V3 OldBundle, welche das Spiel benutzt, sind die Dateien mit 0xFF verXORt. Also einfach mal mit XOR arbeiten, und siehe da:
166F: 62 CC 2C 02 2C 04 A8 6F 8D 48 01 46 63 00
Rot sind hier die einzelnen Kommandos wie oben beschrieben. Wenn also die Variable 6F 8D nicht 0 ist, dann wurde der Code falsch eingegeben und er wiederholt die Abfrage. Das Ziel ist es also, die Variable 6F D8 auf 0 zu setzen und das Spiel anschließend zu starten. Mithilfe der SCUMM Opcodeliste tauscht man nun das o5_notEqualZero gegen ein o5_move und füllt die Variable mit 0. Weiters kann man sich aus den Aufzeichnungen des Vorgangs, bei welchem der Code angenommen wurde, den Offset zum Sprungziel errechnen und entsprechend ein o5_jumpRelative Kommando einfügen, um das Spiel starten zu lassen. Und schon hat man den Kopierschutz “ausgehebelt”.
Gepatcht ergeben sich dann also folgende Opcodes:
166F: 62 CC 2C 02 2C 04 1A 6F 8D 00 00 18 4C 01
Die blauen bytes sind hierbei die geänderten Bytes. Wenn man das Ganze nun noch mit 0xFF verXORt, so hat man dann einen funktionierenden Crack.
System programmer
Comments
Trackbacks