Historique de remplacement sur un octet
Cartoon Cartoon Summer Resort
C'était l'été 2000. J'ai eu six ans, je viens de terminer la première année et les vacances ont commencé. Cela signifiait que je pouvais jouer longtemps dans la rue, regarder des dessins animés et allumer l'ordinateur de mon père avec Windows 98 pour rechercher des jeux dans un tout nouveau pays inexploré appelé Internet. L'un de mes favoris était le site Web de Cartoon Network. J'y ai trouvé de nombreux jeux flash fascinants basés sur des dessins animés télévisés. Cet été-là, ils ont sorti une série de jeux intitulée Cartoon Cartoon Summer Resort.
Gameplay du premier épisode de Cartoon Cartoon Summer ResortCe jeu était un RPG / aventure en deux dimensions avec une vue de dessus de côté, composé de quatre épisodes. Le joueur contrôlait un personnage de dessin animé en vacances au complexe avec d'autres personnages de dessin animé. Dans chaque épisode, un problème est apparu dans la station qui devait être résolu. Le joueur devait le résoudre en interagissant avec les personnages et en trouvant des objets ou en les échangeant.
Remontant à 18 ans
Lors d'une des récentes attaques de nostalgie, je me suis souvenu de ce jeu et j'ai réalisé que je le rejouerais. Elle avait presque deux décennies, il était donc difficile de trouver un lien de travail.
De plus, aucun navigateur moderne ne lancerait l'ancien et vulnérable lecteur Shockwave ... à l'exception d'Internet Explorer. J'ai probablement été la première personne à trouver une raison légitime d'utiliser Internet Explorer en 2018.
Après avoir joué un peu, j'ai remarqué des moments qui ne pouvaient pas être ignorés. Par exemple, une musique de fond monotone jouant dans une boucle sans fin et une mauvaise reconnaissance des collisions.
Le même bug
Après un certain temps, j'ai trouvé un bug dans le jeu:
Lorsque vous vous déplacez dans des zones où rien ne doit se produire, une boîte de dialogue apparaît parfois.Comme le montre l'animation, dans le jeu, vous pouvez louer un bateau pour vous déplacer sur l'eau. Lorsque vous essayez de louer un autre bateau, le message «Aujourd'hui, il n'y a plus de bateaux loués!» Apparaît. Si vous naviguez vers le nord et marchez le long du bord droit de l'île, mais le même texte s'ouvre qui devrait apparaître à l'embarcadère.
À ce stade, toute personne sensée qui respecte son temps et son énergie considérerait le bug comme une nuisance mineure, se rappelant qu'il s'agissait d'un jeu Web médiocre pour les enfants, créé il y a deux décennies, et continuerait à jouer. Mais pas moi.
Possédant déjà toutes mes connaissances en programmation et regardant le jeu, j'ai perçu ce bug comme étrangement attrayant. Il m'a semblé que j'avais déniché une tombe ancienne et y ai trouvé un puzzle intact qui aurait pu disparaître, qui n'a jamais été résolu par personne. Pour moi, ce bug a été l'occasion d'apprendre et de découvrir quelque chose de nouveau. Fait intéressant, ce sont précisément ces opportunités que le
processus du jeu lui-même m'a donné dans l'enfance. Il y a quelque chose de presque poétique dans la façon dont quelque chose peut, par inadvertance, poser de nouveaux défis si vous le regardez sous un angle différent.
Jeu de déconstruction
Pour corriger le bug, j'avais besoin de comprendre le fonctionnement interne du jeu. Après avoir examiné le problème, j'ai découvert que le jeu avait été créé sur Shockwave dans l'application
Director . Lorsque vous travaillez avec Director, les projets sont enregistrés dans un
.dir
(Director). Ce fichier est similaire au fichier PSD pour Photoshop. Tout comme un fichier PSD contient des informations non destructives sur les calques et le texte, un projet
.dir
enregistre toutes les ressources, le code source brut et d'autres informations utiles au processus de développement. Director a utilisé le langage de script propriétaire
Lingo pour animer des scènes.
Si le jeu était enregistré dans un fichier
.dir
, je pourrais simplement l'ouvrir dans Director et apprendre facilement comment le jeu fonctionne. Cependant, le jeu est publié sous
.dcr
fichier
.dcr
. Le fichier
.dcr
est une version compilée du projet Director. Autrement dit, tout le code source est compilé en bytecode exécuté sur la plate-forme Shockwave. Ce processus est similaire à la façon dont un fichier PSD est simplifié et devient une image PNG. L'image PNG (dans notre cas, le fichier DCR) est de plus petite taille, mais ne contient pas d'informations sur les calques et les modifications, et est uniquement destinée à la distribution.
Cela signifiait que je tenais un objet binaire de 500 Ko sans documentation de sa structure. Même si j'ai compris comment trouver le bytecode de bas niveau, il semble que personne n'ait effectué de reverse engineering du bytecode Lingo et documenté le principe de la plateforme Shockwave. Toutes ces informations sont propriétaires, elles appartiennent à Adobe, qui n'a aucune raison de les publier. Les chances de comprendre le jeu semblaient plutôt sombres.
Décompression
Me sentant vaincu parce que je ne pouvais probablement pas éliminer ce bug, j'ai décidé de savoir si les ressources pouvaient être extraites du jeu. J'ai pensé qu'il était susceptible de trouver une section de données compressées ou quelque chose de similaire. Après avoir cherché, j'ai trouvé quelques programmes appelés
offzip et packzip . Ces outils peuvent rechercher des données zlib dans des fichiers binaires arbitraires, afficher les décalages et les extraire dans des fichiers séparés.
J'ai exécuté offzip avec un fichier DCR et à ma grande surprise, il a vraiment trouvé les archives! 249 pièces, pour être plus précis.
$ ./offzip.exe -a 1.dcr
- open input file: 1.dcr
- zip data to check: 32 bytes
- zip windowBits: 15
- seek offset: 0x00000000 (0)
+------------+-----+----------------------------+----------------------+
| hex_offset | ... | zip -> unzip size / offset | spaces before | info |
+------------+-----+----------------------------+----------------------+
0x00000026 . 164 -> 214 / 0x000000ca _ 38 8:7:26:0:1:7b6349f6
0x000000d3 .. 3932 -> 9169 / 0x0000102f _ 9 8:7:26:0:1:c1079d84
...
0x00080490 . 265 -> 472 / 0x00080599 _ 0 8:7:26:0:1:04d6b43f
0x00080599 . 209 -> 366 / 0x0008066a _ 0 8:7:26:0:1:7da3ba08
- 249 valid compressed streams found
- 0x0004040d -> 0x001565c8 bytes covering the 50% of the file
J'ai extrait tous ces fichiers dans un dossier et j'ai commencé à étudier les résultats. Il y avait 206 fichiers
.dat
, 38 fichiers
.fff
, 4
.atn
et un seul fichier
.ini
.
Découvertes
J'ai commencé avec le fichier INI, mais ça ne servait à rien. C'était une simple table de conversion de polices de Directory 7.0 entre Windows et Mac. Ensuite, je suis passé aux fichiers DAT. La plupart d'entre eux faisaient 1 Ko, alors j'ai commencé avec un énorme 144 Ko. Je l'ai ouvert dans un éditeur hexadécimal et j'ai étudié. Il s'agissait principalement de données illisibles. Cependant, au fil du temps, j'ai trouvé quelques mots qui semblaient être des identificateurs Lingo.
L'analyse des gros fichiers DAT m'a donné quelques indices, ils ont gardé des messages intéressants. J'ai trouvé que Photoshop 3.0 était très probablement utilisé pour les graphiques. J'ai également appris que le jeu avait un outil d'édition de carte interne appelé
Map-O-Matic v1
. Je voudrais voir à quoi il ressemblait et a été créé.
J'ai également trouvé le nom de la société qui développe le jeu:
Funny Garbage . Le nom du développeur principal figurait également dans le fichier, mais je ne le nommerai pas. C'était génial de découvrir l'auteur du jeu, que j'ai obstinément essayé de réparer après près de 20 ans, et enfin de voir le visage de la personne qui est devenue la cause probable de cette agonie. Toutes ces miettes d'informations étaient bien sûr intéressantes, mais elles n'ont pas beaucoup aidé.
Percée
Puis j'ai commencé à étudier les fichiers
.fff
dans un éditeur hexadécimal. À ma grande surprise, toutes les données de ces fichiers étaient lisibles et ressemblaient à des données cartographiques:
J'ai extrait manuellement certaines de ces données et les ai nettoyées dans un éditeur de texte. Ce que j'ai fait ressemblait beaucoup à un tableau JSON:
[
#member: "block.104",
#type: #FLOR,
#location: [16, 9],
#width: 64,
#WSHIFT: 0,
#height: 32,
#HSHIFT: 0,
#data: [
#item: [
#name: "",
#type: #WALL,
#visi: [
#visiObj: "",
#visiAct: "",
#inviObj: "",
#inviAct: ""
],
#COND: [[#hasObj: "", #hasAct: "", #giveObj: "sunscreen", #giveAct: "gotscreen"], #none, #none, #none]
],
#move: [#U: 0, #d: 0, #L: 0, #R: 0, #COND: 1, #TIMEA: 0, #TIMEB: 0],
#message: [
[#text: "You bought the sun screen.", #plrObj: "", #plrAct: ""],
[#text: "No more sunscreen today!", #plrObj: "", #plrAct: "gotscreen"]
]
]
]
C'était très important, car j'ai réussi à en apprendre beaucoup sur le fonctionnement du jeu.
- Le jeu s'attend à ce que les données de carte, de texte et d'événement soient dans des objets Lingo de type JSON
- Chaque entrée
#member
est une tuile, un bloc ou un caractère #member
. - Les coordonnées et les
#member
tailles #member
peuvent être modifiés.
Sachant que les boîtes de dialogue du jeu ont été enregistrées dans ces fichiers, j'ai écrit une courte ligne pour exporter une seule boîte de dialogue vers un fichier:
grep -a -o '#text: "[^"]*' Uncompressed/*.fff | awk '{print $0,"\r"}' > Dialogue.txt
En utilisant ce fichier, je peux rapidement trouver le texte erroné et voir dans quel fichier il se trouvait:
Le texte erroné est soit dans
0004eda0.fff
, soit dans
0004f396.fff
. Dans notre cas, le texte du bug est apparu dans le premier fichier. Nous le savons car juste après c'est un message que nous recevons lorsque nous interagissons avec Og, qui est un personnage sur la même carte que la tuile avec le bug.
Correction d'un bug
Maintenant, je pouvais ouvrir
0004eda0.fff
et trouver la ligne concernant le bateau dans l'éditeur hexadécimal. L'ayant trouvé, j'ai pu trouver l'objet
#member
associé. Modifiez ensuite ses propriétés et enregistrez le fichier. Ensuite, je l'ai à nouveau compressé et corrigé dans le fichier source du jeu DCR à l'aide de
packzip
.
$ ./packzip -o 0x0004EDA0 Uncompressed/0004eda0.fff test.dcr
Lorsque je change le type de bloc de
block.11
en
block.13
et
block.13
le jeu, je peux clairement voir le contour de la
block.11
d'erreur:
En changeant l'ID de tuile, vous pouvez voir les limites de la zone à problèmeLe correctif de bogue lui-même est ridiculement simple. Tout ce que j'avais à faire était de changer l'identifiant
#message
pour cette
#message
erreur en
#fessage
:
Maintenant, si nous corrigeons les modifications et revenons à cette zone, les messages n'apparaîtront plus!
Correction d'un bug dans le jeu, changeant littéralement 1 octetPourquoi est-il possible de corriger l'erreur?
Je peux seulement supposer que le moteur de jeu est susceptible de vérifier la tuile sur laquelle il se trouve lorsque le joueur se déplace. Si une condition est remplie, il affiche le message correspondant à cette tuile du tableau
#message
. Après avoir changé
#message
en
#fessage
lien vers le tableau
#message
que le code recherche n'est plus trouvé. Il considère qu'il s'agit d'un objet vide (ou non défini?) Et n'affiche rien.
Prenons un exemple sur JS:
function foo(bar) { if (bar["message"] !== undefined) {
Supposons que nous ne pouvons pas changer la fonction
foo()
, mais nous devons changer le résultat. Nous avons accès aux données qui lui sont transmises. Vous pouvez renommer la propriété
message
de l'objet passé et la fonction pensera qu'elle n'était pas là.
Comment ce bug est-il apparu?
Je suppose à cause de la paresse. Les développeurs ont utilisé un éditeur de carte pour créer cette zone. Très probablement, ils ont copié des cartes anciennes dans de nouvelles zones, puis les ont modifiées. C'est plus facile que de tout créer à partir de zéro. Mais comme les données d'événement et de texte sont mélangées, elles ont probablement été ignorées à certains endroits et ont oublié de les supprimer ou de les remplacer. Cela semble le plus logique, car le dialogue erroné a souvent été pris sur une carte voisine, où il a été utilisé correctement.
Pourquoi consacrer autant de travail à quelque chose d'aussi insignifiant?
Je ne sais pas. Peut-être à cause de la nostalgie?