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 .
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_callbackdans la structurepadmgr
- Appelle zurumode_update
zurumode_update
- Vérifie plusieurs bits dans osAppNMIBuffer
- En fonction de la valeur de ces bits, zurumode_flagmet à 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».
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?
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?
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»:
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.
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:
Après avoir inséré NOP au lieu de plusieurs autres constructions de ramification, j'ai commencé à voir diverses choses intéressantes à l'écran:
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. "
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:
À 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_classelle-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:
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 38c00001Cela 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, 28Il 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  
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:- Le bit 26 est défini sur 0x3C(osAppNMIBuffer)
- Le bit 25 est défini sur 0x3C(osAppNMIBuffer)et le contrôleur est connecté au port 2
- 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.
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:
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]=0x00000078Tous 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?
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:
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.
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 deXOR à partir de 1 sera 1 . Si la valeur est 1, le résultat sera 0. Voir la table de vérité pour XOR.)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.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

old_vals = old_vals XOR new_vals
old_vals = old_vals AND new_valsr0r00x1000r50xA. 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:8040ed38
- 8040ed34: la valeur- r0doit être égale- 0x4000(le bouton B est enfoncé)
- 8040ebe0: la valeur- r5doit être égale- 0x5b
- 8040eba4: la valeur- r5doit être supérieure- 0x7
- alors tout se passe comme avant ...
r5 devrait commencer par 0x5b8040ed00
- 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érieure- 0x5b
- 8040eba4:- r5devrait être plus- 0x7
- alors tout se passe comme avant ...
r5 devrait commencer à 98040ed50
- 8040ed4c: la valeur- r0doit être égale- 0x8000(bouton A enfoncé)
- 8040ec04: la valeur- r5doit être inférieure- 0x5d
- 8040ebe4: la valeur- r5doit être supérieure- 0x5b
- 8040eba4: la valeur- r5doit être supérieure- 0x7
- alors tout se passe comme avant ...
r5devrait commencer par 0x5cIl 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, STARTAvant 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 égaux0x2030: 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:- Tenez les pare-chocs L + R et appuyez sur Z
- D-up
- C-DOWN
- C-up
- D-down
- D-gauche
- C-gauche
- C-DROIT
- D-DROIT
- A + B
- 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.Le message "ZURU% d /% d" estzurumode_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:Après avoir fait tout cela, j'ai découvert que passer en mode débogage en corrigeant l'ID deversion 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.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.