Hallo.
Nachdem ich mich nun seit mehreren Wochen mehr oder weniger intensiv mit Assembler beschäftigt habe und zu dem Thema ergänzend zu Thoralf´s Threads einige Bücher gelesen habe, habe ich mir jetzt seit ein paar Tagen eine kleine Auszeit gegönnt und mehr oder weniger nur am C64 gedaddelt, sofern es die Zeit zugelassen hat.
Neben Summer Games, Winter Games und einigen anderen Klassikern hatte ich mich auch einige Zeit mit dem Spiel Commando beschäftigt, was mir schon immer gut gefallen hat. Zugegeben, das Spiel ist nicht ganz einfach und ich kam auch nie wirklich weit. Die 5 Leben sind schnell verbraucht, aber es macht Spaß und den Sound find ich einfach klasse...
Ich habe hier eine Version, die wohl jemand in 2011 mal mit einem schicken Crack-Intro versehen hat, aber wenn die 5 Leben verbraucht sind, ist man GameOver. Also nichts mit Trainerversion.
Also dachte ich mir, ich mogel einfach ein bißchen und versuche meine neu erworbenen Kenntnisse in Sachen Assembler dazu ein zu bringen. Und siehe da, es hat funktioniert. Mein Erlerntes möchte ich mit euch an dieser Stelle teilen.
Um das ganze zu bewerkstelligen brauchen wir ein Freezer-Modul mit eingebautem Maschinensprachemonitor. In meinem Fall das Retroreplay, welches quasi eine Neuauflage des legendären ActionReplay6 ist. Kleine Zwischenfrage. Wie haben das eigentlich die Jungs in den 80ern gemacht, bevor es Freezer-Module gab ? Hatten die den Speicherinhalt manuell durchsucht oder wurde ein geändertes Kernal mit Monitor benutzt und dann nach einem Warmstart-Reset durchstöbert ??
Mit dem Maschinensprachemonitor sollte man ein wenig vertraut sein. Eigentlich funktionieren alle mir bekannten mit den selben Befehlen. Für unser Vorhaben brauchen wir folgende Befehle:
.x
= Exit
.h aaaa eeee oo xx xx
= hunt-Befehl. Sucht zwischen Speicherbereich aaaa und eeee den opcode oo mit den werten xx xx
zB. Der Befehl LDA #$ 05 entspricht in der Maschinensprache A9 05. Wenn wir LDA #$05 im Speicherbereich von $0801 bis $1FFF suchen wollen, müssen wir eingeben
.H 0801 1FFF A9 05
.m aaaa eeee
= das Programm wird als reines Maschinenspracheprogramm (hexdump) angezeigt von Anfangsadresse aaaa bis Endadresse eeee
.d aaaa eeee
= Dissassembler. Das Programm wird dissassembliert von Anfangsadresse aaaa bis Endadresse eeee.
Zum Spiel.
1. Wir laden das Programm und starten es.
2. Sobald das Spiel beginnt. merken wir uns, wie viele Leben wir haben (es sind 5) und drücken den Freeze button.
3. Mit der Taste M kommt man bei dem Retroreplay jetzt in den Maschinensprachemonitor.
4. Die Programmstartadresse beim C64 ist für gewöhnlich $0801, weil da das freie RAM beginnt. Wie wir wissen, haben wir 5 Leben und diese müssen im Speicher irgendwo hinterlegt sein. Der Akku ist das einzige Register, mit dem man rechnen kann, also gehen wir zu Anfang einfach mal davon aus, dass irgendwo ein LDA #$05 stehen muss, das die 5 Leben in den Akku schreibt, um die später in eine Speicherstelle zu übertragen. Und diese Speicherstelle müssen wir jetzt finden. Als Endadresse habe ich einfach mal die 1FFF gewählt, da solche grundfundamentalen Informationen, wie Anzahl der Leben, Anzahl der Waffen etc. bzw. Sprünge ziemlich am Anfang des Programms liegen sollten.
Wir suchen mit dem Befehl .H 0801 1FFF A9 05
5. Als Ergebnis erhalten wir jetzt die beiden Speicherstellen 08B0 und 1ECD. Der Hunt-Befehl hat uns verraten, dass an diesen 2 Speicherstellen ein LDA #$05 stehen muss. Diese Speicherstellen müssen wir jetzt analysieren. Soviel sei verraten, mit der ersten Speicherstelle werden wir Glück haben. In manchen Fällen stehen da dann 50 Speicherstellen, dann wird es natürlich richtig kompliziert, die richtige zu finden. Aber nicht umsonst haben die Jungs Wochen gebraucht, um bei einigen Spielen mogeln zu können.
6. Der Befehl LDA #$05 sagt uns ja zunächst nur, dass der Wert 05 in den Akku kopiert wird. Interessanter ist die Frage, in welche Speicherstelle der Akku den Wert ablegt. Deswegen müssen wir wissen, was nach dem LDA steht. Wir erwarten ein STA. Deswegen disassemblieren wir nur ein paar Stellen weiter mit dem Befehl
.D 08B0 08B8
und erhalten
08B0 LDA #$05
08B2 STA $04FF
08B5 STA $0500
08B8 LDA #$A5
Wie wir sehen wird unser Wert 05 in die Speicherstellen $04FF und $0500 kopiert und an Adresse 08B8 kommt bereits ein neuer LDA Befehl.
Wir erinnern uns, wir haben im Spiel 5 Leben und 5 Granaten. Hier ist es jetzt so, der Wert in $04FF besagt die Anzahl der Granaten und der Wert in $0500 besagt die Anzahl der Leben.
Wir können jetzt das LDA #$05 durch ein LDA #$99 ersetzen, dann 2 mal return drücken und mit x den Monitor verlassen und mit F3 wieder in das Spiel einsteigen. Nach einmal sterben haben wir 98 Leben und 99 Granaten.
Oder aber wir schauen uns die Speicherstellen an. Das ist interessant, wenn man sich nicht sicher ist. Dann schaut man in die Speicherstelle rein, da steht der Wert 05. Dann lässt man sich einmal sterben und schaut sich erneut den Speicherwert an. Wenn dann da Wert 04 steht, kann man sich sicher sein, dass man das richtige Byte erwischt hat.
Mit
.M 04ff
kann man sich die Speicherstellen direkt im hexdump anzeigen lassen. Da stehen dann 8 bytes:
:04FF 05 05 00 00 00 3F 20 20
Der erste Wert 05 ist Speicherstelle $04FF, die zweite 05 ist Speicherstelle $0500. Diese kann man dann auf jeweils 99 abändern und mit return bestätigen. Dann mit x aus dem Monitor aussteigen und mit F3 wieder in das Spiel einsteigen. Nach einmal sterben hat man 99 Granaten und 98 Leben... :-))
Wie gesagt, ich bin noch absoluter Anfänger bei Assembler. Für mich war das jetzt schon ein großer Schritt. Sicherlich kann man es wesentlich edler machen, in dem man verhindert, dass überhaupt ein Leben abgezogen wird. Dann noch ein Intro davor basteln und so weiter...
Ich wollte hier mal zeigen, wie ich vorgegangen bin und ich bin mir sicher, es ist für den ein oder anderen sehr interessant ?! Wobei man sagen muss, es ist schon schwierig, überhaupt ein C64 Spiel zu finden, das nicht geknackt ist...
Anbei noch ein drittklassiges Handyvideo zu dem Thema.
Gruss Jan