Une histoire de piratage d'un jeu classique Dendy ou Contra avec spreadgan au début

Depuis mon dernier article , à ma grande surprise, vous avez intéressé. J'ai décidé de compléter son résultat, une version piratée du jeu "Contra (J) [T + Rus_Chronix]", avec un peu de fonctionnalité, montrant en même temps "injection de code" sur NES. Cette fois, je ferai démarrer le jeu avec le Spreadgun pompé, pour l'obtenir dans le jeu, vous devez sélectionner l'icône "S", puis "R".



Bienvenue à tous sous cat.


Traditionnellement:


enregistrement vidéo ennuyeux et fastidieux du processus

Et nous planifions traditionnellement la séquence d'actions.


  1. Rechercher des adresses
  2. Découvrez la valeur du fusil à pompe
  3. Découvrez ce qu'il écrit à ces adresses au début du jeu
  4. Réécrire la ROM
    • Easyway - changez la valeur de l'arme de base en spreadgan pompé
    • Hardway - utilisez une injection de code complète si la méthode simple échoue
  5. enregistrer le résultat dans un nouveau fichier

Pour rechercher des adresses, nous utilisons la méthode décrite précédemment, mais en nous souvenant que des vies se trouvaient dans des adresses voisines, nous ne chercherons des armes que du premier joueur dans l'espoir que le deuxième joueur sera à proximité. En ouvrant la fenêtre "Ram watch" après le début du premier niveau, nous recherchons une valeur inconnue. Je crois que l'arme de base est réglée sur 0, mais je n'en suis pas sûr.
Nous courons le long du niveau sans courir devant, tirons dans toutes les directions et éliminons les valeurs changeantes. L'arme n'a pas encore changé.


Utilisons une autre option de fenêtre, ou plutôt, dans le champ "Compare To / By", mettant en évidence la fréquence radio "Number of Changes", mis dans le champ 0. Le type de comparaison est bien sûr "Equals to". L'arme n'a toujours pas changé.


Ainsi, en sautant de l'option "égal à la valeur précédente" à l'option "le nombre de modifications est de 0", vous pouvez atteindre environ 10 000 adresses. Lorsque de nouvelles projections réduiront la liste d'adresses trop légèrement ou pas du tout, on peut avancer assez loin pour éliminer la première arme.


Après l'avoir ramassé, nous utilisons immédiatement la méthode de recherche "non égale à la valeur précédente", et réduisons encore la liste en recherchant "le nombre de changements est 1", l'arme a changé exactement une fois.


À l'endroit où nous récupérons notre première arme, un amplificateur d'arme apparaît également. Après l'avoir sélectionné et récupéré, vous pouvez réduire le nombre d'adresses à 1, mais si cela ne fonctionne pas, tuez simplement votre personnage et changez ainsi d'arme à nouveau. (N'oubliez pas la recherche après chaque changement).


Avec un amplificateur d'arme, il y a un certain risque qu'il ne change pas la valeur de l'arme elle-même, mais le drapeau ailleurs en mémoire, mais espérons que les auteurs du jeu auront économisé de la mémoire et des instructions. Et, j'ai eu la chance que le bonus "R" change la valeur même de l'arme et l'adresse était en coordonnée AA 16 . (Je peux me tromper, mais j'ai surveillé à plusieurs reprises l'arme du héros dans différentes versions du jeu Contra, comme partout où cette adresse était AA 16 ).


J'ai également remarqué que le bonus "R" augmentait la valeur de l'adresse de 16 10 ou 10 16 , c'est-à-dire augmentait de 1 le premier chiffre du nombre hexadécimal.


Après le redémarrage dans la fenêtre "Ram watch", on peut voir que la valeur de base est vraiment 00 16 , le bonus "M" a augmenté le deuxième chiffre de 1, et le bonus "R" le premier.


Vous pouvez opter pour un spreadgan, il se réunira certainement à ce niveau, ou vous pouvez changer la valeur de l'adresse pour voir quels nombres, quelles armes ils créent. Empiriquement, j'ai découvert que, 01 16 est "Machinegun", 02 16 est "Fire", 03 16 est "Spreadgun" et 04 16 est "Laser". Lorsque vous entrez d'autres valeurs dans le deuxième chiffre, divers problèmes se produisent.


Après avoir réinitialisé le jeu et entré la valeur 1x 16 (où "x" est l'une des options acceptables) avant de sélectionner le bonus "Rapide", vous pouvez découvrir que la nouvelle sélection du bonus ne change rien.


Vous pouvez maintenant redémarrer le jeu, démarrer le jeu à deux et essayer de changer les adresses adjacentes à AA 16 . (Il y en a deux, la recherche ne sera pas longue) Ayant abattu le deuxième joueur, j'ai très vite découvert que les armes du deuxième joueur sont vraiment stockées à proximité à l'adresse AB 16 . Et maintenant que nous connaissons les adresses qui nous intéressent et la valeur qui devrait y être mise, il est temps de découvrir ce qu'il écrit à ces adresses.


En jetant un point d'arrêt sur l'enregistrement de cette adresse, j'ai découvert que l'enregistrement s'y produit plusieurs fois et l'un d'eux après l'écran de démarrage. Le code suivant fait cette entrée:


AdresseOpcodeMnémoniqueArgumentsUnX
C307A2 28LDX# 28 $????
C309A9 00Lda# $ 00??28 ou 29 ou ... ou F0
C30B95 00STA00 $, X0028 ou 29 ou ... ou F0
C30dE8Inx0028 ou 29 ou ... ou F0
C30eE0 F0CPX# $ F00029 ou 30 ou ... ou F0
C310D0 F9Bne30 milliards de dollars0029 ou 30 ou ... ou F0

Si vous lisez attentivement le jeu ici, la plage d'adresses va de 0028 16 à 00F0 16 , évidemment les deux adresses qui nous intéressent dans la plage. Il n'y aura donc pas de moyen facile. Je vais devoir utiliser "Code Injection" et la solution la plus simple que je vois pour savoir d'où nous venons d'ici, rediriger l'exécution vers un endroit libre de code et de données en mémoire, y écrire ma version de la boucle occupant toute la plage sauf les adresses 00AA 16 et 00AB 16 et renvoyant le chariot exécution en arrière. Au fait, c'est la version la plus classique de l'injection. Vous pouvez également supposer que nous arrivons ici à partir de l'instruction JSR (Jump to SubRoutine), c'est facile à vérifier avec la pile.


Comment fonctionne la pile?

Dans les processeurs 6502, la pile est toujours située dans la plage d'adresses 0100 16 - 01FF 16 pour tous les ordinateurs basés sur ce processeur, et passe d'une adresse plus grande à une plus petite. Il y a un registre séparé pointant vers le haut de la pile, initialement il est égal à FF 16 puisqu'un octet plus significatif ne change jamais. Le registre lui-même indique toujours l'octet le plus haut occupé par les données utiles.


Le débogueur d'émulateur n'affiche pas la valeur du registre "Stack Pointer", il indique plutôt l'adresse à laquelle se réfère le registre et en ce moment c'est 01F2 16 , des calculs simples montrent que les dernières données de la pile sont C3 16 et C2 16 , ce qui pourrait conduire Je pense à l'adresse C3C2 16 mais 6502 est un processeur de type "Little Endian", et donc, lors de l'exécution d'instructions et du stockage de l'adresse en mémoire ou sur la pile, l'octet le moins significatif est écrit en premier. Et si l'adresse est vraiment en haut de la pile, c'est l'adresse C2C3 16 . Et c'est l'adresse du dernier argument de l'instruction JSR, si, encore une fois, c'est une adresse du tout. C'est très facile à vérifier, il suffit de regarder ce qui est écrit deux octets au dessus de l'adresse C2C3 16 .


AdresseOpcodeMnémoniqueArguments
C2C120 07 C3JsrC307 $

Comme vous pouvez le voir, il s'agit d'une instruction JSR pour C307 16 , ce qui signifie que l'hypothèse de sous-programme est correcte.


Vous devez maintenant écrire correctement le code d'injection, trouver un endroit approprié pour lui, l'écrire à cet endroit et rediriger l'instruction JSR vers cette injection.


Sites d'aide

Opcodes , instructions , beaucoup d'informations sur l' assemblage 6502 .


Pour cela, il est très pratique d'utiliser un bloc-notes, j'ai du code Visual Studio pour cela. Chacun a son propre style d'écriture, personnellement, je suis le premier à écrire une instruction JSR avec son adresse, afin de savoir où changer et un opcode complet, afin de savoir quoi changer.


Après quelques retraits, je duplique le code de la boucle, il peut déjà être utilisé sans adresses, mais il est extrêmement utile de voir les mnémoniques avec des arguments autres que les opcodes, et il est utile de saisir l'instruction suivant cette boucle avec l'adresse pour savoir où retourner de l'injection.


C2C1:20 07 C3 JSR $C307 A2 28 LDX #$28 A9 00 LDA #$00 95 00 STA $00,X E8 INX E0 F0 CPX #$F0 D0 F9 BNE $C30B C312:A2 07 LDX #$07 

Quelques tirets ci-dessous, vous pouvez écrire le code de l'injection elle-même, en fait c'est un doublon du cycle lui-même avec quelques ajouts.


 C312:A2 07 LDX #$07 A2 28 LDX #$28 A9 00 LDA #$00 95 00 STA $00,X E8 INX E0 AA CPX #$AA D0 F9 BNE -7 A9 13 LDA #$13 95 00 STA $00,X E8 INX E0 AC CPX #$AC D0 F9 BNE -7 A9 00 LDA #$00 95 00 STA $00,X E8 INX E0 F0 CPX #$F0 D0 F9 BNE -7 

Pour plus de clarté, j'ai indiqué le retrait au lieu de l'adresse de l'emplacement du saut.


Si vous ne pouviez pas lire ce code

Voici le même cycle, mais divisé en trois parties, dans le premier cycle, nous comparons le registre X avec la valeur AA 16 , car nous devons mettre à zéro toutes les adresses à l'adresse 00AA 16 , après avoir mis 13 16 dans le registre A, la valeur du spreadgan pompé et écrire le deuxième cycle à l'adresse 00AC 16 à partir de laquelle le reste de la plage doit être remis à zéro. Nous revenons au registre A zéro et mettons à zéro le reste de la plage.


Il est impératif de compléter les instructions de retour d'injection à la fin.


 E0 F0 CPX #$F0 D0 F9 BNE -7 4C 12 C3 JMP $C312 

Maintenant, pour plus de commodité, je préfère écrire les opcodes ci-dessous dans le fichier.


 4C 12 C3 JMP $C312 A2 28 A9 00 95 00 E8 E0 AA D0 F9 A9 13 95 00 E8 E0 AC D0 F9 A9 00 95 00 E8 E0 F0 D0 F9 4C 12 C3 

Et après avoir compté les opcodes, il est facile de découvrir qu'il y en a 32. Par conséquent, vous devez trouver 20 16 adresses inoccupées sur la ROM. En règle générale, les adresses inoccupées sont de grands espaces de mêmes valeurs, le plus souvent des zéros ou FF 16. C'est juste un morceau si grand qui doit être trouvé, il doit y avoir au moins 35 10 adresses pour qu'il y ait une marge.


Dans "Hex Editor", j'ai trouvé une telle gamme dans B29E 16 -BFFF 16 . Utiliser le début de tels sites gratuits pour les injections peut être dangereux, donc je vous conseille d'écrire un code d'injection à la fin. L'adresse la plus pratique pour démarrer l'injection est BFE0 16 , mais il s'agit de l'adresse dans la mémoire de la console, pour savoir où elle se trouve dans le fichier ROM, faites un clic droit dessus et sélectionnez «Aller ici dans le fichier ROM».


Vous pouvez maintenant copier-coller l'intégralité de l'opcode ici (32 valeurs). Instructions de modification finale


 C2C1:20 07 C3 JSR $C307 

passer à l'adresse d'injection que j'ai est BFE0 16 .


 C2C1:20 E0 BF JSR $BFE0 

Bien sûr, trouver le vrai lieu d'enseignement sur ROM.


La réponse à la question des professionnels inattentifs.

L'adresse de l'instruction JSR se trouve sur la pile, donc, quel que soit le lieu du saut, la même adresse de retour sera là, et à partir de l'injection, nous revenons au code avec l'instruction JMP qui n'affecte en rien la pile. Ainsi, l'instruction RTS fonctionne au même endroit que sans injection et revient au même endroit que sans injection. Par conséquent, cette injection ne casse pas la pile.


PS Pour de bon, vous devez toujours vous assurer qu'après la mort, les personnages renaissent avec une propagation propagée, mais je suis sûr qu'avec les connaissances acquises, vous pouvez le gérer vous-même. Je vais tourner les yeux vers autre chose. Moteur Unity par exemple.

Source: https://habr.com/ru/post/fr447990/


All Articles