Approche de l’ASM NES

Quelques approches possibles du reverseengineering de ROM NES aka un essai raté de recueil de quelques techniques que j'utilise pour « hacker » les ROM NES en ayant recourt à l'assembleur.
Par Graou (Mars 2006) – Génération IX

Table des matières


1) Préliminaires

Tout d'abord, je tiens à préciser que ce document ne s'adresse pas à quelqu'un pour qui les termes assembleur, mapper, RAM, ROM, et j'en passe, sont totalement inconnus.
Je recommande très fortement à toute personne souhaitant se lancer dans le « reverse-engineering » (juste histoire de mettre un mot compliqué et de me la péter :P), de d'abord se familiariser avec la plateforme cible, c'est à dire dans notre cas la NES / Famicom de Nintendo.

Pour ce faire, je recommande tout particulièrement d'aller faire un tour sur le site http://www.nesdev.com et par la suite en cas de doute sur les caractéristiques de la bête d'aller voir en premier lieu à l'adresse suivante : http://www.nesdev.com/wiki

Un bon moyen de se faire la main, et de ce fait de ne pas être complètement paumé par la suite est de d'abord essayer de coder quelques petits programmes pour la NES. Ceci n'étant pas le but de ce document, j'invite les intéressés à aller voir sur Nesdev.

 

2) Les outils nécessaires (ou ceux que j'utilise)

Au cours de ce tutoriel, j'utiliserai l'émulateur FCEUXD SP (version 1.6 pour ceux qui veulent des détails). Celui-ci est au moment où j'écris ces lignes disponible ici : http://www.the-interweb.com/serendipity/. Évidemment, les techniques présentées ici peuvent être mises en œuvre avec n'importe quel autre émulateur, à condition que celui-ci dispose de fonctionnalités similaires (comprendre un « debuger » bien foutu :P).

J'aime bien travailler avec un désassembleur afin d'avoir un bon gros fichier texte à commenter avec mes trouvailles. Évidemment, désassembler une ROM entière est assez violent, et pas toujours conseillé (étant donné qu'il est impossible de différencier les données du code, le résultat n'est pas toujours pertinent, enfin bref ...). Celui que j'utilise personnellement, plutôt par habitude que parce qu'il est bien, est TraCER disponible une fois encore sur Nesdev.

Pour désassembler toute la ROM, rien de plus simple ...

TRaCER -N -I -o Nom_de_la_rom

Sinon, toujours plus par habitude que pour autre chose :D, je me sers de l'assembleur XORcyst de Kent Hansen, disponible à l'adresse suivante :
http://folk.ntnu.no/kenth/xorcyst/index.htm

 

3) Quelques rappels

Je vais maintenant rappeler certaines notions importantes pour ce que l'on veut faire. Je ne serai peut-être pas toujours ultra précis donc ...

1. A quoi ça sert tout ça ...

Sans doute la première question qu'il faut se poser 😛

Je répondrais « à tout plein de choses ». Après, je pense qu'il est utile de bien évaluer l'utilité d'avoir recours à l'assembleur, car bien souvent il existe de moins fastidieux pour hacker une ROM. Ceci étant, voici une liste non-exhaustive de ce que l'on peut faire (d'utile pour une traduction) en modifiant le code du jeu :

  • Agrandir la ROM, et plus précisément, pouvoir tirer parti de la place disponible (d'origine ou non) dans la ROM ;
  • Modifier la police du jeu. Par exemple se débrouiller pour que le jeu affiche des caractères en 8*16 pixels plutôt que des petits caractères en 8*8 tout moches quand ils sont accentués ;
  • Identifier, comprendre, et modifier une éventuelle compression du script d'un jeu. De même, avoir la possibilité d'utiliser un script compressé afin de gagner de la place ;
  • Agrandir des cadres de texte ;
  • Et virtuellement tout ce qu'on veut.

Bien évidemment, cela a un prix, étant donné que ça peut être long et fastidieux 😛

 2. Quelques points techniques

Bon étant quelqu'un de bordélique, et en aucun cas doué pour écrire ce genre de document, je vais balancer tout ce qui me passe par la tête sans vraiment d'ordre précis 😛

Les Mappers :
L'espace adressable de la NES est comme tout le monde le sait, ou comme toute personne ayant lu ce document jusqu'ici devrait savoir, limité à 16bits. Les adresses 0 .. $7FFF sont occupées par la RAM, les registres de la machines, ...

Reste donc les adresses $8000 .. $FFFF pour charger la ROM. Hors, $8000 octets (32ko) sont bien peu pour un jeu NES. Ainsi, la plupart des jeux ont recours à ce que l'on appelle un mapper pour palier à ce problème.

Les ROM sont décomposées en banks (ou bancs mémoires en Français il me semble), bref découpées en morceaux de taille variables, traditionnellement de $2000, $4000 ou $8000 octets. Toutes ces banks ne pouvant être chargées simultanément dans la mémoire de la console, on utilise le fameux mapper pour charger/décharger les banks au fil de l'exécution du code.

La communication avec le mapper s'effectue par l'intermédiaire de registres qui sont alors accessibles par des adresses particulières en mémoire (genre $8000, $C000, ... ça dépend du mapper).

Bref, si l'on veut déplacer des choses dans la ROM, il sera souvent nécessaire de rajouter du code pour changer de bank si besoin est.

Les Tiles, les pattern tables et les nametables :
L'affichage de la NES est basé sur deux choses. Les sprites et le background, le fond quoi. Ce qui nous intéresse en tant que traducteurs est principalement le background. Celui-ci est construit à partir de blocs de 8*8 pixels nommés tiles. Pour être précis, il est constitué de 32*30 tiles. Ce système est efficace puisque l'on peut stocker d'un côté les différents tiles utilisés, et d'un autre côté la définition du background à partir de ces tiles.

Les tiles sont stockés dans une « pattern table ». Celle-ci comporte 256 tiles. A chaque tile est associé son indice dans cette table.

La définition du background est elle stockée dans ce que l'on appelle une « nametable ». Cette définition est faite en utilisant les indices des tiles à utiliser.

Tout ceci est illustré par le merveilleux schéma qui suit ...
Pattern Table + Name Table = Rendu Final

approche_rendu_pattern_table

Bref pour en revenir à nos problèmes de traduction, la police sera souvent stockée dans la pattern table, avec dans le cas d'une police en 8*8 pixels, un tile par caractère (2 dans le cas d'une 8*16). Le texte sera affiché en écrivant dans la nametable les indices des tiles associés aux caractères à afficher.

Les accès à la mémoire de la PPU (Picture Processing Unit) :
Il est important de savoir que l'on n'accède pas à la mémoire de la PPU comme l'on accède à la RAM de la console. En effet, la mémoire de la PPU est séparée de l'espace d'adressage normal. Pour y accèder, il faut passer par des
registres de la PPU. Ces registres sont accessibles aux adresses $2006 et $2007 dans l'espace d'adressage normal.

$2006 sert à déterminer l'adresse utilisée lors des accès par $2007. A chaque accès par $2007 se registre s'incrémente de 1 ou 32 selon la configuration de la PPU (configurable par $2000). Le bus étant de 8 bits, les adresses s'écrivent en 2 fois. On écrit d'abord l'octet de poids fort.

$2007 est le registre d'entrée/sortie de la PPU. Il permet d'accéder en lecture ou écriture à la valeur se trouvant à l'adresse courante dans la mémoire de la PPU.

Ainsi pour écrire la valeur $12 à l'adresse $2284 de la PPU, il faudra faire :

LDA #$22 STA $2006 LDA #$84 STA $2006 LDA #$12 STA $2007

 

4) Une brève présentation de l'émulateur

Pour ne pas trop me prendre la tête je vais essayer d'illustrer un peu tout ça. Voici donc le menu le plus important pour ce que l'on veut faire.

approche_asm_emulateur

C'est par ce menu que l'on accède aux outils que nous utiliserons par la suite, à savoir :

  • Le débuggeur (Debug) ;
  • Le visualiseur de PPU (PPU Viewer) ;
  • Le visualiseur de Name Table (Name Table Viewer) ;
  • Le visualiseur/éditeur de la mémoire de la console (Hex éditor) ;
  • Le Tracer dont je ne parlerai pas dans ce document (Trace Logger).
a) Le débuggeur

Là encore, si vous n'avez jamais touché à un débuggeur, ce n'est pas gagné 😀 Bref, voici à quoi ressemble celui de FCEUXD SP.

approche_asm_debugger

A mon avis, le plus utile à localiser pour ce que l'on veut faire est le petit cadre en haut à droite, qui concerne les breakpoints. Les breakpoints permettent de mettre en pause l'exécution du programme lorsque certaines conditions sont remplies.

Par exemple, lorsque l'on exécute l'instruction se trouvant à une certaine adresse, ou que l'on tente de lire la valeur à une autre adresse. On peut également définir des breakpoints plus poussés, en disant par exemple que l'on
souhaite que le programme s'arrête lorsque l'on essaye d'écrire une valeur donnée à une adresse donnée. Bref, voici le menu qui sert à ajouter des breakpoints (cliquer sur Add pour y accèder).

approche_asm_breakpoint
Simple, sobre, efficace 😛

Comme on le remarque assez vite, un breakpoint se défini sur une adresse, ou une plage d'adresses. Il peut s'agir d'un breakpoint en lecture, écriture ou exécution.

En Lecture, l'exécution s'arrêtera lorsqu'il y aura un accès en lecture à l'adresse/plage d'adresses définie au-dessus. Par exemple lors d'un LDA $XX où XX l'adresse sur laquelle le breakpoint a été défini.

En écriture, l'exécution s'arrêtera lorsqu'il y aura une écriture à l'adresse/plage d'adresses définie au dessus. Par exemple lors d'un STA $XX.

En exécution, le programme s'arrêtera lorsque le compteur ordinal (PC) sera égal à l'adresse définie.

Par ailleurs, la NES dispose de trois mémoires distinctes sur lesquelles il est possible de définir des breakpoints. Ce sont : la mémoire centrale (CPU Mem), la mémoire de la PPU (PPU Mem), et la mémoire des sprites (Sprite Mem). Nous nous servirons surtout des deux permières. Bref un breakpoint est donc défini à une adresse/plage d'adresses dans une de ces trois mémoires.

Nous ne nous attarderons pas sur les deux champs en dessous qui servent à définir des breakpoints conditionnels pour, comme je l'ai abordé précédemment, que le breakpoint soit pris en compte sous des conditions
spéciales (registre A = #$12, ...).

b) Le Visualiseur de PPU

Celui-ci sert à visualiser les pattern tables ainsi que les palettes. Son utilité est assez limitée, mais dans un soucis de complétude, je le présente quand même 😛

approche_asm_visu_PPU

Bref, en bas se trouvent les palettes ... oui je sais, je suis trop fort. Au-dessus se trouve les deux pattern tables. Une pattern table peut être utilisée soit pour le background soit pour les sprites. Dans l'exemple ci-dessus, celle de gauche est celle des sprites. Elle contient les 256 tiles utilisés par les sprites. A droite, c'est la pattern table pour le background. Soit les 256 tiles utilisés par les nametables.

Lorsque l'on survole un tile, son numéro s'affiche en dessous (la principale utilité de ce truc).

c) Le Visualiseur de Name table

Celui-ci sert à visualiser les name tables ... oui je sais, ce n'est pas vraiment original, mais bon ... Bref jetons-y un oeil.

approche_asm_exemple_nametable

Pour aller directement à l'essentiel, le plus utile est le cadre « Properties » tout en bas à droite. Il affiche les propriétés du tile actuellement survolé par le curseur de la souris.

TileID : correspond à l'indice du tile dans la pattern table.
X/Y : ses coordonnées dans la nametable.
PPU Address : l'adresse correspondante dans la mémoire de la PPU (hu hu ! On me sent venir avec mes breakpoints).
Mirror : Ben... On s'en fout pour le moment.

d) L'éditeur de mémoire

Je ne vais pas m'attarder là-dessus, en partie par flemme, et puis parce qu'il n'y a rien de bien compliqué à comprendre.

approche_asm_visu_hexeditor

Bon ça ressemble à un éditeur hexadécimal ... c'est rassurant. Si vous n'avez jamais vu d'éditeur hexadécimal, veuillez arrêter de lire tout de suite, ce document n'est pas fait pour vous 😛

Parmi les fonctions intéressantes, on peut à partir du menu File, charger une table (format .tbl), chercher des valeurs (Edit>Find), visualiser les trois mémoires (View), ...

A noter que lorsque l'on fait un clic droit, le menu que l'on aperçoit sur l'image ci-dessus apparaît. On peut :

  • Bloquer/débloquer la valeur d'un ou plusieurs octets de la mémoire (Freeze) ;
  • Placer directement des breakpoints (Pas besoin de préciser où c'est) ;
  • Ajouter/Enlever un repère (Add/Remove bookmark).

Voilà qui conclut cette présentation (bancale) de l'émulateur, nous allons donc maintenant pouvoir entrer dans le vif du sujet!

 

5) Une première technique assez simple

A mon avis, rien de plus simple pour apprendre que de prendre un exemple. Le jeu auquel nous allons nous intéresser est Gargoyle's Quest II (que je recommande à tout le monde, cela dit en passant).

Pour information, les images de GQ2 ci-dessous proviennent d'une traduction non officielle en français réalisée par Génération IX, le groupe dont je fais partie, et qui est le meilleur de la planète et de l'univers tout entier d'ailleurs (d'ailleurs, il est intéressant de noter que le ROMhackeur n'a pas manipulé d'ASM 😀 - « oh le mauvais »).

Bref débrouillez-vous pour récupérer la ROM du jeu, afin de pouvoir essayer en même temps.

Lancez le jeu, passez l'intro, le menu principal, et... on arrive sur une fenêtre avec du texte...

approche_asm_exemple_intro

Arg, regardez ces minuscules caractères en 8*8. Ça serait bien de passer ça en 8*16 pour par exemple ajouter des caractères accentués (ndlr : en fait, ce n'est pas si simple que ça, il y a d'autres facteurs dont il faut tenir compte, donc on pardonne au ROMhackeur du jeu :D), non?

Bon tout d'abord, il faut essayer de repérer à quel endroit dans le code le programme va afficher les caractères. Pour ce faire, ouvrez le Name table Viewer.

approche_asm_exemple_nametable

Maintenant positionnez le curseur de la souris sur le I de IL, et regardez le cadre Properties. Pour afficher le I, il faut donc qu'il y ait écriture de la valeur $09 à l'adresse $2287 de la PPU. Maintenant que l'on sait ça, il suffit de d'ajouter un breakpoint en écriture sur l'adresse $2287 de la mémoire de la PPU.

Faites-le (dis-je en utilisant la Force ... oui, je sais, je ne suis pas drôle :P), et ensuite relancez le jeu.

L'exécution va s'arrêter à plusieurs reprises, nous ne nous intéresserons qu'à l'écriture de la valeur $09 à l'adresse $2287 de la PPU. A chaque fois que le programme se bloque, cliquez sur Run pour continuer l'exécution. On s'arrête quand on voit ça.

approche_asm_exemple_debugger

Là, on essaye d'écrire $09 à $2287 (par l'intermédiaire du registre d'accès à la mémoire de la PPU : $2007). C'est peut-être bien ce qu'on cherche. On modifie la valeur du registre A, pour la passer à $0A par exemple.

Normalement si c'est bien la routine que l'on cherche, un J doit s'afficher au lieu d'un I.

Cliquez sur Run, et ô Miracle ! un J s'affiche! Bref maintenant que l'on sait que c'est ça, redémarrez, et revenez à la configuration précédente.

Bon maintenant, il n'y a plus trop de technique, on peut par exemple exécuter pas à pas (Step Into) afin de voir un peu ce qui se passe autour.

Dans notre exemple, on isole assez facilement (grâce au BNE $C1AB) l'intégralité de cette petite routine (voir un peu plus loin).

Bref, en regardant le code, on remarque que le programme charge les valeurs à écrire à partir de $0780 - $0783. Voyons voir ce qui se trouve à ces adresses grâce à l'éditeur de la mémoire de la console.

Et ô miracle, le retour :

000780 : 22 87 00 09 FF 00 00 00 00 00 00 00 00 00 00 00 $C1AB:BD 80 07 LDA $0780,X $C1AE:30 1B BMI $C1CB $C1B0:8D 06 20 STA $2006 $C1B3:BD 81 07 LDA $0781,X $C1B6:8D 06 20 STA $2006 $C1B9:BC 82 07 LDY $0782,X $C1BC:BD 83 07 LDA $0783,X $C1BF:8D 07 20 STA $2007 $C1C2:E8 INX $C1C3:88 DEY $C1C4:10 F6 BPL $C1BC $C1C6:E8 INX $C1C7:E8 INX $C1C8:E8 INX $C1C9:D0 E0 BNE $C1AB $C1CB:60 RTS

Avec un effort mental relativement important :P, on remarque qu'à l'adresse $0783 se trouve la valeur à écrire en mémoire de la PPU, et l'adresse où doit s'effectuer l'écriture se trouve en $0780/$0781.

Pour utiliser une police en 8*16, le principe est assez simple, il « suffit » de modifier cette routine pour qu'au lieu de faire une seule écriture en mémoire PPU par caractère, on en fasse 2.

Il faut tout d'abord modifier la font pour la stocker par exemple comme ci-dessous.

Bref deux tiles consécutifs pour un même caractère.

approche_asm_exemple_tile
C'est très moche, je sais 😀

A titre d'exemple, voici en gros ce qu'il faudrait faire (en bleu le nouveau code). Je précise que c'est le principe de la chose, je ne sais pas si ça marche bien dans ce cas 😀

$C1AB:BD 80 07 LDA $0780,X $C1AE:30 1B BMI $C1CB $C1B0:8D 06 20 STA $2006 // on écrit la partie haute de l'adresse en PPU $C1B3:BD 81 07 LDA $0781,X $C1B6:8D 06 20 STA $2006 // on écrit la partie basse de l'adresse en PPU $C1B9:BC 82 07 LDY $0782,X $C1BC:BD 83 07 LDA $0783,X $C1BF:8D 07 20 STA $2007 // on a écrit le tile du bas du caractères par exemple INC // on incrémente pour écrire le tile du haut après PHA // on met A de côté dans la pile LDA $0781,X // on met à jour l'adresse en PPU pour écrire le tile du haut SEC // à faire avant soustraction SBC #$20 // on veut écrire à la ligne au dessus STA $0781,X // on sauvegarde le résultat LDA $0780,X // SBC #$00 // en cas de retenue à la soustraction d'avant STA $0780,X // < pas forcément nécessaire STA $2006 // on écrit la partie haute de l'adresse en PPU LDA $0781,X STA $2006 // on écrit la partie basse de la même adresse PLA STA $2007 // on écrit le tile du haut du caractère là où il faut $C1C2:E8 INX $C1C3:88 DEY $C1C4:10 F6 BPL $C1BC $C1C6:E8 INX $C1C7:E8 INX $C1C8:E8 INX $C1C9:D0 E0 BNE $C1AB $C1CB:60 RTS

Bref, je ne compte pas aller plus loin, le but étant de faire une brêve présentation d'une technique qui marche dans pas mal de cas pour localiser assez vite les routines importantes pour l'affichage de texte. Une fois une telle routine repérée, il existe tout plein de façons pour remonter jusqu'à la routine de texte, comme par exemple chercher les routines qui mettent à jour la valeur à l'adresse mémoire $0783 (le caractère à afficher quoi).

Tiens ben essayons de faire ça en fait 😛
Hop, on met un breakpoint en écriture sur l'adresse $0783, afin de repèrer le moment où le programme y écrit la valeur $09. On peut par exemple définir un breakpoint conditionnel, il suffit d'ajouter « A == #9 » dans le champ condition lors de l'ajout du breakpoint.

On relance la ROM, et hop on tombe directement à la bonne adresse.
Bon cette fois-ci j'arrête ^^ Juste au passage, on pourrait continuer en recherchant par exemple dans le code de la ROM desassemblée tous les appels à cette routine (genre JSR $8144 ou JMP $8144 ou BXX $8144 ...).

Cette façon de procéder peut s'avérer utile lorsque par exemple on ne sait rien de la façon dont le texte est codé, ou si l'on s'intéresse plus au côté rendu du texte qu'au texte lui même (par exemple pour implémenter une 8*16).

$8143:60 RTS // fin d'une routine // ici commence donc une nouvelle routine $8144:8D 83 07 STA $0783 = #$09 // on écrit le caractère à afficher $8147:20 98 81 JSR $8198 // calcule sans doute l'adresse de la PPU où écrire la valeur du caractère $814A:A5 76 LDA $0076 = #$22 // On recopie cette adresse à $814C:8D 80 07 STA $0780 = #$23 // $0780 $0781 $814F:A5 77 LDA $0077 = #$87 // $8151:8D 81 07 STA $0781 = #$46 // $8154:A9 00 LDA #$00 $8156:8D 82 07 STA $0782 = #$13 $8159:A9 FF LDA #$FF $815B:8D 84 07 STA $0784 = #$00

 

6) Une autre approche

La technique précédente, bien que simple sur le principe, peut s'avérer assez fastidieuse pour localiser une simple routine de texte. D'où cette autre approche basée sur une connaissance préalable de certaines informations concernant la façon dont le jeu exploite son script.

Par exemple, savoir où se trouve les tables de pointeurs, dans quelle bank se trouve le script, comment est encodé le texte ...

Un bon point de départ est de se renseigner sur le type de mapper utilisé par le jeu étudié. Pour ce faire, il suffit d'aller dans le menu Help puis dans Message log. On voit alors quelque chose du genre.

PRG ROM: 16 x 16KiB CHR ROM: 0 x 8KiB ROM CRC32: 0x2511dd3a ROM MD5: 0x61183ff5ae5318059ae167e24c42d22f Mapper: 1 Mirroring: Vertical

On a alors directement le numéro du mapper. Après ça, il suffit d'aller faire un tour sur le wiki de nesdev pour avoir des infos précises sur ce mapper.

Dans le cas du mapper 1 (MMC1), on voit que les écritures dans les registres du mapper sont de la forme.

// Initialement la valeur à écrire est dans A STA $E000 LSR STA $E000 LSR STA $E000 LSR STA $E000 LSR STA $E000

Donc on peut supposer que quelque part se trouve dans la ROM une routine qui ressemble très fortement à ça. On est en tout cas sûr de trouver quelque part un STA $E000 (écriture d'un bit sur le registre du mapper).

Il est donc utile de rechercher la routine équivalente à celle-ci dans la ROM étudiée. D'autant plus que le jeu y fera par exemple appel pour charger la bank dans laquelle le texte se trouve.

On peut déjà imaginer que si tout le texte du jeu se trouve dans une même bank, que l'on connait sa position dans la ROM, la taille des banks utilisées (paramètre dépendant du mapper), on peut donc calculer le numéro de la bank correspondate pour le mapper (position_dans_la_rom / taille_bank), et donc rechercher tous les appels à la routine décrite ci-dessus pour lesquels on aurait
au préalable chargé ce numéro de bank dans A.

Cette technique marche pour Bionic Commando. La routine ci-dessus provient d'ailleurs de ce jeu. Elle se trouve à l'adresse $DC0C. Le texte se trouve dans la 11ème bank du jeu ($0B). On trouve en plein milieu de la routine de texte.

07/C46F: LDA #$0B // charge le numéro de la bank07/C471: JSR $D692 // Appel à $D692 (soit comme on le voit, un appel à $DC0C, routine d'écriture dans le 07/D692: JMP $DC0C // registre de chargement de bank du MMC1

Par ailleurs, on peut aussi procéder d'une façon plus ou moins analogue si l'on connait l'adresse d'une table de pointeur. En effet, souvent les routines de texte fonctionnent sur le schéma suivant.

Admettons que l'on veuille charger la k-ième chaîne à partir d'une table de pointeurs, que l'adresse de la table de pointeur est adr_tab_ptr (adresse 16 bits)

// on suppose que dans Y se trouve la valeur k LDA adr_tab_ptr,Y // On récupère le byte inférieur du pointeur de la k-ième chaîne, et STA $7A // on le sauvegarde en page zéro LDA (adr_tab_ptr + 1) ,Y // de même pour le byte supérieur STA $7B // // le pointeur de la chaîne est donc chargé à $7A $7B // pour récupérer le Y-ième caractère il suffit de faire LDA ($7A),Y // charger toute la chaîne en mémoire est trivial, il suffit de boucler sur // quelque chose (attente de marqueur de fin, taille de la chaîne, ...)

Bref, si l'adresse de la table de pointeurs dans la ROM est A BC DE, on peut en déduire que l'adresse de cette table, lorsqu'elle sera utilisée depuis la mémoire de la console sera quelque chose comme XC DE (X car on ne sait pas comment sera chargée la bank dans laquelle se trouve la table).

Donc une autre méthode, est par exemple de rechercher dans le code de la ROM desassemblée, tous les « LDA .C DE,Y » ou « LDA .C DE,X » ou « LDX .C DE,Y » ou « LDY .C DE,X ».
' . ' étant le ' . ' des expressions régulières (bref le caractère inconnu).

Voilà, voilà, une fois la routine de texte localisée, il reste à l'analyser, et éventuellement la modifier. Il faut cependant bien garder à l'esprit que chaque jeu dispose de sa propre façon de faire, et que ces « techniques » ne sont en aucun cas applicables pour tous les jeux 😛

 

7) Conclusion

Je suis très mauvais pour les conclusions, donc ne m'en voulez pas trop de faire court ^^

Les méthodes que j'ai évoquées au cours de ce document ne sont en aucuns cas les seules existantes, et à mon avis, leur principale utilité est d'illustrer le genre de raisonnement qu'il faut mettre en place pour « hacker » un jeu.

Bref, de toute façon tout ça ne s'apprend à mon avis qu'en essayant, et en aucun cas dans un document aussi mal écrit (malgré la merveilleuse relecture du grand Ti Dragon).

Pour conclure, je vais dire un grand merci à tous ceux qui le méritent.

Commençons par toute l'équipe de Génération IX, le groupe de traduction dont je fais partie (oui, je l'ai déjà dit, je radote, je sais :P), groupe où on ne se prend pas la tête et où l'ambiance est très bonne.

Voilà, ça c'est dit. Je remercie tout particulièrement Ti Dragon pour son soutien, d'une part pour sa relecture, mais aussi pour son travail sur la TRAF.

Un grand merci aussi à tous les gens qui gardent Nesdev en vie, ce merveilleux site plein de bonnes choses.

Et tous les autres que j'ai oubliés mais auxquels je pense quand même (comment ça, ce n'est pas crédible?).

Si jamais, par miracle, vous vouliez me contacter, le plus simple est encore de le faire par l'intermédiare du forum utilisé par la quasi-intégralité des groupes de traduction.

Article au format PDF

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Adviennes que pourra