Speedran Legend of Zelda en manipulant la mémoire du jeu
La première partie de Legend of Zelda est un classique immortel. Un joueur ordinaire a besoin de quelques jours pour le terminer, mais pour les coureurs de vitesse les plus expérimentés, c'est une question d'une demi-heure. Cependant, le bogue très déroutant et complexe ouvert par Sockfolder permet à l'utilisateur d'exécuter du code arbitraire directement à partir du jeu afin de terminer le jeu en moins de trois minutes.En bref, cela se produit comme suit:- Saisissez le code sur l'écran de saisie du nom.
- Nous entrons dans le deuxième donjon, prenons le sifflet.
- Nous passons au cimetière, nous appelons dix fantômes.
- Nous attendons les conditions nécessaires, mettons le jeu en pause lorsque les créatures sont à certains endroits.
- Faites une pause, appuyez sur A et B en même temps, et c'est tout!
Oui, c'est génial. Examinons maintenant de plus près ce qui se passe dans le jeu et comment cet incroyable bug Legend of Zelda est exécuté.
Comment provoquer une erreur
Donc, nous entrons d'abord le code sur l'écran de saisie du nom. Les noms de fichiers sont stockés en mémoire et chaque caractère correspond à un octet spécifique en mémoire. Nous donnons des noms étranges aux fichiers, car en fait nous écrivons les octets nécessaires en mémoire, qui deviendront alors du code assembleur. Il n'y a que deux limitations:- nous pouvons travailler avec seulement trois fichiers, c'est-à-dire que le programme ne peut contenir que 3 * 8 caractères = 24 octets;
- nous devons saisir les cinq premiers caractères de l'un des fichiers ZELDA si nous voulons commencer par la deuxième quête.
Nous devons commencer par la deuxième quête pour une raison que j'expliquerai plus tard. Nous appelons le premier fichier ZELDA car ce nom est le mieux adapté. Commençons maintenant le jeu. Avant d'arriver au cimetière, notre comportement n'est pratiquement pas différent du jeu habituel. La principale chose que nous devons faire est d'essayer de ne pas mourir deux fois. Par "mourir", on entend à la fois la mort elle-même et le passage fréquent au menu. Vous comprendrez pourquoi il en est ainsi, à partir d'autres explications.
Après avoir sifflé, nous allons sur cet écran de cimetière pour terminer le bug. L'erreur est déclenchée ici, car lors de l'utilisation du sifflet, un objet est créé à partir de la pierre tombale, ce qui ouvre un escalier caché. Cela est nécessaire pour l'apparition d'un bug. Et tout cela est dû aux limitations des sprites. Dans Legend of Zelda, l'écran peut contenir jusqu'à 11 sprites à la fois. Si vous essayez de créer un 12e sprite, le jeu ne vous permettra pas de le faire. Pour reproduire l'erreur, nous cassons la limite de débordement et créons le 12e sprite.
Lorsque vous créez l'objet sifflet, le jeu oublie de vérifier combien de sprites étaient à l'écran auparavant. Par conséquent, lorsque nous avons créé le nombre maximal de sprites, le sprite est créé en dehors de la table de sprites, la mémoire est remplacée et un état inattendu se produit.Il existe un petit fragment en mémoire à partir du décalage 350 qui stocke les identifiants de onze sprites. Un sprite est créé lorsque l'écran se charge, à partir d'une position avec le plus petit décalage possible du sprite. Cela signifie que les sprites recherchent une position avec un décalage minimum, à partir du décalage 350 et au-delà. Lorsqu'un sprite doit être créé, le jeu recherche une valeur vide dans la table des sprites pour le remplacer par l'identifiant du sprite, le créant ainsi. Contrairement à la création de sprites lors du chargement de l'écran, lorsque vous essayez de créer un sprite, le jeu recherche une position avec un décalage maximum pour le sprite. Cela signifie qu'elle vérifie d'abord s'il est possible de créer un sprite à la position 10 (0A). Sinon, elle vérifie la position 9 (09), c'est-à-dire décalage 359, et ainsi de suite. Si toutes les positions de sprite sont occupées, le jeu «se rend» et ne crée pas de sprite.
Cependant, les développeurs ont oublié d'effectuer des vérifications de bordures afin que le jeu puisse «abandonner» en essayant de créer un objet «sifflet», et le jeu continue de rechercher des octets avec la valeur 00 à un endroit en dehors de la table des sprites afin d'y écrire l'identifiant de l'objet. Mais où cherche-t-elle d'abord ce sens? En fait, cette table fait partie d'un tableau plus large qui stocke des informations sur les sprites. Lorsque le sifflet trouve un endroit à créer au début du tableau, il commence à rechercher des positions avec la valeur 00 à la fin du tableau.Sur l'écran du cimetière, ce fragment de la matrice contient des informations sur l'état actuel des actions fantômes. Parlons maintenant des états d’action des fantômes. Les fantômes créés dans le cimetière se déplacent au hasard. En effet, leurs actions sont contrôlées par un comportement déterminé par leur état d'action. Ces états d'action peuvent avoir n'importe quelle valeur de 0 (00) à 5 (05), selon les actions du fantôme. Ils sont écrits à la fin d'un tableau contenant des informations sur les sprites.En général, tous ces états d'action correspondent à une position dans la table des fonctions qui définit les actions des fantômes. Étant donné que les états ne peuvent avoir que 6 valeurs, la table a la taille nécessaire pour stocker les six actions. Ici, l'état d'action 0 (00) correspond à l'accélération du fantôme. Ceci est important car lorsque le sifflet commence à chercher un endroit pour créer son sprite, il remplira la première position trouvée en mémoire avec la valeur 00. L'accélération fantôme correspond à l'action 0, enregistrée dans le code avec la valeur 00, donc le jeu la considère comme une position vide et lui écrit l'identifiant. sifflet 5E.
Ensuite, le jeu essaie d'exécuter le code à la position 5E de la table, mais comme la table ne contient que des valeurs allant jusqu'à 05, le jeu exécute les données «ordures» sous forme de code bien au-delà de la table. Si vous faites tout correctement, les données «indésirables» nous mèneront au code que nous avons enregistré avec les symboles de fichiers, le jeu ira à Zelda et nous passerons par le jeu.Cependant, pour que le bogue fonctionne, nous devons endommager le troisième état de l'action dans le tableau. Ainsi, le troisième fantôme créé doit être accéléré, et tous les fantômes suivants doivent effectuer d'autres actions (dont le code n'est pas égal à 00). Ce sont des informations importantes. Voyons maintenant ce qui se passe lorsque nous exécutons un bogue.Exécution de bogues
Si nous avons tout fait correctement, le jeu essaie d'exécuter les données en position 5E de la table. Il commence à être lu sous forme de données de code commençant à l'offset 602. Les informations associées à l'état de l'action Link sont stockées en mémoire à l'offset 602 et 603, afin que nous puissions les contrôler. Lorsque Link est debout, les valeurs des décalages 602 et 603 seront 00. Mais lorsque nous appuyez sur le bouton B pour utiliser le sifflet, la valeur à 602 sera 10 et lorsque nous appuyez sur A pour utiliser l'épée, la valeur à 603 sera 01.
Par conséquent, lorsque nous appuyons simultanément sur ces deux boutons, les données voisines seront 10 01. Le jeu interprète ces données comme une commande de branche BPL pour passer à l'offset 605 et exécuter les données qu'il contient sous forme de code. Les valeurs de 605 et 606 seront 00 si notre santé n'est pas trop faible et 40 si notre santé est faible. Pour passer rapidement le jeu, ces valeurs doivent être égales à 00, vous devez donc essayer de maintenir la santé jusqu'à la fin du bug. La valeur 00 correspond à l'instruction BRK (break). Puisqu'il ne fait rien ici, nous avons besoin que les valeurs soient 00 et que le jeu continue à exécuter le code.
Depuis que nous avons utilisé l'épée, le jeu continuera à exécuter des instructions dans le prochain octet impair. L'instruction suivante, qui n'est pas BRK, est à l'offset 08, mais puisque nous avons utilisé l'épée, le jeu la saute et exécute le code à 09 et 0A. La valeur dans l'octet 09 est toujours 10, ce qui signifie que nous avons à nouveau affaire à l'instruction de branche BPL. Les octets au décalage 623 (62E) concernent la musique. Elle essaie d'augmenter dans le processus de lecture de musique, mais saute parfois à des valeurs plus basses.Cela signifie que pour terminer le bug, nous devons l'appliquer à un morceau de musique spécifique. Si la valeur est petite, nous avons une chance de sauter en mémoire dans une zone dont les valeurs changent considérablement. Ils changent de manière si aléatoire que nous ne pouvons pas les contrôler en temps réel pour recevoir des instructions que le jeu doit suivre. Par conséquent, la transition ici risque d'entraîner un blocage du jeu.
Cependant, après ces données chaotiques, il y a une zone de données sûres. Par conséquent, nous allons essayer de sauter là-bas. Nous avons besoin de plus de données dans le 60A pour ignorer avec précision la zone dangereuse et accéder aux données permanentes et sûres. Si nous y sommes allés, alors tout est en ordre. Mais au décalage 630, il y a un compteur pour les morts de Link. Si Link est mort deux fois, cette valeur sera 02, ce qui forme une instruction et arrête la partie. C'est pourquoi il est important de ne pas mourir deux fois. Par conséquent, nous passons au décalage 638, qui est le début du tableau stockant les noms de fichiers. Si nous arrivons ici, le jeu exécutera le code que nous avons entré sur l'écran du fichier. Et ici commence ...Code
Les noms de fichiers sont stockés en mémoire dans l'ordre. Cela signifie que les premiers octets que nous exécutons sont un fichier appelé ZELDA. Heureusement, le code exécuté par ces octets est sûr, afin que nous puissions passer au reste. Puisque le nom ZELDA n'est pas important, regardons ce que fait le reste du code. Tout d'abord, nous exécutons trois commandes PLP (pull from stack, pull from stack). Lorsque nous appelons une fonction, elle écrit deux valeurs dans la pile. Ces valeurs correspondent à l'endroit où vous vous trouviez dans le code lorsque vous avez exécuté la fonction. Ainsi, le jeu peut savoir où y retourner après avoir exécuté la fonction.Nous commençons par extraire trois valeurs de la pile, puis nous effectuons la fonction de retour. Nous le faisons afin de retourner à l'endroit où nous nous trouvions avant l'exécution du bogue. Sinon, le jeu ne terminera pas l'exécution des données sous forme de code et se figera en conséquence. Mais avant d'arriver au code qui endommage la mémoire et termine le jeu, nous devons parler de quelques valeurs supplémentaires.Les valeurs au décalage de mémoire 10 correspondent au nombre de monde dans lequel nous sommes. Si nous sommes dans le monde en surface, la valeur est 00. Pour le premier donjon, la valeur est 01, pour le second - 02, et ainsi de suite. Puisque Zelda est dans le neuvième donjon, nous avons besoin que cette valeur soit 09. Cependant, nous effectuons un bogue dans le monde en surface et la valeur est 00. Nous devons donc trouver un moyen de l'assimiler à 09. La valeur à l'offset 11 correspond à certaines données sur l'état du jeu. Lorsque le jeu se charge, la valeur est 00, lorsque le jeu ne se charge pas - 01. Nous devons charger le neuvième donjon, cette valeur doit donc être 00.La valeur à l'offset 12 correspond à une partie de l'état. Lorsque l'écran se charge, la valeur est généralement 02, lorsqu'il ne se charge pas - généralement 05. Puisque nous voulons charger le donjon, cette valeur doit être 02.La dernière valeur que nous voulons modifier correspond à la quête dans laquelle nous nous trouvons. La valeur à l'offset 62D correspond à la première ou à la deuxième quête, et a la valeur 00 ou 01. Nous sommes partis de la deuxième quête, mais nous voulons terminer dans la première quête, car c'est ainsi que nous confondons le jeu. Par conséquent, nous devons changer cette valeur à 00. Cela nous mettra dans un étrange hybride des première et deuxième quêtes. Nous avons besoin de cet état hybride pour exécuter du code dans un but spécifique. Nous l'examinerons lorsque nous expliquerons ce que fait le code.
Eh bien, nous nous fixons des objectifs, passons au code. Premièrement, nous avons la fonction LSR (décalage logique vers la droite) pour le décalage 11. Cette fonction divise la valeur en deux et écrit le reste dans le report. 11 est un endroit en mémoire qui stocke la valeur correspondant à l'état du jeu, et avant cette instruction sa valeur est 01. Lorsque nous divisons par deux, nous obtenons 00 avec le reste 01, car la division est entière. Au décalage 11, la valeur 00 est écrite, et dans le transfert, 01.Ensuite, nous avons la fonction ROX pour décaler 0D (tourner à gauche, à gauche) avec l'index X. Puisque nous avons écrasé l'état d'action du troisième fantôme que nous avons créé, X est égal à trois. 0D + X est 0D + 03, ce qui est hexadécimal 10. Par conséquent, cette fonction tourne à gauche au décalage 10. Cette fonction multiplie la valeur au décalage 10 par 2 et ajoute à la césure. La valeur commence à 0. Zéro fois 2 est égal à 0 et 0 + 1 est égal à 1, donc la valeur est écrite sur le décalage 10.Maintenant, l'opération ROX est répétée à nouveau pour compenser 0D avec l'index X. La valeur de X n'a pas changé, elle est toujours de trois, par conséquent, c'est un autre virage à gauche au décalage 10. 1 * 2 = 2, et puisque nous avons déjà utilisé le transfert, sa valeur est 0. 2 + 0 = 2, donc la valeur 2 est écrite dans le décalage 2.Ensuite, nous avons la troisième opération ROX pour le décalage 0D. 2 * 2 = 4 et 4 + 0 = 4, donc la valeur 4 est écrite au décalage 10.L'instruction suivante est LSR au décalage 12. Nous commençons par la valeur 5, donc la division par deux nous donne le reste 1. 2 est écrit au décalage 12 , et 1 - dans le transfert.Puis le dernier ROX tourne à gauche à l'offset 10. 4 * 2 = 8. La valeur de transfert est 1, nous l'ajoutons au produit, obtenant 9.La dernière instruction avant de revenir est un décalage logique à droite à l'offset 62D. La valeur ici est 1, car nous sommes dans la deuxième quête. Et puisque nous avons divisé par 2, la valeur sera égale à 0. Nous sommes donc entrés dans le mode de quête hybride.Maintenant, nous effectuons la fonction de retour et le jeu met à jour les valeurs de son état avec les valeurs enregistrées dans notre code. Ceci termine le bug et nous entrons dans la chambre de Zelda. Nous y arrivons car la quête hybride confond le jeu. Elle ne sait pas exactement où mettre Link. Et donc on se retrouve dans la chambre de Zelda, ayant ainsi passé le match.
J'espère que cela vous aide à comprendre ce qui se passe dans le jeu Legend of Zelda lors de l'exécution de code arbitraire et de l'exécution d'un bug de jeu rapide.Source: https://habr.com/ru/post/fr398171/
All Articles