Rétro-ingénierie du mode développeur Animal Crossing

Utiliser le code sur un vrai GameCube

L'été dernier, j'ai commencé le reverse engineering Animal Crossing pour le GameCube. Je voulais explorer la possibilité de créer des mods pour ce jeu. De plus, je voulais documenter le processus de création de didacticiels pour les personnes intéressées par le piratage des ROM et le reverse engineering. Dans cet article, je parlerai des fonctionnalités de débogage des développeurs qui sont restées dans le jeu, et partagerai également comment j'ai découvert des combinaisons de triche qui peuvent être utilisées pour les déverrouiller.

new_Debug_mode


En étudiant les symboles de débogage restants, j'ai remarqué les noms des fonctions et des variables contenant le mot «débogage», et j'ai décidé qu'il serait intéressant de voir s'il restait une fonctionnalité de débogage dans le jeu. Si j'arrive à activer les fonctions de débogage ou de développement, cela m'aidera à créer des mods.

La première fonction que j'ai remarquée était new_Debug_mode . Il est appelé par la fonction d' entry , qui démarre immédiatement après la fin de l'écran du logo Nintendo. Elle ne fait que placer la structure d'octets 0x1C94 et y enregistrer un pointeur.

Après avoir été appelé en entry dans la structure hébergée à l'offset 0xD4 immédiatement avant d'appeler mainproc valeur 0 est définie.


Pour voir ce qui se passe lorsque la valeur n'est pas nulle, j'ai corrigé l'instruction li r0, 0 à 80407C8C , en la remplaçant par li r0, 1 . Les octets bruts de l'instruction li r0, 0 sont 38 00 00 00 où la valeur assignée est à la fin de l'instruction, donc je pourrais simplement remplacer les octets par 38 00 00 01 et obtenir li r0, 1 . Pour créer des instructions de manière plus fiable, vous pouvez utiliser quelque chose comme kstool :

$ kstool ppc32be "li 0, 1"
li 0, 1 = [ 38 00 00 01 ]


Dans l'émulateur Dolphin, ce patch peut être appliqué en allant dans l'onglet "Patches" dans les propriétés du jeu et en le saisissant comme suit:


Après avoir attribué la valeur 1, un graphique intéressant est apparu en bas de l'écran:



Cela ressemblait à un indicateur de performance: les petites barres en bas de l'écran ont augmenté ou diminué. (Plus tard, lorsque j'ai regardé les noms des fonctions qui dessinent ce graphique, j'ai constaté qu'elles affichent en fait des mesures d'utilisation du processeur et de la mémoire.)

C'était super, mais pas particulièrement utile. Après avoir attribué la valeur 1, ma ville a cessé de se charger, donc rien d'autre n'a pu être fait ici.

Mode Zuru


J'ai recommencé à chercher d'autres références aux fonctions de débogage, et plusieurs fois j'ai rencontré quelque chose appelé «mode zuru». Les branches de blocs de code avec fonctionnalité de débogage vérifiaient souvent la variable zurumode_flag .

Fonction game_move_first

zzz_LotsOfDebug (le nom que j'ai trouvé moi-même) dans la fonction game_move_first montrée ci-dessus est appelé uniquement lorsque zurumode_flag pas égal à zéro.

À la recherche de fonctions associées à cette valeur, j'ai trouvé celles-ci:

  • zurumode_init
  • zurumode_callback
  • zurumode_update
  • zurumode_cleanup

À première vue, leur objectif est mystérieux, ils jonglent avec des bits dans les décalages d'une variable appelée osAppNMIBuffer .

Voici à quoi ressemble le travail de ces fonctions à première vue:

zurumode_init


  • Définit zurumode_flag à 0
  • Vérifie plusieurs bits dans osAppNMIBuffer
  • Enregistre un pointeur sur la fonction zurumode_callback dans la structure padmgr
  • Appelle zurumode_update

zurumode_update


  • Vérifie plusieurs bits dans osAppNMIBuffer
  • En fonction de la valeur de ces bits, zurumode_flag met à jour
  • Imprime une chaîne de format sur la console du système d'exploitation.

Ceci est généralement utile pour donner du contexte au code, mais il y avait beaucoup de caractères non imprimables dans la ligne. Le seul texte reconnaissable était «zurumode_flag» et «% d».

chaîne de formatage en mode zuru

En supposant qu'il pourrait s'agir d'un texte japonais avec un codage de caractères multi-octets, j'ai passé la chaîne via l'outil de reconnaissance de codage et j'ai découvert que la chaîne était codée avec Shift-JIS. En traduction, la ligne signifiait simplement "La valeur de zurumode_flag est passée de% d à% d". Cela ne nous donne pas beaucoup de nouvelles informations, mais maintenant nous savons que Shift-JIS est utilisé: dans les fichiers binaires et les tables de lignes, il y a beaucoup plus de lignes dans cet encodage.

zurumode_callback


  • Appelle zerumode_check_keycheck
  • Vérifie plusieurs bits dans osAppNMIBuffer
  • La valeur zurumode_flag
  • Appelle zurumode_update

zerumode_check_keycheck jusqu'à ce que nous nous rencontrions à cause d'une orthographe différente ... qu'est-ce que c'est?

zerumode_check_keycheck

Une énorme fonction complexe qui fait beaucoup plus de travail sur les bits avec des valeurs sans nom.

À ce stade, j'ai décidé de prendre du recul et d'étudier d'autres fonctions et variables de débogage, car je n'étais pas sûr de l'importance du mode zuru. De plus, je n'ai pas compris ce que signifie «vérification des clés» ici. Est-il possible qu'il s'agisse d'une clé cryptographique?

Retour au débogage


À cette époque, j'ai remarqué un problème avec ma façon de charger les symboles de débogage dans l'IDA. Le fichier foresta.map sur le disque du jeu contient de nombreuses adresses et noms de fonctions et de variables. Au début, je n'ai pas vu que les adresses de chaque section recommencent à zéro, j'ai donc écrit un script simple qui ajoute une entrée de nom pour chaque ligne du fichier.

J'ai écrit de nouveaux scripts IDA pour corriger le chargement des tables de symboles pour différentes sections du programme: .text , .rodata , .data et .bss . La section .text contient toutes les fonctions, donc je l'ai fait pour que cette fois, lorsque je définirai le nom, le script reconnaîtra automatiquement les fonctions à chaque adresse.

Dans les sections de données, il a maintenant créé un segment pour chaque objet binaire (par exemple, m_debug.o , qui était censé être du code compilé pour quelque chose appelé m_debug ), et a défini l'espace et les noms pour chaque élément de données.

Cela m'a donné beaucoup plus d'informations, mais j'ai dû définir manuellement le type de données pour chaque élément de données, car j'ai défini chaque objet de données comme un tableau d'octets simple. (Avec le recul, je comprends qu'il serait préférable de supposer que des fragments de 4 octets contenaient des entiers 32 bits, car il y en avait beaucoup et beaucoup contenaient des adresses de fonctions et de données importantes pour la construction de références croisées.)

En étudiant le nouveau segment .bss pour m_debug_mode.o , j'ai trouvé plusieurs variables de la forme quest_draw_status et event_status . C'est intéressant car je voulais que des informations utiles, pas seulement un graphique de performances, soient affichées en mode débogage. Heureusement, à partir de ces enregistrements de données, il y avait des références croisées à un énorme morceau de code vérifiant debug_print_flg .

À l'aide d'un débogueur dans l'émulateur Dolphin, j'ai défini un point d'arrêt à l'emplacement de la fonction où debug_print_flg vérifié (à 8039816C ) pour comprendre comment cette vérification fonctionne. Mais le programme n'est jamais passé à ce point d'arrêt.

Voyons pourquoi cela se produit: cette fonction est appelée par game_debug_draw_last . Devinez quelle valeur est vérifiée avant son appel conditionnel? zurumode_flag ! Que diable se passe-t-il?

vérification zurumode_flag

J'ai défini un point d'arrêt sur ce chèque ( 80404E18 ) et cela a fonctionné tout de suite. La valeur de zurumode_flag était nulle, donc en exécution normale, le programme aurait manqué l'appel à cette fonction. J'ai inséré une instruction de branche NOP à la place (remplacée par une instruction qui ne fait rien) pour vérifier ce qui se passe lorsque la fonction est appelée.

Dans le débogueur Dolphin, cela peut être fait en interrompant le jeu, en cliquant avec le bouton droit sur les instructions et en sélectionnant «Insérer nop»:

Débogueur Dolphin Nopping

Il ne s'est rien passé. Ensuite, j'ai vérifié ce qui se passait à l'intérieur de la fonction et découvert une autre construction de branchement qui a contourné tout ce qui était intéressant à 803981a8 . J'ai également inséré NOP à la place, et la lettre "D" est apparue dans le coin supérieur droit de l'écran.

Lettre de mode de débogage D

Dans cette fonction à 8039816C (je l'ai appelée zzz_DebugDrawPrint ), il y a encore un tas de code intéressant, mais il n'est pas appelé. Si vous regardez cette fonction sous la forme d'un graphique, vous pouvez voir qu'il existe une série d'opérateurs de branchement qui ignorent les blocs de code dans la fonction:

Branches dans zzz_DebugDrawPrint

Après avoir inséré NOP au lieu de plusieurs autres constructions de ramification, j'ai commencé à voir diverses choses intéressantes à l'écran:

Plus de trucs de débogage imprimés

La question suivante était de savoir comment activer cette fonctionnalité de débogage sans modifier le code.

En outre, dans certaines constructions de branche, zurumode_flag se produit à nouveau dans cette fonction de dessin de débogage. J'ai ajouté un autre patch afin que dans zurumode_update drapeau zurumode_update zurumode_flag toujours attribuer la valeur 2, car lorsqu'il ne se compare pas à 0, il est comparé spécifiquement à la valeur 2.

Après avoir redémarré le jeu, j'ai vu dans le coin supérieur droit de l'écran un tel message "msg. non. "

affichage du numéro de message

Le nombre 687 est l'identifiant d'enregistrement du dernier message affiché. Je l'ai vérifié en utilisant le programme de visualisation de table que j'ai écrit au tout début de l'analyse, mais vous pouvez également le vérifier en utilisant l' éditeur de table de chaînes avec une interface graphique complète , que j'ai écrite pour pirater les ROM. Voici à quoi ressemble le message dans l'éditeur:

Message 687 dans l'éditeur de table de chaînes

À ce stade, il est devenu clair que l'étude du mode zuru n'était plus supprimée - elle est directement liée aux fonctions de débogage du jeu.

Retour au mode Zuru à nouveau


zurumode_init initialise plusieurs choses:

  • 0xC(padmgr_class) reçoit la valeur de l'adresse zurumode_callback
  • 0x10(padmgr_class) reçoit la valeur d'adresse de padmgr_class elle-même
  • 0x4(zuruKeyCheck) reçoit la valeur du dernier bit du mot chargé à partir de 0x3C(osAppNMIBuffer) .

J'ai compris ce qu'est padmgr , une abréviation de «gamepad manager». Cela signifie qu'il peut y avoir une combinaison spéciale de touches (boutons) qui peuvent être saisies sur la manette de jeu pour activer le mode zuru, ou une sorte de dispositif de débogage ou une fonction de la console du développeur qui peut être utilisée pour envoyer un signal pour l'activer.

zurumode_init n'est exécuté que lors du premier chargement du jeu (lorsque le bouton de réinitialisation est enfoncé, cela ne fonctionne pas).

Après avoir défini un point d'arrêt à l'adresse 8040efa4 , auquel la valeur 0x4(zuruKeyCheck) est attribuée 0x4(zuruKeyCheck) , nous pouvons voir que lors du chargement sans appuyer sur les touches, la valeur est définie sur 0. Si vous le remplacez par 1, une chose intéressante se produit:

Écran de titre avec le mode zuru

La lettre "D" apparaît à nouveau dans le coin supérieur droit (cette fois est verte, pas jaune), et certaines informations d'assemblage sont également affichées:

[CopyDate: 02/08/01 00:16:48 ]
[Date: 02-07-31 12:52:00]
[Creator:SRD@SRD036J]


Un patch qui définit toujours 0x4(zuruKeyCheck) à 1 au début ressemble à ceci:

8040ef9c 38c00001

Cela semble être la bonne façon d'initialiser le mode zuru. Après cela, diverses actions peuvent être nécessaires pour obtenir l'affichage de certaines informations de débogage. En commençant le jeu, en vous promenant dessus et en parlant à un villageois, nous ne verrons aucun des messages mentionnés ci-dessus (à l'exception de la lettre "D" dans le coin).

Les suspects les plus probables sont zurumode_update et zurumode_callback .

zurumode_update


zurumode_update abord appelé dans zurumode_init puis constamment appelé par zurumode_callback .

Il vérifie à nouveau le dernier bit 0x3C(osAppNMIBuffer) puis, en fonction de cette valeur, met à jour zurumode_flag .

Si le bit est nul, le drapeau est mis à zéro.

Sinon, l'instruction suivante est exécutée, la valeur complète 0x3c(osAppNMIBuffer) étant r5 :

extrwi r3, r5, 1, 28

Il extrait le 28e bit de r5 et le stocke dans r3 .

Ensuite, 1 est ajouté au résultat, c'est-à-dire que le résultat final est toujours 1 ou 2.

Ensuite, zurumode_flag comparé au résultat précédent, en fonction du nombre de 28e et dernier bits définis sur 0x3c(osAppNMIBuffer) : 0, 1 ou 2.

Cette valeur est écrite dans zurumode_flag . Si cela ne change rien, la fonction se ferme et renvoie la valeur d'indicateur actuelle. S'il modifie la valeur, une chaîne de blocs de code beaucoup plus complexe est exécutée.

Un message s'affiche en japonais: la même «valeur zurumode_flag est passée de% d à% d», dont nous avons parlé plus haut.

Ensuite, une série de fonctions est appelée avec différents arguments, selon que le drapeau est devenu égal à zéro ou non. Le code assembleur de cette partie est monotone, je vais donc montrer son pseudocode:

 if (flag_changed_to_zero) { JC_JUTAssertion_changeDevice(2) JC_JUTDbPrint_setVisible(JC_JUTDbPrint_getManager(), 0) } else if (BIT(nmiBuffer, 25) || BIT(nmiBuffer, 31)) { JC_JUTAssertion_changeDevice(3) JC_JUTDbPrint_setVisible(JC_JUTDbPrint_getManager(), 1) } 

Notez que si l'indicateur est nul, l'argument 0 est passé à JC_JUTDbPrint_setVisible.

Si l'indicateur n'est pas égal à zéro et que le bit 25 ou le bit 31 sont définis sur 0x3C(osAppNMIBuffer) , setVisible argument 1.

Il s'agit de la première clé pour activer le mode zuru: le dernier bit 0x3C(osAppNMIBuffer) doit être défini sur 1 pour afficher les informations de débogage et définir zurumode_flag valeur non nulle.

zurumode_callback


zurumode_callback est situé au 8040ee74 et est probablement appelé par une fonction liée à la manette de jeu. Après avoir inséré un point d'arrêt dans le débogueur Dolphin, la pile d'appels nous montre qu'il est réellement appelé à partir de padmgr_HandleRetraceMsg .

L'une de ses premières actions a été d'exécuter zerucheck_key_check . Cette fonction est complexe, mais il semble qu'en général elle est conçue pour lire et mettre à jour la valeur de zuruKeyCheck . Avant de passer à la fonction de vérification des touches, j'ai décidé de vérifier comment cette valeur est utilisée dans le reste de la fonction de rappel.

Ensuite, il vérifie à nouveau pour certains bits dans 0x3c(osAppNMIBuffer) . Si le bit 26 est défini, ou si le bit 25 est défini et que padmgr_isConnectedController(1) renvoie une valeur différente de zéro, le dernier bit de 0x3c(osAppNMIBuffer) sur 1!

Si aucun de ces bits n'est défini, ou que le bit 25 est défini, mais que padmgr_isConnectedController(1) renvoie 0, la fonction vérifie si l'octet à l'adresse 0x4(zuruKeyCheck) est égal à zéro. S'il est égal, il réinitialise le dernier bit de la valeur d'origine et le 0x3c(osAppNMIBuffer) sur 0x3c(osAppNMIBuffer) . Sinon, il définit toujours le dernier bit sur 1.

En pseudo code, cela ressemble à ceci:

 x = osAppNMIBuffer[0x3c] if (BIT(x, 26) || (BIT(x, 25) && isConnectedController(1)) || zuruKeyCheck[4] != 0) { osAppNMIBuffer[0x3c] = x | 1 // set last bit } else { osAppNMIBuffer[0x3c] = x & ~1 // clear last bit } 

Après cela, si le bit 26 n'est pas défini, la fonction passe à l'appel de zurumode_update , puis se zurumode_update .

Si le bit est défini, alors si 0x4(zuruKeyCheck) pas égal à zéro, alors il charge une chaîne de format dans laquelle il affiche ce qui suit: "ZURU% d /% d".

Pour résumer le sous-total


Voici ce qui se passe:

padmgr_HandleRetraceMsg appelle zurumode_callback . Je suppose que ce «message de retour de poignée» signifie qu'il scanne simplement les frappes du contrôleur. À chaque analyse, il peut provoquer une série de rappels différents.

Lorsque zurumode_callback exécuté zurumode_callback il vérifie les frappes (boutons) en cours. Il semble qu'elle vérifie un bouton spécifique ou une combinaison de boutons.

Le dernier bit du tampon NMI est mis à jour en fonction des bits spécifiques de sa valeur actuelle, ainsi que de la valeur de l'un des octets zuruKeyCheck ( 0x4(zuruKeyCheck) ).

Ensuite, zurumode_update est zurumode_update et vérifie ce bit. S'il est égal à 0, alors l'indicateur de mode zuru est mis à 0. S'il est égal à 1, alors l'indicateur de mode passe à 1 ou 2, selon que le bit 28 est activé.

Il existe trois façons d'activer le mode zuru:

  1. Le bit 26 est défini sur 0x3C(osAppNMIBuffer)
  2. Le bit 25 est défini sur 0x3C(osAppNMIBuffer) et le contrôleur est connecté au port 2
  3. 0x4(zuruKeyCheck) pas nul

osAppNMIBuffer


Intéressé par ce osAppNMIBuffer signifie osAppNMIBuffer , j'ai commencé à chercher «NMI» et j'ai trouvé des liens dans le contexte Nintendo vers «interruption non masquable». Il s'avère que le nom de cette variable est entièrement mentionné dans la documentation développeur de Nintendo 64:

osAppNMIBuffer est un tampon de 64 octets qui est effacé lors d'un redémarrage à froid. Si le système redémarre en raison de NMI, l'état de ce tampon ne change pas.

En fait, il s'agit d'un petit morceau de mémoire enregistré lors d'un redémarrage «doux» (avec le bouton de réinitialisation). Le jeu peut utiliser ce tampon pour stocker toutes les données pendant que la console est sur le réseau. L'original Animal Crossing est sorti sur Nintendo 64, il est donc logique que quelque chose de similaire ait dû apparaître dans le code.

Si nous allons dans le fichier boot.dol binaire (tout ce qui est montré ci-dessus était dans foresta.rel ), alors sa fonction main a beaucoup de liens vers osAppNMIBuffer . Un rapide coup d'œil montre qu'il existe une série de vérifications qui peuvent conduire à 0x3c(osAppNMIBuffer) valeurs de différents bits 0x3c(osAppNMIBuffer) aide d'opérations OR.

Les valeurs d'opérande OR suivantes peuvent être intéressantes:

  • Bit 31: 0x01
  • Bit 30: 0x02
  • Bit 29: 0x04
  • Bit 28: 0x08
  • Bit 27: 0x10
  • Bit 26: 0x20

Nous nous souvenons que les bits 25, 26 et 28 sont particulièrement intéressants: 25 et 26 déterminent si le mode zuru est activé et le bit 28 détermine le niveau du drapeau (1 ou 2).
Le bit 31 est également intéressant, mais il semble qu'il change en fonction des valeurs des autres.

Bit 26

Tout d'abord: à l'adresse 800062e0 il y a une instruction ori r0, r0, 0x20 avec une valeur tampon de 0x3c . Il active le bit 26, qui active toujours le mode zuru.

Règlement du bit 26

Pour que le bit soit défini, le huitième octet renvoyé par DVDGetCurrentDiskID doit être 0x99 . Cet identifiant est situé au tout début de l'image disque du jeu et est chargé en mémoire à 80000000 . Dans une version commerciale régulière du jeu, l'ID ressemble à ceci:

47 41 46 45 30 31 00 00 GAFE01..

En remplaçant le dernier octet de l'identifiant par un 0x99 pour 0x99 , nous obtenons l'image suivante au démarrage du jeu:

ID de version du jeu 0x99

Et ce qui suit s'affiche dans la console du système d'exploitation:

06:43:404 HW\EXI_DeviceIPL.cpp:339 N[OSREPORT]: ZURUMODE2 ENABLE
08:00:288 HW\EXI_DeviceIPL.cpp:339 N[OSREPORT]: osAppNMIBuffer[15]=0x00000078


Tous les autres correctifs peuvent être supprimés, après quoi la lettre D apparaît à nouveau dans le coin supérieur droit de l'écran, mais aucun message de débogage n'est activé.

Bit 25

Le bit 25 est utilisé conjointement avec la vérification du port du contrôleur 2. Qu'est-ce qui le fait s'allumer?

Bit 25 et 28

Il s'avère qu'il doit utiliser le même contrôle que pour le bit 28: la version doit être supérieure ou égale à 0x90 . Si le bit 26 est défini (l'ID est 0x99 ), ces deux bits seront également définis et le mode zuru sera toujours activé.

Cependant, si la version est comprise entre 0x90 et 0x98 , le mode zuru ne s'active pas instantanément. Rappelez la vérification effectuée dans zurumode_callback - le mode ne sera activé que si le bit 25 est défini et padmgr_isConnectedController(1) renvoie une valeur différente de zéro.

Une fois que le contrôleur est connecté au port 2 (l'argument isConnectedController a zéro indexation), le mode zuru est activé. La lettre D et les informations sur l'assemblage apparaissent sur l'écran initial, et nous ... pouvons contrôler l'affichage du débogage à l'aide des boutons du deuxième contrôleur!

Certains boutons effectuent des actions qui non seulement modifient l'affichage, mais aussi, par exemple, augmentent la vitesse du jeu.

zerucheck_key_check


Le dernier mystère reste 0x4(zuruKeyCheck) . Il s'avère que cette valeur est mise à jour avec une énorme fonction complexe que j'ai montrée ci-dessus:

zerumode_check_keycheck

En utilisant le débogueur d'émulateur Dolphin, j'ai pu déterminer que la valeur vérifiée par cette fonction est un ensemble de bits correspondant aux pressions de bouton sur le deuxième contrôleur.

Le suivi des clics sur les boutons est stocké dans une valeur de 16 bits à 0x2(zuruKeyCheck) . Lorsque le contrôleur n'est pas connecté, la valeur est 0x7638 .

2 octets contenant les drapeaux des pressions des boutons du contrôleur sont téléchargés puis mis à jour au début de zerucheck_key_check . La nouvelle valeur est transmise avec le registre r4 fonction padmgr_HandleRetraceMsg lorsqu'elle appelle la fonction de rappel.

fin de la vérification des clés

Vers la fin de zerucheck_key_check il y a un autre endroit où 0x4(zuruKeyCheck) mis à jour 0x4(zuruKeyCheck) .Il n'apparaissait pas dans la liste de références croisées car il l'utilisait comme adresse de base r3, et nous ne pouvons connaître la valeur r3qu'en regardant la valeur qui lui est affectée avant d'appeler cette fonction.

À l'adresse, la 8040ed88valeur est r4écrite 0x4(zuruKeyCheck). Juste avant cela, mais il est écrit du même endroit, puis XOR à partir de 1. La tâche de cette opération est de basculer la valeur d'octet (en fait le dernier bit) entre 0 et 1. (Si la valeur est 0, le résultat de
XOR à partir de 1 sera 1 . Si la valeur est 1, le résultat sera 0. Voir la table de vérité pour XOR.)

fin de la vérification des clés

Plus tôt, lorsque j'ai étudié les valeurs en mémoire, je n'ai pas remarqué ce comportement, mais je vais essayer de casser cette instruction dans le débogueur pour comprendre ce qui se passe. La valeur d'origine est chargée à 8040ed7c.

Sans toucher aux boutons du contrôleur, je ne parviendrai pas à ce point d'arrêt sur l'écran initial. Pour entrer dans ce bloc de code, la valeur r5doit devenir égale 0xbavant l'instruction de branchement qui précède le point d'arrêt ( 8040ed74). Parmi les nombreux chemins différents menant à ce bloc, un seul attribue une r5valeur 0xbdevant lui à l'adresse 8040ed68.

Définition de r5 sur 0xb

Notez que pour atteindre le bloc affectant la r5valeur 0xB, la valeur r0doit être égale juste avant 0x1000. En suivant les blocs de la chaîne jusqu'au début de la fonction, nous pouvons voir toutes les restrictions nécessaires pour réaliser ce bloc:

  • 8040ed74: la valeur r5doit être égale0xB
  • 8040ed60: la valeur r0doit être égale0x1000
  • 8040ebe8: la valeur r5doit être égale0xA
  • 8040ebe4: la valeur r5doit être inférieure0x5B
  • 8040eba4: la valeur r5doit être supérieure0x7
  • 8040eb94: la valeur r6doit être 1
  • 8040eb5c: la valeur r0ne doit pas être 0
  • 8040eb74: les valeurs du bouton du port 2 doivent changer

Traçage du chemin du code

Ici, nous avons atteint le point où les anciennes valeurs de bouton sont chargées et les nouvelles valeurs sont enregistrées. Viennent ensuite quelques opérations appliquées aux nouvelles et anciennes valeurs: L'opération XOR marque tous les bits qui ont changé entre les deux valeurs. Ensuite, l'opération ET masque la nouvelle entrée pour définir tous les bits qui ne sont pas actuellement définis sur l'état 0. Le résultat en est un ensemble de nouveaux bits (pressions de bouton) dans la nouvelle valeur. S'il n'est pas vide, nous sommes sur la bonne voie. Pour faire une différence , le quatrième des boutons de suivi 16 bits doit changer. Après avoir inséré un point d'arrêt après l'opération XOR / AND, j'ai découvert que le bouton START déclenche cet état. La question suivante est de savoir comment le rendre initialement égal

old_vals = old_vals XOR new_vals
old_vals = old_vals AND new_vals


r0

r00x1000

r50xA. r5et r6sont chargés depuis 0x0(zuruKeyCheck)le début de la fonction de test clé et mis à jour plus près de la fin, lorsque nous n'entrons pas dans le bloc de code qui comprend 0x4(zuruKeyCheck).

Il y a plusieurs endroits avant cela où la r5valeur est affectée 0xA:

  • 8040ed50
  • 8040ed00
  • 8040ed38

8040ed38

  • 8040ed34: la valeur r0doit être égale 0x4000(le bouton B est enfoncé)
  • 8040ebe0: la valeur r5doit être égale0x5b
  • 8040eba4: la valeur r5doit être supérieure0x7
  • alors tout se passe comme avant ...

r5 devrait commencer par 0x5b

8040ed00

  • 8040ecfc: la valeur r0doit être égale 0xC000(A et B sont pressés)
  • 8040ebf8: la valeur r5doit être> = 9
  • 8040ebf0: la valeur r5doit être inférieure à 10
  • 8040ebe4: la valeur r5doit être inférieure0x5b
  • 8040eba4: r5devrait être plus0x7
  • alors tout se passe comme avant ...

r5 devrait commencer à 9

8040ed50

  • 8040ed4c: la valeur r0doit être égale 0x8000(bouton A enfoncé)
  • 8040ec04: la valeur r5doit être inférieure0x5d
  • 8040ebe4: la valeur r5doit être supérieure0x5b
  • 8040eba4: la valeur r5doit être supérieure0x7
  • alors tout se passe comme avant ...

r5devrait commencer par 0x5c

Il semble qu'il y ait une sorte d'état entre les frappes, après quoi vous devez entrer une certaine séquence de combos à partir des boutons, en terminant par une pression sur START. Il semble que A et / ou B devraient aller juste avant START.

Si vous tracez le chemin du code qui définit la r5valeur à 9, alors un modèle apparaît: r5- c'est une valeur croissante qui peut soit augmenter lorsqu'une r0valeur appropriée est trouvée, soit zéro. Les cas les plus étranges lorsque ce n'est pas une valeur dans la plage de 0x0à0xB, se produisent lors du traitement d'étapes avec plusieurs boutons, par exemple, lorsque A et B sont enfoncés simultanément. Une personne qui essaie d'entrer dans ce combo ne peut généralement pas appuyer sur les deux boutons exactement en même temps tout en suivant la manette de jeu, vous devez donc traiter le bouton sur lequel vous appuyez. premier.

Nous continuons d'explorer différents chemins de code:

  • r5prend la valeur 9 lorsque vous appuyez sur DROITE à l'adresse 8040ece8.
  • r5prend la valeur 8 lorsque le bouton droit C à l'adresse est enfoncé 8040eccc.
  • r5prend la valeur 7 lorsque le bouton gauche C est pressé à l'adresse 8040ecb0.
  • r5prend la valeur 6 lorsque GAUCHE est pressé à l'adresse 8040ec98.
  • r5prend la valeur 5 (et r6 prend la valeur 1) lorsque BAS est pressé à l'adresse 8040ec7c.
  • r5prend la valeur 4 lorsque le bouton supérieur C à l'adresse est enfoncé 8040ec64.
  • r5prend la valeur 3 lorsque le bouton inférieur C à l'adresse est enfoncé 8040ec48.
  • r5prend la valeur 2 lorsque vous appuyez sur UP à l'adresse 8040ec30.
  • r5prend la valeur 1 (et r6prend la valeur 1) lorsque Z est pressé à l'adresse 8040ec1c.

La séquence actuelle est:

Z, UP, C-DOWN, C-UP, DOWN, LEFT, C-LEFT, C-RIGHT, RIGHT, A + B, START

Avant de vérifier Z, une autre condition est vérifiée: bien qu'un nouveau bouton doive être enfoncé Z, les drapeaux actuels doivent être égaux 0x2030: les pare-chocs gauche et droit doivent également être enfoncés (ils ont les valeurs de 0x10et 0x20). De plus, UP / DOWN / LEFT / RIGHT sont des boutons D-pad, pas un stick analogique.

Code de triche


Le combo complet ressemble à ceci:

  1. Tenez les pare-chocs L + R et appuyez sur Z
  2. D-up
  3. C-DOWN
  4. C-up
  5. D-down
  6. D-gauche
  7. C-gauche
  8. C-DROIT
  9. D-DROIT
  10. A + B
  11. COMMENCER

Ça marche! Connectez le contrôleur au deuxième port et entrez le code, après quoi les informations de débogage apparaissent. Après cela, vous pouvez commencer à appuyer sur les boutons du deuxième (voire du troisième) contrôleur pour effectuer diverses actions.

Ce combo fonctionnera sans patcher le numéro de version du jeu. Il peut même être utilisé dans une copie régulière du jeu au détail sans outils de triche ou mods de console. Une nouvelle saisie des combos désactive le mode zuru.

Utiliser le code sur un vrai GameCube

Le message "ZURU% d /% d" est zurumode_callbackutilisé pour afficher l'état de cette combinaison si vous le saisissez lorsque l'ID de disque est déjà égal 0x99(probablement pour déboguer le code de triche lui-même). Le premier nombre correspond à votre position actuelle dans la séquence correspondante r5. Le second prend la valeur 1, lorsque certains boutons de la séquence sont maintenus, ils peuvent correspondre au moment où la r6valeur est affectée 1.

La plupart des messages n'expliquent pas ce qu'ils font à l'écran, donc pour comprendre leur fonction, vous devez trouver des fonctions qui les traitent. Par exemple, une longue ligne d'étoiles bleues et rouges en haut de l'écran sont des espaces réservés pour afficher l'état de diverses quêtes. Lorsque la quête est active, certains numéros y apparaissent, indiquant l'état de la quête.

L'écran noir affiché en appuyant sur Z est une console pour afficher les messages de débogage, en particulier pour les aspects de bas niveau, tels que l'allocation de mémoire, les erreurs de tas et autres mauvaises exceptions. Par comportement, fault_callback_scrollon peut supposer qu'il est utilisé pour afficher ces erreurs avant le redémarrage du système. Il ne lance aucune de ces erreurs, mais peut les amener à imprimer quelques caractères parasites avec plusieurs NOP. Je pense qu'à l'avenir, il sera très utile pour afficher vos propres messages de débogage:

JUTConsole ordures caractères

Après avoir fait tout cela, j'ai découvert que passer en mode débogage en corrigeant l'ID de
version est 0x99déjà connu des autres: https://tcrf.net/Animal_Crossing#Debug_Mode . (Il y a aussi de bonnes notes sur le lien qui indiquent divers messages et parlent d'autres choses qui peuvent être faites avec le contrôleur dans le port 3.) Cependant, pour autant que je sache, personne n'a encore publié la combinaison de triche.

C’est tout. Il y a d'autres fonctionnalités pour les développeurs que j'aimerais explorer, comme l'écran de débogage de la carte et l'écran de sélection de l'émulateur NES, et comment les activer sans utiliser de correctifs.

Écran de sélection de carte


De plus, je publierai des articles sur la rétro-ingénierie des systèmes de dialogue, des événements et des quêtes dans le but de créer des mods.

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


All Articles