Crack für LOOM / Deutsch

By dose | August 22, 2009
Under: Uncategorized

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:0x1670): Script 203, offset 0x1670: [62] o5_stopScript()
(69:203:0x1672): Script 203, offset 0x1672: [2C] o5_cursorCommand()
(69:203:0x1674): Script 203, offset 0x1674: [2C] o5_cursorCommand()
(69:203:0x1676): Script 203, offset 0x1676: [A8] o5_notEqualZero()
(69:203:0x167B): Script 203, offset 0x167b: [46] o5_increment()
(69:203:0x167E): Script 203, offset 0x167e: [48] o5_isEqual()
(69:203:0x1685): Script 203, offset 0x1685: [2A] o5_startScript()

Nun benötigt man noch einen Vergleichswert, was passiert, wenn man den richtigen Code eingibt:

(69:203:0x1670): Script 203, offset 0x1670: [62] o5_stopScript()
(69:203:0x1672): Script 203, offset 0x1672: [2C] o5_cursorCommand()
(69:203:0x1674): Script 203, offset 0x1674: [2C] o5_cursorCommand()
(69:203:0x1676): Script 203, offset 0x1676: [A8] o5_notEqualZero()
(69:203:0x17C3): Script 203, offset 0x17c3: [48] o5_isEqual()
(69:203:0x17CA): Script 203, offset 0x17ca: [2A] o5_startScript()

Offensichtlich wird also an Offset 0x1676 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.

7 comments | Add One

Comments

  1. Ron - 09/30/2014 at 09:19

    Hmm, komme da irgendwie mit dem “XOR” nicht weiter! Wie macht man denn das genau? Den Eintrag soweit gefunden, weiß aber nicht wie man diesen in ”
    166F: 62 CC 2C 02 2C 04 A8 6F 8D 48 01 46 63 00″ umwandelt und dann natürlich wieder geändert zurück…

    Gut habe leider auch wenig Ahnung davon, wollte nur gerne ebenfalls die Abfrage für mich entfernen 😀

  2. Tom - 08/6/2015 at 00:59

    Wie kommt man auf die neue relative Sprungadresse $4C01?

  3. dose - 08/6/2015 at 11:14

    Little endian! Offset 14C
    Ganz einfach: Kommando steht auf $167B. Instruktionslänge ist 3 Bytes: $167B + 3 = $167E. Wir wollen auf $17CA. 17CA – 167E = 14C
    Alles klar? 🙂

  4. Tom - 10/11/2015 at 23:52

    Achso little endian.. Nun ist alles klar 😉

    Hab’s grad mal ausprobiert mit der englischen Amiga Version von Monkey Island 2.

    Von:
    —–
    Script 130, offset 0x297: [9A] o5_move()
    Script 130, offset 0x29c: [88] o5_isNotEqual()
    Script 130, offset 0x2a3: [14] o5_print()

    Nach:
    ——
    Script 130, offset 0x297: [9A] o5_move()
    Script 130, offset 0x29c: [18] o5_jumpRelative()
    Script 130, offset 0x2c5: [2E] o5_delay()

    Patch:
    @49BCA in monkey2.001:
    71 4F 69 (Xor’ed)

    Danke für deine Tutorials.
    Wie haben das wohl die Leute früher angestellt bevor die SCUMM Details so bekannt waren wie heutzutage..

  5. John - 10/9/2016 at 17:54

    Wenn man das Ganze nun noch mit 0xFF verXORt, so hat man dann einen funktionierenden Crack.

    166F: 9D 33 D3… habe ich gefunden

    Wie würde das fertig aussehen ?
    Bin leider kein Programmierer

Trackbacks

  1. Crack für Monkey Island 1 / Deutsch |hardwarefetish.com
  2. Crack für Indiana Jones 3 (Der letzte Kreuzzug) / Deutsch |hardwarefetish.com

Leave a Comment

Name:

E-Mail :

Subscribe :
Website :

Comments :