Recherche de l'offset d'un jeu
Pokedeus - 14 mai 2011 à 11:32 Bonjour ! Je voudrais savoir comment trouver l'offset d'un jeu pour créer des codes action replay sur celui-ci. Existe-t-il un tutoriel en anglais ou en français ?? Parce qu'il y a beaucoup de tutos pour créer des codes AR avec Emucheat mais je n'ai toujours pas réussi à en trouver un sur les offsets. Merci de votre compréhension, j'attends votre aide.
lVl477l-l13Ll - 14 mai 2011 à 11:39 Tu veux dire, l'adresse mémoire du pointeur ? La plupart des jeux n'en ont pas, et pour ceux qui en ont, regarde les codes existants, tu la trouveras sans doute. Sinon, perso j'utilise un programme appelé "NDS Pointer codes & Backtracer Tool" (NDS PC&BT) qui compare deux dumps de RAM pour rechercher le pointeur. Ça fonctionne plutôt bien, mais j'ai pas le temps de faire un tuto. EDIT : Tu pourras le trouver ici : http://www.kodewerx.org/forum/viewtopic.php?t=721
Pokedeus - 15 mai 2011 à 13:12 Merci beaucoup. Enfin, j'aimerais quand même être sûr : Par exemple, dan ton tutoriel pour EmuCheat avec Pokémon Version Platine (http://www.pokemontrash.com/club/triche/nouveaux-codes-inedits-pour-pokemon-platine-fr-!/msg85916), tu dis à un moment :
Ensuite, il faut connaître l'offset actuel du jeu.Rien de plus facile, rendez-vous dans l'onglet "Search" puis le sous-onglet "Memory Edit". Entrez 101F20 dans le champ "Address" et cliquez sur "Show Address" (ou appuyez sur la touche "Entrée". Et donc cette adresse de 101F20 (qui permet de connaître la valeur de l'offset), NDS Pointer codes & Backtracer Tool permet de la trouver ? Merci encore de ton aide.
lVl477l-l13Ll - 16 mai 2011 à 13:26 Ouaip, c'est son but (cette adresse est appelée un pointeur). Pour cela, il te faut deux dumps de RAM à deux moments où la valeur du pointeur est différente, et également connaître l'adresse mémoire absolue de quelque chose qui dépend du pointeur pour chacun de ces dumps. La plupart du temps, j'utilise l'adresse de l'argent du joueur, parce que c'est très facile à retrouver.
Pokedeus - 16 mai 2011 à 16:46 Merci beaucoup M@T ! Je suis vraiment désolé de t'importuner encore, mais j'aurais encore deux questions : 1) Dans tes explications, si j'ai bien compris, l'adresse mémoire absolue est 0AAAAAAA ??
Nous avons l'offset et l'adresse mémoire des PCa (que l'on va noter 0AAAAAAA).Or, cette adresse mémoire est formée comme ça : 0AAAAAAA = 0XXXXXXX + offset. Un peu de maths, et on obtient : 0XXXXXXX = 0AAAAAAA - offset. Dans mon cas, ça donne : 0XXXXXXX = 0x02284DB8 - 0x0227E434. 2) Pour définir la valeur du pointeur (dans ton tuto de Platine, 101F20), il faut dans le code Action Replay une ligne de cette forme : B2XXXXXX 00000000 où XXXXXX est le pointeur ? J'ai cru comprendre ça en regardant les différents codes des différents jeux car j'ai vu que pour les codes Platine cette ligne est B2101F20 00000000 et pour les codes Blanc/Noir elle est B2000024 00000000, donc je suppose qu'il faut placer B2 au début. Est-ce que c'est cela ? Merci encore pour ton aide, M@T.
lVl477l-l13Ll - 16 mai 2011 à 16:55 En effet, c'est bien ça pour les deux. Attention cependant, il faut bien se souvenir qu'une adresse mémoire est toujours de la forme 0x02XXXXXX (sauf pour certaines choses liées au système ; par exemple les touches pressées c'est à 0x04000130). EmuCheat n'affiche que les 3 derniers octets des adresses mémoire, donc 0xXXXXXX quand on considère 0x02XXXXXX (n'oublions pas que le préfixe "0x" désigne un nombre hexadécimal). D'où le "2" dans "B2101F20" : c'est en fait un "B" ajouté à l'adresse mémoire 0x02101F20. Cette instruction sert à ajouter dans la valeur courante de l'offset la valeur à l'adresse qui vient après le B. Donc la ligne "B2101F20 00000000" veut dire "valeur de l'offset = valeur de l'offset + valeur à l'adresse 0x02101F20". De plus, l'instruction "B" est affectée par l'offset courant. Donc la vraie instruction c'est "valeur de l'offset = valeur de l'offset + valeur à l'adresse [0x02101F20 + valeur de l'offset]". Comme au début de chaque code, l'offset vaut 0, ça peut se réduire à "valeur de l'offset = valeur à l'adresse B2101F20". (attention, ce n'est vrai que quand l'offset vaut 0 ; dans D/P par exemple, il y a un double-pointeur)
Pokedeus - 16 mai 2011 à 17:48 Merci. Et donc, dans le cas où il y a un double pointeur, quelle serait la procédure à suivre pour définir le pointeur ? Le pointeur étant une variable contenant l'adresse mémoire d'une autre variable, il y aurait quelque chose de ce genre : Pointeur 1 : XXXXXXXX YYYYYYYY Pointeur 2 (vers offset) :YYYYYYYY AAAAAAAA ? Et comment trouver le pointeur 1 dans ce cas ? Parceque on peut arriver au pointeur deux à l'aide de ton programme, mais après, s'il change chaque fois... Merci encore de ton aide !
lVl477l-l13Ll - 16 mai 2011 à 17:55 Le programme peut rechercher un double-pointeur, mais c'est beaucoup plus long et le résultat n'est pas assuré (y'a une case à cocher).
Pokedeus - 16 mai 2011 à 18:04 Merci. Mais pour définir le double pointeur dans le code, il faudra écrire : BXXXXXXX 00000000 BYYYYYYY 00000000 où 0XXXXXXX est le pointeur qui pointe vers 0YYYYYYY ??
lVl477l-l13Ll - 16 mai 2011 à 18:12 Yep, exactement. Sachant que 0YYYYYYY peut être décalé de la valeur pointée par 0XXXXXXX, comme par exemple pour Pokémon D/P, où le 2ème pointeur est décalé de 4 octets : B21C4EA8 00000000 B0000004 00000000 D'ailleurs, je viens de me rendre compte que j'ai dit une connerie un peu plus tôt ; le code "B" n'ajoute pas la valeur à l'offset, il la définit. Sinon, le code ci-dessus ne fonctionnerait pas.
Pokedeus - 16 mai 2011 à 19:39 Donc là, à la place de : B21C4EA8 00000000 B0000004 00000000 on peut écrire : B21C4EA8 00000000 B21C4EAC 00000000 ?? Cela reviendrait au même car on rajoute 4 à 21C4EA8, donc on peut écrire l'adresse complète, non ?? Ou bien il faut toujours que la définition du deuxième pointeur (B0000004 00000000 ici) se fasse par rapport au premier avec : BXXXXXXX 00000000 B[YYYYYYY-XXXXXXX] 00000000 où XXXXXX pointe vers YYYYYYY ?? Merci encore.
lVl477l-l13Ll - 16 mai 2011 à 20:46 Si j'ai bien compris ce que tu voulais dire dans la 2ème partie de ton message (à partir de "Ou bien", ça devrait être bon ; en fait, l'adresse du 2ème pointeur est calculée par rapport à l'offset. B21C4EA8 00000000 <- offset = (valeur à l'adresse 0x021C4EA8) B0000004 00000000 <- offset = (valeur à l'adresse [0x00000004 + offset]) Du coup, le 2ème pointeur est relatif à la valeur du 1er. Quand on résume les deux lignes, ça fait : offset = (valeur à l'adresse [0x00000004 + \{valeur à l'adresse 0x021C4EA8\}])
Pokedeus - 20 mai 2011 à 19:24 Merci et excuse-moi encore M@T : Quel est le programme nécessaire pour faire un dump de la RAM ?? Sinon, peut-on le faire directement sur N$Gba ? Parceque j'ai compris que ton programme exige deux adresses mais aussi deux fichiers, et comme il ne m'indique pas quel type de fichiers il faut,... voilà.
lVl477l-l13Ll - 21 mai 2011 à 17:56 Pour faire les dumps, perso j'utilise HasteDS. Lance No$GBA, charge la ROM, puis ouvre HasteDS, et il devrait trouver tout seul No$GBA (si ce n'est pas le cas, clique sur "Attach To Emulators". Pour faire le dump de RAM, clique sur "Memory Dump" dans HasteDS. Par contre, ça ne fonctionne pas pour les versions N/B, le dump est crypté. Mais il se trouve que DeSmuME peut faire des dumps de RAM décryptés, bien qu'il dump la totalité de la RAM, au lieu de seulement les 4 Mo qui sont utilisés par l'AR. C'est bien moins pratique, alors ça ne doit servir que pour les versions N/B.
Pokedeus - 21 mai 2011 à 19:23 Merci. Donc, en fait, la procédure à suivre pour trouver le pointeur est la suivante, si je ne m'abuse : 1) Lancer la ROM du jeu avec No$Gba puis lancer Emucheat et HasteDS. 2) Attacher Emucheat et HasteDS à No$Gba. 3) Rechercher l'adresse qui contient la quantité d'argent, par exemple, avec Emucheat, créer le code et le tester dans le jeu. 4) S'il marche, aller dans HasteDS et faire un dump de la RAM. 5) Reseter le jeu et recommencer les étapes 3-4. 6) Ouvrir NDS PC&BT, mettre les deux fichiers de dump et les adresses trouvées coresspondantes et cliquer sur Go! 7) Attendre qu'il trouve le pointeur. Est-ce que c'est comme cela qu'il faut procéder ?? Mais alors, y a-t-il un format spécifique (.bin, .dump, ...) sous lequel enregistrer le dump ???
lVl477l-l13Ll - 21 mai 2011 à 21:46 C'est EXACTEMENT ça, et tu donnes n'importe quelle extension, on s'en fout. Perso je mets .bin, mais ce sont les données qui importent, pas l'extension.
Pokedeus - 21 mai 2011 à 21:57 Merci ! Mais en fait, NDS PC&BT trouve plusieurs pointeurs. Chez moi, il en affiche trois : 02101F20:0227E3D0 021C0974:0227E3D0 0227E3A8:0227E3B0 Comme c'est Pokémon Platine, on sait déjà que le pointeur est 02101F20, mais imaginons qu'on ne le sait pas. Comment ferait-on pour trouver le bon ?? On les teste tous un par un ou il y a une méthode moins "barbante" ??
lVl477l-l13Ll - 21 mai 2011 à 22:27 Il se peut très bien que le jeu ait plusieurs adresses qui se "décalent" en même temps ; elles feraient donc toutes un bon pointeur. Perso, je prends toujours celle avec l'adresse la plus basse. Si tu en as vraiment beaucoup, c'est peut-être que certaines se retrouvent là par hasard, et ne sont pas des pointeurs valides. Pour éliminer les intruses, tu peux refaire la recherche avec deux dumps différents, et les pointeurs potentiels qui ne sont pas dans les deux résultats sont invalides.
Pokedeus - 21 mai 2011 à 23:10 Merci M@T ! Maintenant que je comprends un peu mieux les pointeurs, j'aurais une question plus technique qui touche directement les codes AR : Pourrais-tu me dire ce qui ne va pas dans ce code, code qui devait mettre des PV infinis (ou plutôt 999 pv) au Pokémon pendant le combat, s'il te plaît : 94000130 FCFF0000 62101F20 00000000 B2101F20 00000000 10047604 000003E7 1004CFB4 000003E7 1004D01C 000003E7 1006CEB2 000003E7 D2000000 00000000 Pour le trouver, j'ai lancé un combat dans le jeu, attaqué le Pokémon adverse avec une attaque qui n'enlève pas de PV (Rugissement) et quand il m'attaquaient et que mes PV diminuaient, je les mettais dans Emucheat. Au fur et à mesure, j'ai vu que il ne restait que 4 adresses (0x022C5A28, 0x022CB3D8, 0x022CB440, 0x022FB2D6) dans Emucheat, et que ces 4 adresses diminuaient au même moment et avaient toujours la même valeur. Donc, je leur ai soustrait l'offset, qui vaut 0x0227E424, et j'ai obtenu respectivement avec la calculatrice 0x00047604, 0x0004CFB4, 0x0004D01C, 0x0006CEB2 et donc j'ai fait le code (sachant que 0x000003E7 = 999). Cependant, il me donne un résultat bizarre. Comment le corriger ?? J'ai vu dans le code officiel que seule la ligne 10047604 000003E7 est présente (comment savoir laquelle choisir alors, quand dans Emucheat il y en a toujours 4 ?) et qu'il y a la ligne 10047608 000003E7 (je n'ai pas trouver d'adresse a laquelle en soustrayant l'offset on trouvait 0x00047608...).
lVl477l-l13Ll - 22 mai 2011 à 11:12 Il y a souvent plusieurs adresses mémoire impliquées dans ce genre de choses. Par exemple, une qui stocke la valeur des PV courants, l'autre qui sert de variable temporaire pour afficher les PV à l'écran, etc. Pour savoir laquelle est la plus importante, pas d'autre choix que de les tester une par une. Sinon, l'offset 0x00047608 contient les PV max du Pokémon. Ça évite les bugs d'affichage, comme ça le Pokémon a 999/999 PV, au lieu de par exemple 999/50.
Pokedeus - 22 mai 2011 à 15:52 Merci. Enfin, j'ai enlevé les lignes suivantes : 1004CFB4 000003E7 1004D01C 000003E7 1006CEB2 000003E7 Et il ne me reste donc que la ligne 10047604 000003E7, présente dans le code officiel : pourtant, j'obtiens quand même un effet bizarre (je ne parle pas de 999/50 pv) : en effet, j'ai 999/XX pv quand je lance le code, mais le plus étrange, c'est que quand l'adversaire m'attaque, je retrouve mes pv originels, il me les enlève tous et puis alors que ma barre de pv est vide j'ai 61/32 pv (dans mon cas) et je ne suis pas K.O. ... Est-ce que l'offset 0x00047608 permet également de palier à ce problème et si oui, comment le trouver avec Emucheat, vu que c'est une valeur qui ne change pas ? Ou plutôt, elle change mais uniquement si on arrête le combat, qu'un utilise un pv plus et qu'on recommence un combat. Est-ce que c'est comme cela qu'il faut donc procéder pour trouver l'offset et palier au problème ci-dessus ??
Pokedeus - 23 mai 2011 à 18:55 Excuse-moi, j'ai peut-être mal formulé ma question : l'adresse qui géré les PV maximum du Pokémon, est-ce qu'elle permet de régler tous les problèmes d'ordre graphique et si oui, comment la trouver avec Emucheat ?? Merci encore de ton aide, M@T. Je ne pourrais pas m'en sortir sans toi...
lVl477l-l13Ll - 23 mai 2011 à 19:22 Pour la trouver, il faut savoir qu'elle se trouve là. Dans tous les jeux Pokémon, elle est à ([offset des PV courants] + 4), mais ça peut varier selon les jeux. On la voit bien en utilisant la fonction "Memory Edit" de EmuCheat ; elle se trouve souvent à proximité des PV courants, et on peut la repérer en connaissant sa valeur en hexa.
Pokedeus - 23 mai 2011 à 22:41 Merci ! En fait, j'ai rencontré un autre problème : j'ai souhaité modifier le niveau du premier Pokémon dans mon équipe. Au début il était niveau 6, j'ai cherché cette valeur dans Emucheat, il en a trouvé plusieurs, puis je lui ai donné un Super Bonbon et j'ai refait une recherche avec 7, et le nombre de valeurs s'est réduit. Sauf que quand j'ai refait la même chose avec un autre Super Bonbon, Emucheat n'a plus trouvé aucune valeur. Est-ce que ce code est irréalisable car dépendant d'une adresse variable ou bien il y a une astuce pour contourner ceci ?? Merci encore de ton aide.
lVl477l-l13Ll - 23 mai 2011 à 23:04 Houlà, ça ne fonctionne pas comme ça. :baffan: Les données du Pokémon sont encodées, ce qui fait que quand une valeur change (l'expérience, en l'occurrence), les 236 octets du Pokémon changent, de manière quasiment aléatoire. À l'inverse, si on modifie un octet de ces données, le Pokémon sera corrompu et deviendra un Mauv.œuf. Tu ne pourras pas modifier les données du Pokémon de cette manière, à part son PID qui, lui, est en clair puisqu'il sert de clé pour l'encodage du Pokémon.
Pokedeus - 24 mai 2011 à 07:28 Merci. Quand tu dis de cette manière, ça veut dire qu'on peut quand même le faire, modifier les données du Pokémon ?? Il faut utiliser les "data register codes" ?? (le code que je cherchais faisait en fait qu'en appuyant sur L+R, le 1er Pokémon de l'équipe devenait niveau 100) Merci encore.
lVl477l-l13Ll - 24 mai 2011 à 11:47 Non, il faut profiter du fait que quand on marque un Pokémon dans le PC, le jeu décode temporairement ses données pour appliquer le marquage. D'où tous les codes de marquage que l'on voit fleurir ces derniers temps. Mais ça, c'est de l'ASM (de l'ARM Thumb plus exactement), et tu ne pourras rien faire avec EmuCheat. Par exemple, le code "Donner votre propre DO et sexe du DO à un Pokémon" pour la version Noire, c'est en fait ce code ASM : [spoiler=Code][code=ARM Thumb]0x02001e00 b4ff push \{r0, r1, r2, r3, r4, r5, r6, r7\} 0x02001e02 73b4 strb r4, [r6, #14] ... 0x02001f80 4808 ldr r0, [pc, #32] 0x02001f82 b43e push \{r1, r2, r3, r4, r5\} 0x02001f84 c83c ldmia r0!, \{r2, r3, r4, r5\} 0x02001f86 c13c stmia r1!, \{r2, r3, r4, r5\} 0x02001f88 bc3e pop \{r1, r2, r3, r4, r5\} 0x02001f8a 4807 ldr r0, [pc, #28] 0x02001f8c 81c8 strh r0, [r1, #14] 0x02001f8e b40c push \{r2, r3\} 0x02001f90 4806 ldr r0, [pc, #24] 0x02001f92 7800 ldrb r0, [r0, #0] 0x02001f94 7f0a ldrb r2, [r1, #28] 0x02001f96 237f movs r3, #0x7f 0x02001f98 401a ands r2, r3 0x02001f9a 01c0 lsls r0, r0, #7 0x02001f9c 4302 orrs r2, r0 0x02001f9e 770a strb r2, [r1, #28] 0x02001fa0 bc0c pop \{r2, r3\} 0x02001fa2 e005 b.n 0x02001fb0 0x02001fa4 f8ac 0224 0x02001fa8 ffff 0x02001faa 0000 0x02001fac 4f4d 0223 ... 0x02001ffc bcff pop \{r0, r1, r2, r3, r4, r5, r6, r7\} 0x02001ffe bdf8 pop \{r3, r4, r5, r6, r7, pc\} ... 0x020195b4 f7e8 fc24 bl 0x02001e00[/code][/spoiler] C'est BEAUCOUP plus compliqué, je te conseille de t'en tenir aux choses simples pour le moment.
Pokedeus - 24 mai 2011 à 21:40 Merci ! Bon, vu que le code de modifications des caractéristques d'un Pokémon est un peu compliqué, je vais revenir dessus plus tard (mais j'y reviendrais ). Par contre, j'ai un petit problème concernant tous les autres codes qui ne touchent pas des données chiffrées (comme l'argent) du jeu, à commencer par les objets. J'ai réussi plus ou moins à interpréter le code ci-dessous à l'aide de EnHacklopedia mais j'aurais quand même besoin de ton aide s'il te plaît, M@T : 94000130 FCFF0000 62101F20 00000000 B2101F20 00000000 D5000000 03E60011 C0000000 00000025 D6000000 00000B60 D4000000 00000001 D2000000 00000000 Bon, passé les trois premières lignes, j'ai compris "à peu près" que D5000000 03E60011 permettait de déterminer le nombre d'objets à générer, 0x03E6, soit 998. Après, C0000000 00000025 définissait le début de la boucle qui se répete le nombre de fois qu'il existe d'objets dans la partie du sac (en l'occurence, 37 dans la partie des Médicaments). Cependant, certains détails m'ont échappé : d'abord, j'ai bien compris que le 0x0011 de D5000000 03E60011 définissait la poche du sac pour les Médicamants mais comment trouver cette valeur ?? Ensuite, je n'ai pas bien compris le fonctionnement de la ligne D6000000 00000B60 (à part le fait qu'elle créait l'objet...) et l'utilité de D4000000 00000001 vu que comme on a une boucle qui va se répéter 0x25 fois, pourquoi incrémenter le data register de 1 ?? Merci encore de ton aide.
lVl477l-l13Ll - 24 mai 2011 à 22:34 En fait, c'est un peu plus compliqué que ça. Dans la RAM, les objets du sac sont stockés sous forme de deux entiers 16 bits (2 octets) adjacents, l'un pour l'ID de l'objet, l'autre pour la quantité. Comme ils sont adjacents, on peut les regrouper sous forme d'un seul entier 32 bits. On aura par exemple, pour 999 Master Balls : 01 00 E7 03 (représentation dans la RAM) ; 0x03E70001 (représentation 32 bits correspondante). La ligne "5000000 03E60011" sert à mettre la valeur du registre "ata" à 0x03E60011, ce qui correspond à une quantité de 998 de l'objet ayant l'ID 17 (0x11). Ensuite, la ligne "C0000000 00000025" définit le commencement d'une boucle qui se répétera 0x25 (= 37) fois, donc elle s'exécutera 38 fois en tout. La ligne "6000000 00000B60" écrit les 32 bits la valeur courante du registre "ata" à l'adresse [0x00000B60 + offset] (l'offset a été défini avec la ligne "B2101F20 00000000". Ça incrémente également de 4 la valeur courante de l'offset. Comme l'adresse [0x00000B60 + offset] (quand l'offset a été défini par le bon pointeur) correspond au 1er emplacement de la poche médicaments, à chaque itération de la boucle, on écrit à l'emplacement suivant. Puis vient la ligne "4000000 00000001", qui ajoute 1 à la valeur du registre "ata". Ça permet de passer à l'objet avec l'ID suivant, donc logiquement l'objet suivant dans la liste. Comme c'est relativement bien fait, les Médicaments sont ensemble, donc ça permet de parcourir la liste des médocs. Enfin, la ligne "2000000 00000000" sert d'abord à itérer la boucle, puis à réinitialiser tous les registres une fois toutes les itérations effectuées. Le code pourrait s'écrire comme ça, en "développant" la boucle : [spoiler]94000130 FCFF0000 62101F20 00000000 B2101F20 00000000 00000B60 03E60011 00000B64 03E60012 00000B68 03E60013 00000B6C 03E60014 00000B70 03E60015 00000B74 03E60016 00000B78 03E60017 00000B7C 03E60018 00000B80 03E60019 00000B84 03E6001A 00000B88 03E6001B 00000B8C 03E6001C 00000B90 03E6001D 00000B94 03E6001E 00000B98 03E6001F 00000B9C 03E60020 00000BA0 03E60021 00000BA4 03E60022 00000BA8 03E60023 00000BAC 03E60024 00000BB0 03E60025 00000BB4 03E60026 00000BB8 03E60027 00000BBC 03E60028 00000BC0 03E60029 00000BC4 03E6002A 00000BC8 03E6002B 00000BCC 03E6002C 00000BD0 03E6002D 00000BD4 03E6002E 00000BD8 03E6002F 00000BDC 03E60030 00000BE0 03E60031 00000BE4 03E60032 00000BE8 03E60033 00000BEC 03E60034 00000BF0 03E60035 00000BF4 03E60036 D2000000 00000000[/spoiler] Sinon, pour connaître les différentes valeurs (adresses mémoire des poches du sac, ID des objets), le mieux c'est d'utiliser Pokésav.
Pokedeus - 24 mai 2011 à 23:01 Merci. Donc en fait, si j'ai bien suivi ton raisonnement, le code pour avoir tous les objets dans Platine est plus long parce que tous les objets ne sont pas situés les uns à la suite des autres, donc on refait plusieurs fois des boucles qui commencent à des adresses différentes ?? Merci encore.
lVl477l-l13Ll - 24 mai 2011 à 23:06 C'est exactement ça, tu apprends vite.
Pokedeus - 25 mai 2011 à 15:06 Merci. J'ai compris le fonctionnement total du code, mais tu pourrais s'il te plaît m'éclairer un peu sur le fonctionnement en général des data registers ?? Est-ce que ce sont des variables ? des tableaux ? Et généralement, comment savoir s'il faut les utiliser ?? Encore merci.
lVl477l-l13Ll - 25 mai 2011 à 17:37 L'Action Replay gère 2 registres principaux : le "x Data" et l'"offset" (il y en a d'autres utilisés pour le fonctionnement interne mais on ne peut pas y toucher). Le "x Data" est une variable unique, pouvant contenir un entier 32 bits (de 0 à 0xFFFFFFFF). On ne peut pas avoir d'autres variables dans les codes, donc on s'en sert dès qu'on doit utiliser une valeur temporairement. Si jamais il devait y avoir plusieurs variables, alors il faudrait les stocker quelque part dans une zone inutilisée de la RAM. La seule opération possible sur cette variable est l'addition (avec le code de type 0xD4). Bien entendu, ajouter un nombre très grand revient à soustraire. Par exemple, le code suivant soustrait 1 à la valeur 32 bits située à l'adresse 0x02345678 et la réécrit à la même adresse : D9000000 02345678 D4000000 FFFFFFFF D6000000 02345678 D2000000 00000000 En effet, si la valeur était 1, alors elle devient 1 + 0xFFFFFFFF = 0x100000000, or c'est une valeur 32 bits, donc seuls les 4 octets de poids faible sont conservés (en bleu), ce qui donne bien 0 = 1 - 1. Si la valeur était 0x12345678, elle devient 0x12345678 + 0xFFFFFFFF = 0x112345677, ce qui vaut bien 0x12345677 = 0x12345678 - 1. Et ainsi de suite. L'autre registre, l'offset, permet de "décaler" les adresses mémoire. Je t'explique quelques trucs au passage, même si ce n'était pas vraiment ta question. Il s'agit également d'une valeur 32 bits, mais on ne peut pas utiliser sa valeur directement, on peut juste la définir. L'addition sur l'offset se fait grâce au code de type 0xDC. Par le même principe que précédemment, on peut décaler "négativement" une adresse en définissant un offset suffisamment grand. Exemple avec un code qui écrit une valeur 16 bits à l'adresse 0x02345678 : D3000000 FFFFF678 12346000 0000CAFE D2000000 00000000 L'AR va écrire 0xCAFE à l'adresse [0x02346000 + 0xFFFFF678 = 0x102345678], ce qui revient bien au code suivant : 102345678 0000CAFE. Mais cette utilisation de l'offset négatif n'est pas vraiment utile ; c'est plutôt le contraire qui est utilisé. Ce code, par exemple, charge l'offset du pointeur à l'adresse 0x02101F20 et écrit à une adresse située avant l'adresse pointée : B2101F20 00000000 DC000000 FFFFF000 10000000 0000CAFE D2000000 00000000 Explications : tout d'abord, on définit l'offset comme étant la valeur à l'adresse 0x02101F20. Disons qu'elle vaut 0x02345678. Ensuite, on ajoute 0xFFFFF000 à la valeur de l'offset, ce qui donne 0x02345678 + 0xFFFFF000 = 0x102344678, donc la valeur de l'offset est désormais 0x02344678 (ça revient à soustraire 0x1000). Enfin, on écrit une valeur 16 bits à l'adresse [0x00000000 + offset], c'est-à-dire [0x00000000 + 0x02344678 = 0x02344678]. Et voilà, on a écrit une valeur à une adresse située 0x1000 octets avant l'adresse indiquée par le pointeur.
Pokedeus - 25 mai 2011 à 19:31 Merci énormément ! Pour voir si j'ai bien compris, est-ce que tu pourrais me dire s'il te plaît si le code ci-dessous est correct ?? B2101F20 00000000 <- On définit l'offset. D3000000 02345678 <- L'offset vaut 0x02345678. DC000000 FFFFFEAC <- On rajoute 0xFFFFFEAC à l'offset, soit on lui soustrait 0x154. 10000000 0000CAFE <- On écrit la valeur 16 bits 0xCAFE 0x154 octets avant la valeur indiquée par le pointeur (soit à l'adresse 0x0000000 + (0x02345678+0xFFFFFEAC) = 0x00000000 + 0x102345524 donc à l'adresse 0x02345524). D9000000 02345524 <- On charge la valeur à l'adresse 0x02345524 dans le Dx Data. D4000000 FFFFFFF2 <- On ajoute 0xFFFFFFF2 à 0xCAFE et on obtient donc 0xCAF0. D6000000 02345524 <- On remet la nouvelle valeur du Dx Data à l'adresse 0x02345524. D2000000 00000000 Est-ce que mon code est correct et est-ce que les différentes lignes effectuent ce que j'ai écrit à côté d'elles ?? Merci encore.
lVl477l-l13Ll - 25 mai 2011 à 19:41 Ça m'a l'air correct, mais la 1ère ligne est inutile, puisque tu redéfinis l'offset juste après. Par contre, garde bien en tête que ce genre d'utilisation des offsets, ça n'existe pas en vrai, car c'est extrêmement peu efficace. Quand on peut écrire directement l'adresse, on le fait. Mais c'est très bien pour les exemples. L'instruction 0xD3 est surtout utilisée pour remettre l'offset à zéro sans passer par l'instruction 0xD2, qui remet TOUT à zéro alors qu'il se peut qu'on ait besoin de conserver des choses comme le registre Data.
Pokedeus - 25 mai 2011 à 22:55 Merci. Excuse-moi, mais j'ai quand même l'impression de m'être trompé : j'ai à un moment écrit ça :
D9000000 02345524 <- On charge la valeur à l'adresse 0x02345524 dans le Dx Data.D4000000 FFFFFFF2 <- On ajoute 0xFFFFFFF2 à 0xCAFE et on obtient donc 0xCAF0. D6000000 02345524 <- On remet la nouvelle valeur du Dx Data à l'adresse 0x02345524. Je ne devrais pas plutôt mettre : D9000000 00000000 D4000000 FFFFFFF2 D6000000 00000000 Vu que quasiment tous les Data Register Codes de la forme DZ000000 XXXXXXXX vont pour effectuer leurs manipulations prendre [XXXXXXXX + offset] et comme l'offset vaut justement 0x02345524, il faut mettre 0x00000000 pour les instructions du Dx Data, non ?? J'ai lu ça sur EnHacklopedia en tout cas...
lVl477l-l13Ll - 25 mai 2011 à 23:52 Tu as totalement raison, j'avais pas fait gaffe, excuse-moi.
Pokedeus - 26 mai 2011 à 17:50 Merci. Excuse-moi encore une fois mais quand tu dis pour le code : B2101F20 00000000 DC000000 FFFFF000 10000000 0000CAFE D2000000 00000000
Et voilà, on a écrit une valeur à une adresse située 0x1000 octets avant l'adresse indiquée par le pointeur.Tu veux dire 0x1000 octets avant l'adresse indiquée par le pointeur au début ?? Parce que au début, l'offset vaut en effet 0x02345678 mais après la ligne DC000000 FFFFF000, il vaut 0x02344678 et avec la ligne 10000000 0000CAFE, on écrit 0xCAFE à l'adresse 0x02344678, qui est le nouveau offset. Donc en fait, 0xCAFE est écrit 0x1000 octets avant l'ancienne valeur de l'offset (0x02345678), pas la nouvelle (0x02344678), non ?? Est-ce que j'ai bien compris ??
lVl477l-l13Ll - 26 mai 2011 à 17:59 Le pointeur, c'est l'adresse 0x02101F20. Dans mon exemple, il pointe vers 0x02345678, et ça ne change pas, même quand on modifie l'offset par la suite.
Pokedeus - 26 mai 2011 à 20:01 Merci. Ah, donc en fait l'instruction BXXXXXXX 00000000 définit l'offset comme étant la valeur située à l'adresse 0XXXXXXX et toutes les modifications ultérieures sur la valeur de l'offset n'affectent pas cette instruction ?? En fait c'est comme si on copiait le contenu d'une variable x dans une variable y et qu'on modifiait y, ce qui fait que la valeur de x ne change pas, c'est cela ?? Merci encore.
lVl477l-l13Ll - 26 mai 2011 à 20:15 Ouais, c'est bien ça. On pourrait écrire ça comme ça (en disant qu'une adresse mémoire entre [crochets] signifie "valeur à cette adresse" : B2101F20 00000000 <- offset = [0x02101F20] // L'offset vaut la valeur à l'adresse 0x02101F20 DC000000 FFFFF000 <- offset = offset - 0x1000 // On soustrait 0x1000 à la valeur de l'offset (ça ne modifie pas la valeur à l'adresse 0x02101F20) 10000000 0000CAFE <- [offset] = 0xCAFE // La valeur 16 bits située à l'adresse mémoire "offset" vaut maintenant 0xCAFE D2000000 00000000 <- offset = 0; fin du code
Pokedeus - 27 mai 2011 à 16:20 Merci ! Maintenant, je souhaiterais savoir, si posssible, comment fais tu pour des codes qui sont encore plus éloignés des chiffres (pour les objets, ça va encore, il y avait les quantités, les numéros des objets, etc. donc il étaient encore assez "chiffrés" ) : mais par exemple, pour le code pour faire du vélo dans les bâtiments : 94000130 FFFE0000 B2101F20 00000000 20001324 00000001 D2000000 00000000 J'ai compris que pour ce cas (tout comme pour le sexe du personnage), 0x0 veut dire pas de vélo et 0x1 veut dire vélo. Mais après, comment fais-tu pour trouver l'adresse 0x00001324 ?? Parce que on ne peut pas chercher la valeur, vu qu'il y en a pas, à part ce 0x0 et 0x1 (et beaucoup d'autres variables risquent d'avoir les mêmes valeurs...) ?? Merci encore.
Pokedeus - 27 mai 2011 à 18:10 En fait, excuse-moi : j'ai réussi à trouver par moi-même le code pour faire le vélo dans les bâtiments. Par contre, pourrais-tu m'aider s'il te plaît à comprendre comment trouver le code pour traverser les murs : 94000130 FCFD0200 12060CC4 00002000 D0000000 00000000 94000130 FCFD0100 12060CC4 00001C20 D2000000 00000000 Dans ce code, j'ai cru comprendre que l'adresse 0x02060CC4 indiquait l'état du terrain sur lequel se trouve le personnage (traversable, pas traversable) et 0x2000 indiquait que le terrain était traversable et 0x1C20 que le terrain ne l'était pas. Est-ce que j'ai bien compris ?? Si oui, pourrais-tu s'il te plaît me dire comment tu t'y prendrais pour trouver cette adresse et ces valeurs (vu que dans le jeu, il ne traverse jamais les murs, on ne peut pas changer d'état comme pour le vélo...) ?? Merci encore de ton aide.
lVl477l-l13Ll - 28 mai 2011 à 04:04 Pour le vélo, il s'agit d'une valeur booléenne, qui vaut soit 0 (personnage pas sur le vélo), soit 1 (personnage sur le vélo). Afin de trouver l'adresse, pas le choix : monter sur le vélo, rechercher une valeur 8 bits valant 1 ; descendre du vélo, rechercher "0" ; monter, rechercher "1" ; etc. Concernant le code pour traverser les murs, c'est de l'ASM. Tout ne fonctionne pas uniquement avec des variables, il y a également un programme derrière pour faire fonctionner le jeu. En l'occurrence, il s'agit d'une routine (ou "procédure", "fonction", appelle ça comme tu veux) qui renvoie un booléen (0 ou 1 donc) selon si le joueur est bloqué ou non. Ça calcule sûrement des trucs par rapport à la case du terrain sur laquelle il se dirige et ça vérifie si il peut y aller ("0", il n'est pas bloqué ou pas ("1", il est bloqué. L'instruction d'origine est "1C20", soit, traduit en ARM Thumb : mov r0, r4 (r0 est le registre de retour de la procédure). En fait, juste avant dans la RAM, la routine fait quelques calculs dont le résultat est placé dans le registre r4. Là, ça copie la valeur de r4 et la place dans r0, qui est la valeur de retour. Dans beaucoup de langages de plus haut niveau, ça pourrait s'écrire "return r4;". Le code remplace l'instruction par "2000", ce qui signifie : mov r0, 0 (placer "0" dans le registre r0). En clair, la routine retournera toujours 0, quel que soit le résultat du calcul précédent, ce qui fera croire au jeu que le joueur n'est jamais bloqué ("return 0;". Tu peux essayer ce code-ci, qui aura pour effet de toujours renvoyer 1, ce qui fera que le joueur est toujours bloqué ("2001" -> "mov r0, 1" -> "return 1;" : 12060CC4 00002001 Pour trouver ces adresses-là, c'est beaucoup plus compliqué ; il faut un débogueur et savoir l'utiliser (breakpoints et tout le tralala).
Pokedeus - 28 mai 2011 à 10:10 Merci ! Et pour le code pour passer du héros masculin au héros féminin : 94000130 FCFF0000 B2101F20 00000000 20000094 00000001 D2000000 00000000 Est-ce qu'on peut trouver l'adresse de 0x94 avec Emucheat ou bien il faut utiliser aussi un débogueur (vu que l'on ne se transforme pas facilement en fille dans le jeu...) ?? Vu que c'est quand même juste une valeur booléenne, je serais tenter de dire que Emucheat suffirait, mais je sèche complètement pour savoir comment la trouver... Merci encore de ton aide.
lVl477l-l13Ll - 28 mai 2011 à 10:57 C'est en effet une valeur booléenne (0 -> garçon et 1 -> fille) ; pour la trouver le débogueur ne sert à rien, et EmuCheat non plus à vrai dire. Ça se passe plutôt du côté de la sauvegarde à mon avis ; COM (l'auteur de Pokesav) a dû comparer deux sauvegardes similaires avec chacune le personnage de sexe opposé à l'autre. Avec quelques essais il a dû trouver l'offset dans la sauvegarde, et à partir de là c'est assez facile de retrouver l'offset dans la RAM (il y a une correspondance entre certaines zones de la sauvegarde avec certaines zones dans la RAM). Il ne faut pas se leurrer, pas mal de codes comme celui-ci sont générés par Pokesav ; COM nous mâche pas mal de boulot.
Pokedeus - 28 mai 2011 à 22:59 Merci ! Excuse-moi, je reviens un petit peu en arrière, mais j'aurais encore une question pour le code des objets : en cherchant les adresses et les identités des objets (pour faire les codes) sur celui-ci, je ne les ai pas trouvés. Dans le menu "Editer" des objets, il y avait juste le nom des objets et rien d'autre... Est-ce qu'il faut utiliser la fonction codes AR du Pokésav pour cela ?? Mais il me donne alors un code bien plus long et qui semble écrit en ARM Thumb (ici le code pour les médocs en 998) : 94000130 FCFF0000 B2101F20 00000000 E0000B60 000000A0 03E60011 03E60017 03E60018 03E60019 03E6001A 03E6001E 03E6001F 03E60020 03E60021 03E60022 03E60023 03E6002B 03E6002C 03E60026 03E60027 03E60028 03E60029 03E60012 03E60013 03E60014 03E60015 03E60016 03E6001B 03E60024 03E6002A 03E6001C 03E6001D 03E60025 03E6002D 03E6002E 03E6002F 03E60030 03E60031 03E60032 03E60033 03E60034 03E60035 03E60036 00000000 00000000 D2000000 00000000 On reconnaît des éléments comme le début de la liste des médocs en 0xB06 et les ID des objets mais pourquoi certains ID sont sautés et à quoi sert la ligne E0000B60 000000A0 ?? C'est donc de ce code qu'il faut s'aider pour faire le code "réduit" , c'est cela ?? Merci encore de ton aide !
lVl477l-l13Ll - 29 mai 2011 à 04:09 En effet, il faut exporter un code AR pour trouver l'ID de l'objet. Sinon, c'est pas de l'ARM, c'est juste un code de type "E", qui sert à écrire un grand nombre d'octets consécutifs d'un coup. La ligne "EXXXXXXX YYYYYYYY" copie les YYYYYYYY octets qui suivent cette ligne vers l'adresse [0XXXXXXX + offset]. Par exemple, ce code-ci : E2345678 00000010 00010203 04050607 08090A0B 0C0D0E0F Équivaut à celui-ci : 02345678 00010203 0234567C 04050607 02345680 08090A0B 02345684 0C0D0E0F Pour un nombre d'octets relativement faible comme là, on ne voit pas vraiment l'utilité, mais plus ça augmente, plus le ratio entre la longueur du code en utilisant le type "E" et celle en utilisant "0" (écriture de valeurs 32 bits) se rapproche de 1:2. C'est donc une bonne méthode pour réduire les codes où on a besoin d'écrire des plages de données (octets consécutifs). Sinon, certains ID sont "sautés" parce que les objets que tu choisis avec Pokesav ne sont pas toujours consécutifs ; là par exemple tu passes de 0x11 à 0x17 au début, puis tu refais ceux de 0x12 à 0x16 plus tard vers la moitié du code.
Pokedeus - 29 mai 2011 à 20:12 Merci. Encore une fois, pourrais-tu s'il te plaît m'aider à comprendre le code pour qu'à l'adversaire il reste 1 PV : 94000130 FCFF0000 621BEA80 00000000 B21BEA80 00000000 10005EC8 00000001 D2000000 00000000 Merci encore de ton aide. EDIT: Désolé de ne pas avoir précisé plus ma question, j'étais pressé. En fait, je souhaitais juste savoir comment tu faisais pour trouver l'adresse de 0x00005EC8 car en effet, on ne connaît pas les PV initials ?? Est-ce qu'il faut par exemple capturer un Pokémon, regarder ses PV, essayer d'en rencontrer un qui est du même niveau et du même sexe et avec cela tenter de trouver la bonne adresse ?? Est-ce que c'est la bonne technique ?? Merci encore de ton aide !
lVl477l-l13Ll - 30 mai 2011 à 08:09 Non, de toute façon tu ne connaîtras jamais les PV exacts, parce que les IV les font varier (contrairement au sexe qui n'a aucune influence). Il ne faut pas rechercher une valeur exacte mais une valeur qui diminue. Dans EmuCheat, faut d'abord rechercher "?" au début du combat (valeur initiale inconnue), puis "-" (ou "<", ça revient au même) à chaque fois que l'adversaire perd des PV.
Pokedeus - 31 mai 2011 à 15:56 Merci M@T ! Je m'étais justement demandé comment chercher des valeurs dont on sait juste si elles ont augmenté ou baissé par exemple. Donc, les signes seront les suivants, c'est cela ?? "?" -> Valeur inconnue. ">" ou "+" -> Valeur qui a augmenté. "<" ou "-" -> Valeur qui a baissé. "=" -> Valeur restée identique. "!=" -> Valeur qui a changé. Est-ce que c'est cela qu'il faut utiliser pour rechercher des valeurs dont on connait uniquement les variations ?? Parce que j'étais parfois confronté à ce problème avec Emucheat... Merci encore de ton aide !
lVl477l-l13Ll - 31 mai 2011 à 16:51 Ouaip, c'est bien ça.
Pokedeus - 1 juin 2011 à 17:44 Merci encore ! Je viens de remarquer aujourd'hui que le code pour les events (Arceus, Darkrai, etc.) dans Pokémon Platine est assez spécial, et je ne le comprends pas du tout. Pourrais-tu s'il te plaît "éclairer ma lanterne" ?? J'ai pris ici le code pour débloquer l'event de la Flûte Azurée : 94000130 FCFF0000 621BFCD0 00000000 B21BFCD0 00000000 B0000004 00000000 0000B600 EDB88320 2000B62C 0000000A D2000000 00000000 D'abord, ce qui m'étonne et m'intrigue énormément, c'est que on n'utilise pas le même pointeur que dans les autres codes, soit 0x02101F20, mais bien 0x021BFCD0... Je ne comprends absolument pas, d'autant que ce n'est même pas un autre pointeur que nous donne NDS PC&BT lors de sa recherche. Il avait en effet trouvé ces trois pointeurs chez moi : 02101F20:0227E3D0 021C0974:0227E3D0 0227E3A8:0227E3B0 Et ce qui est utilisé ici ne correspond à aucun d'eux. Pourrais tu s'il te plaît m'expliquer pour quelle raison ?? D'autre part, le reste du code m'est presque aussi obscur : pourquoi après avoir défini le pointeur à la ligne B21BFCD0 00000000, on en redéfinit un autre (assez étrange d'ailleurs) à la ligne d'après (B0000004 00000000) ?? D'autre part, j'avoue franchement ignorer la "raison d'existence" de la ligne 0000B600 EDB88320 et je ne comprends qu'à moitié la ligne 2000B62C 0000000A (j'ai juste compris que le 0xA est le type de l'événement (Arceus, Shaymin, etc.) et 0xB62C l'adresse où le mettre, mais pour trouver cette adresse...). Je suppose que ce code fait encore une fois appel à de l'ARM thumb, mais je ne suis pas sûr. Merci encore de ton aide M@T !
Pokedeus - 2 juin 2011 à 08:44 Excuse-moi encore une fois, j'ai trop écrit et je me suis peut-être mal expliqué. En fait, je ne comprends tout simplement pas le code en entier cette fois-ci. Pourrais-tu, s'il te plaît, me l'expliquer rapidement ?? Merci beaucoup pour ton aide, M@T !
