Da einige japanische Unternehmen ihr Urheberrecht immer noch sorgfältig überwachen. Ich kann Ihnen weder meine Rum-Version noch die von mir verwendete Quelle zur Verfügung stellen. Ich kann nur sagen, dass ich es in der Torrent-Sammlung "All games on Dendy" gefunden habe. Ich nahm die japanische Version des Spiels "Contra (J) [T + Rus_Chronix]", die von dort ins Russische übersetzt wurde, und ging sie mehrmals durch. Als äußerst neugierige Person entschied ich mich, das ROM-Bild ein wenig herauszusuchen, um den Spielern ein paar Leben zu geben.
Hier ist eine lebendige, langweilige und langwierige Aufzeichnung dieses Prozesses. Um das Spiel zu hacken, habe ich den FCEUX- Emulator verwendet.
Und das sind alles vorbereitende Vorbereitungen, ohne die Bildschirmeinstellungen und das Gamepad.
Das Hacken selbst erfolgt in mehreren Phasen:
- Suchen Sie nach den gewünschten Werten oder vielmehr nach den Variablen, in denen sie gespeichert sind, oder nach Adressen, die die gewünschten Werte enthalten
- Suchen Sie nach Anweisungen, die diese Werte ändern oder lesen, je nachdem, was Sie interessiert
- Analyse von Codeblöcken, die diese Anweisungen enthalten
- Ändern von interessierenden Codeblöcken, gefolgt vom Schreiben in eine ROM-Datei
Wenn das Ergebnis der Analyse der Codeblöcke andere Adressen sind, müssen die Punkte 2 und 3 wiederholt werden. Weiter werde ich diesen Moment zeigen.
Um nach Werten im Speicher zu suchen, wird das im Emulator integrierte Tool "RAM search" verwendet.

Ich weiß nicht, ob in Spielen für NES Verschlüsselung verwendet wurde, aber ich bin immer noch nicht auf solche Spiele gestoßen. Und auf dem Bildschirm nach dem Begrüßungsbildschirm und vor dem Start des Levels sah ich die Anzahl der Leben "drei".

Also habe ich mit den drei die Suche gestartet.
Der Vergleichsoperator "gleich", ich vergleiche mit einem bestimmten Wert von "3" und klicke nicht vor Beginn des Levels auf die Suchschaltfläche. Theoretisch ist dies für das NES-Spiel nicht wichtig, aber ich ziehe es vor, die Suche zu wiederholen und zu starten, nachdem ich sicher bin, dass der gewünschte Wert an seiner Stelle im Speicher liegt, dh nach dem Beginn des Levels selbst.
Das Suchen nach Adressen ist sehr routinemäßig. Sie müssen die verschiedenen Werte außer der Suche geringfügig ändern, die Suche wiederholen usw. Übrigens ändert sich im Moment der Sinn des Lebens in keiner Weise und Sie können alle Werte löschen, die sich in letzter Zeit mehrmals geändert haben. Es ist jedoch besser, dies zu tun, wenn Sie das Suchfenster nach dem Start des Levels öffnen oder wenn Sie die Suche vor dem ersten Vergleich, aber nach dem Beginn des Levels zurücksetzen. Anschließend können Sie den gewünschten Wert ändern (in diesem Fall das Zeichen beenden) und im Vergleichsfeld einen neuen Wert festlegen usw., bis eine Variable übrig bleibt.
Aber ich habe danach keine Variablen mehr und es kann zwei Gründe dafür geben:
- menschlicher Faktor, mit anderen Worten, ich habe einen Fehler im Suchprozess gemacht
- In der für das Leben verantwortlichen Variablen liegt etwas anderes
Wir werden die erste Option später verschieben, nicht dass ich selten Fehler machen würde. Ich beginne die Suche immer mit Überprüfungen von allem anderen. Ich bin so selbstbewusst.
Und bevor Sie über einen Plan zur Umgehung der gerissenen Verschlüsselung nachdenken, schauen Sie noch einmal auf den Bildschirm.

Der Spieler hat drei Leben und zwei Medaillen hängen über ihm. Wenn ein Spieler drei Leben hat, wird möglicherweise der Wert „zwei“ (zwei freie Leben) in seinem Gedächtnis aufgezeichnet. Als ich das Spiel zurücksetzte und eine neue Suche startete, bereits mit der Anzahl der Medaillen und zwei Spielern, fand ich fast sofort zwei Adressen mit geeigneten Werten.

Dies sind 32 16 und 33 16 Adressen. Der einfachste Weg, die gefundene Adresse zu überprüfen, besteht darin, ihren Wert zu ändern. Dazu benötigen Sie das im Emulator integrierte HEX Editor-Tool. Im RAM-Suchfenster können Sie es öffnen, indem Sie mit der rechten Maustaste auf die Adresse klicken, damit Sie diese Adresse im Speicher öffnen. Und als ich die Adresse „vier“ auf 32 16 setzte, sah ich, wie sich der Bestand des ersten Spielers veränderte, und als ich ihn auf 33 16 setzte, veränderte ich das Leben des zweiten Spielers.
Der langweiligste und routinemäßigste Teil der Arbeit ist erledigt. Mit der Schaltfläche "Überwachen" können Sie dem zur Überwachung der Werte erstellten Fenster "RAM-Überwachung" eine Adresse hinzufügen. In meinem Fall, damit sich der Computer an die von mir benötigten Adressen erinnert, ist mein Speicher voller Löcher, die ich vergessen werde. Diese Variablen werden übrigens im statischen Speicher des Emulators gespeichert. Sobald Sie sie gefunden haben, können Sie sie jederzeit verwenden, ohne befürchten zu müssen, das Spiel, den Emulator und sogar den Computer neu zu starten.
In der zweiten Phase müssen Sie nach Funktionen / Unterprogrammen / Codeblöcken suchen (unterstreichen Sie Ihren Favoriten), die diese Werte ändern. Wenn das Spiel nicht von Dummköpfen erstellt wurde, sondern zu Beginn des Spiels des Lebens, erhalten beide Spieler eine Unterroutine, aber ohne dies vorher zu wissen, werden solche Dinge am besten überprüft. Zu diesem Zweck ist im Emulator ein Debugger eingebaut, das Fenster "Debugger".

Und dies ist wahrscheinlich das schwierigste Fenster im Emulator. Formal kann es in zwei Teile unterteilt werden: Ein großes Feld links zeigt den gesamten Inhalt des Speichers, der ihn in Opcodes mit Parametern / Argumenten aufteilt, und schreibt entsprechende Mnemoniken in der Nähe. Und in der rechten Hälfte wird sich der Teufel auf den ersten Blick das Bein brechen. Obwohl es nichts Kompliziertes gibt, müssen Sie nur alles sorgfältig lesen und, wenn möglich, daran denken. Hier interessiert mich vor allem das Feld "Haltepunkte", in dem Sie über die Schaltfläche "Hinzufügen" Haltepunkte zu den Adressen hinzufügen können. Um herauszufinden, welche Anweisungen Daten an diese Adressen schreiben, habe ich das Kontrollkästchen "Schreiben" aktiviert.

Das Setup ist fertig.
Sie können das Spiel neu starten und sehen, welche Anweisungen, von welchen Unterroutinen und welche Werte an diese Adresse geschrieben werden. Wenn Sie daran denken, dass ich daran interessiert bin, eine Zwei an diese Adresse zu schreiben, können Sie alle Unterprogramme, die dort Nullen schreiben, ignorieren. Um das Programm nach dem Stoppen fortzusetzen, klicken Sie im Debugger-Fenster auf die Schaltfläche "Ausführen".
Und schließlich ein interessanter Code.
Adresse | Opcode | Mnemonik | Argumente | A. | X. | Y. |
---|
C2E7 | 85 39 | STA | $ 0039 | ?? | 00 | ?? |
C2E9 | A9 02 | Lda | # $ 02 | ?? | 00 | ?? |
C2EB | A4 24 | LDY | $ 0024 | 02 | 00 | 00 |
C2ed | F0 02 | BEQ | $ C2f1 | 02 | 00 | 00 |
C2EF | A9 1D | Lda | # $ 1D | 02 | 00 | 00 |
C2f1 | 95 32 | STA | $ 32, X. | 02 oder 1D | 00 | 00 |
C2f3 | CA. | Dex | | 02 oder 1D | 00 | 00 |
C2f4 | 10 F3 | Bpl | C2E9 | 02 oder 1D | Ff | 00 |
C2F6 | A9 C8 | Lda | # $ C8 | 02 oder 1D | Ff | 00 |
C2f8 | 85 3C | STA | $ 003C | 02 oder 1D | Ff | 00 |
Die durchgestrichenen Anweisungen interessieren mich nicht, weil Sie arbeiten bereits mit völlig unterschiedlichen Adressen. Und ich werde die Anweisungen, die mich interessieren, im Detail betrachten. Die Adresse C2E9 16 enthält den Opcode A9 16 , der den Wert in Register A schreibt. Sie entspricht der lesbaren Abkürzung LDA "LoaD A", was das Schreiben in Register A bedeutet. Diese Abkürzung entspricht acht Opcodes, und speziell A9 16 bedeutet, dass der Wert selbst in das nächste Byte geschrieben wird . Zusätzlich zum Wert selbst kann die Adresse übertragen werden, von der der Wert übernommen werden soll. Sie können hier mehr über Opcodes, hier über Mnemonik (für Menschen lesbare Abkürzungen) lesen und diese Assemblersprache hier ausführlich studieren (obwohl warum?). Jetzt können Sie mit Wissen den Rest der Anweisungen entschlüsseln. Nur der Debugger im Emulator ist etwas unaufrichtig und in der Adresse C2EB 16 wird der LDY $ 0024-Befehl angezeigt. Tatsächlich ist dieser Befehl jedoch als LDY $ 24 geschrieben. Beide Datensätze bedeuten dasselbe, aber der erste, der auf den Opcode übertragen wird, benötigt ein Byte mehr und sieht aus wie AC 24 00. Es kann auch Fragen zu der Anweisung in C2ED 16 geben . Diese Verzweigungsanweisung funktioniert, wenn sie gleich ist, aber nichts wird vorher verglichen. Wie funktioniert sie? Eigentlich sehr einfach, liest dieser Befehl nur das Null-Flag des Statusregisters. Die Vergleichsanweisung in der Assemblierung subtrahiert einen Wert von einem anderen, ohne das Ergebnis irgendwo zu schreiben, sondern ändert die Flags des Statusregisters. Weil Verzweigungsbefehle nur Flags lesen. In diesem Fall setzt der LDY-Befehl von der Adresse C2EB 16 in das Register Y die Null, die zuvor in die Adresse 0024 16 geschrieben wurde, und setzt die Einheit in das Null-Flag, da das Ergebnis der letzten Operation Null war. Und der Verzweigungsbefehl ignoriert alles außer dem Zustand des Null-Flags und springt, wenn er eine Einheit sieht, vom Beginn des darauf folgenden Befehls 2 Bytes vorwärts, dh zur Adresse C2EF 16 + 2 16 = C2F1 16 . An dieser Adresse in Register A ist 2 16 oder 1D 16 , abhängig davon, ob der Sprung gemacht wurde oder nicht, der Sprung war und daher gibt es eine Zwei im Register. Es fällt in die Adresse 32 16, die im Wert des Registers X eingerückt ist, dh 0032 16 + 00 16 = 0032 16 . Der folgende DEX-Befehl reduziert den Wert des Registers X um 1, indem der Wert FF 16 darauf geschrieben wird . Denken Sie daran, dass in der 8-Bit-Arithmetik mit Vorzeichen die Werte (00 16 - 7F 16 positiv und die Werte (80 16 - FF 16 ) negativ sind. Dies ist das Vorzeichen der Zahl, die der BPL-Befehl überprüft, und wenn die Zahl positiv ist, wird die Ausführung an C2E9 16 zurückgegeben. F3 16 = - 13 10 = -D 16 , C2F6 16 - D 16 = C2E9 16. Hier können wir annehmen, dass irgendwo früher im Code im Register X 0 geschrieben wurde, wenn das Spiel für einen Spieler ist, oder 1, wenn das Spiel für zwei ist. Offensichtlich hat der zweite Spieler bereits seine erhalten Teil der Leben auf der vorherigen Iteration des Zyklus (C2E9 16 - C2F4 16 ), und der Adressmonitor zeigt dies, an Adresse 0033 16 gibt es eine Zwei. Der Code oben in der Adresse C2DD 16 zeigt den Datensatz im Register X des Werts von der Adresse 0022 16 an . Wenn Sie einen Haltepunkt zum Schreiben an diese Adresse festlegen und prüfen, wann und was dort geschrieben ist, können Sie sehen, dass sich der Wert in dieser Adresse wirklich auf 0 ändert, wenn der Spieler alleine ist und 1, wenn es zwei Spieler gibt. Ich habe diesen Moment erkannt. Jetzt müssen Sie den Datensatz herausfinden. Eine offensichtliche Entscheidung, das Argument 99 10 = 63 16 in Adresse C2E9 16 an den A9-Opcode zu übergeben, aber wenn der Spieler den Konami-Code eingibt?
Ich musste einen schwierigeren Weg gehen.
Die Idee ist folgende: Der von Konami eingegebene Code kann nicht abgebrochen werden. Dies bedeutet, dass Sie das Spiel davon überzeugen können, dass der Code bereits eingegeben wurde, und den Wert 99 10 in das Argument der Anweisung von der Adresse C2EF 16 eingeben können, die funktioniert, wenn der Code von Konami eingegeben wird. Es ist mir also garantiert, dass beide Spieler 99 99 freie Leben eingeben, unabhängig davon, ob sie den Code eingegeben haben oder nicht. Es klingt einfach genug und ich begann mit der Analyse der Adresse 0024 16 , von wo aus das Spiel „Konami-Code“ liest, den Haltepunkt für das Schreiben an diese Adresse festlegte und zum nächsten Codeblock gelangte.
Adresse | Opcode | Mnemonik | Argumente | A. | X. | Y. |
---|
F95b | 91 00 | STA | ($ 00), Y. | 00 | ?? | 24 oder 23 ... oder FF |
F95d | 88 | DEY | | 00 | ?? | 24 oder 23 ... oder FF |
F95E | C0 FF | CPY | $ Ff | 00 | ?? | 23 oder 22 ... oder FF |
F960 | D0 F9 | Bne | $ F95B | 00 | ?? | 23 oder 22 ... oder FF |
Nachdem ich es sorgfältig gelesen hatte, kam ich zu dem Schluss, dass dieses Unterprogramm den Adressbereich aufhebt, was bedeutet, dass es nicht zu mir passt. Nichts berührte diese Adresse im Player-Auswahlbildschirm. Wo der "Konami-Code" selbst das Gerät unter dieser Adresse notiert hat. Daher schlägt das einfache Ändern des Werts in der Adresse 0024 16 fehl. Dann können Sie den Anweisungen etwas mehr Aufmerksamkeit schenken:
Adresse | Opcode | Mnemonik | Argumente | A. | X. | Y. |
---|
C2EB | A4 24 | LDY | $ 0024 | 02 | 00 | 00 |
Wie oben geschrieben, schreibt es den Wert von der Adresse 0024 16 in das Register Y und es ist bereits klar, dass es nicht möglich ist, den Wert dieser Adresse leicht zu ändern. Warum ändern Sie dann nicht den Wert des Registers selbst? Ändern Sie dazu den Opcode A4 16 in den Opcode A0 16 und übergeben Sie einen anderen Wert als Null mit einem Argument. Kaum gesagt als getan, aber dann entsteht ein anderes Problem. Nachdem ich den "HEX-Editor" geöffnet habe (Sie tun dies nicht über den Debugger, Sie müssen das Fenstermenü verwenden), kann ich diesen Opcode nicht ändern. Die Erklärung ist sehr einfach, das Spiel verwendet das sogenannte Mapping. Technologie, mit der Sie Konsolenspiele mit einem größeren Volumen ausführen können, als die Konsole akzeptieren kann. Es funktioniert, indem die realen ROM-Adressen durch die Adressen ersetzt werden, die dem Prozessor zur Verfügung stehen, und die Teile übergeben werden, die das Spiel gerade benötigt, um es zu verarbeiten. Das heißt, die Adresse, die ich im Debugger sehe, stimmt nicht mit der tatsächlichen Adresse im ROM überein, und ich habe keine Ahnung, wo ich nach dieser Anweisung im ROM suchen soll. In diesem Moment beginnt der ausgewählte Emulator zu leuchten, da ich jetzt nur noch mit der rechten Maustaste auf den Opcode klicken und "Hier in ROM-Datei gehen" auswählen muss. Dadurch werde ich zu derselben Anweisung im ROM selbst weitergeleitet, in die ich den Opcode sicher ändern kann neue Bedeutung. Genauso habe ich das Argument der Anweisung geändert:
Adresse | Opcode | Mnemonik | Argumente | A. | X. | Y. |
---|
C2EF | A9 1D | Lda | # $ 1D | 02 | 00 | 00 |
Von 1D 16 bis 63 16 . Natürlich speichere ich das Ergebnis in einer neuen Datei, denn wenn ich nicht den gesamten Schutz des Spiels umgangen habe, habe ich nur das ROM kaputt gemacht und möchte nicht ohne ein funktionierendes Original zurückbleiben.
PS: Ich entschuldige mich für das mehrteilige und gründliche, vielleicht zu gründliche Kauen. Bereit, Kritik, Kommentare und Korrekturen anzunehmen. Vielen Dank, dein Victor.