; Desassemblage loader cassette FIREBIRD
; T&J du GPA (c) Mars 2003, maj le 12/03/2005
J'ai fait ce petit article pour me rappeler les techniques a employer pour
transferer facilement les jeux Firebird. A la fin de l'article, il y a deux
desassemblages, que je vous conseille d'imprimer (comme le reste du texte
d'ailleurs !) pour mieux comprendre.
J'espere que ces explications ne sont pas trop confuses.
Afin de pouvoir rajouter des commentaires dans cette notice, j'ai dissocie
cette dernier du source du loader Firebird. Vous le trouverez dorenavant sous
le nom FIREBIRD.ASM.
Nouveautes du 12/03/05
----------------------
* Modification de la routine FIRE128P.ASM. Maintenant, la mathode numero 2 sauve
un fichier S.BIN de 7ko (zone &A600 a &BFFF), afin d'etre le plus compatible
possible avec des logiciels utilisant des zones de ram elevees pour se
decoder (Chimera utilise la plage &AB00-&ABFF par exemple).
* Rajout dans la liste des transferts de Chimera.
Qu'est ce que le loader Firebird ?
----------------------------------
C'est un chargeur binaire, utilise pour les jeux au format cassette
de l'editeur Firebird. A ma connaissance, tous les jeux de cet editeur
beneficient de ce qui s'avere etre une protection (les donnees chargees
sont codees) assez originale.
Elle ne resiste pas a un Hacker, mais il peut s'averer interessant de
pouvoir la detourner, ne serait-ce que pour savoir comment elle
fonctionne et faire des versions propres de ses jeux (le Hacker parfois
corrompt les donnees lors d'un reset).
Cela vous servira aussi si vous n'avez pas de Hacker et que vous voulez
'passer' sur disquette vos jeux originaux.
Cette routine n'a rien a voir avec le loader musical de Melvyn Wright
mais elle est utilisee soit pour charger la page ecran et le loader final
d'un jeu (Spiky Harold, Thrust), soit pour charger le programme principal
(Cylu).
Sur un jeu (Cylu), elle est utilise avec une autre routine, qui la charge.
La presence de cette deuxieme routine se remarque en listant le programme
Basic de depart. Si vous avez des lignes du style CALL &2200,3,8,15, ce
chargeur est utilise. Pour le detourner, il suffit de rechercher la sequence
de code suivante :
LD HL,(&xxxx)
LD A,H
OR L
RET Z
Vous pointez sur une routine de sauvegarde de la memoire, et le tour est joue.
Le desassemblage ci-dessous a ete fait sur le loader du jeu
'Stars Firebird'. Sur les autres jeux, il peut etre implante ailleurs
(en &9900 pour Cylu, par exemple). Meme remarque pour le buffer de &100
octets (en &3132 pour Star Firebird, &9C32 pour Cylu, &A132 pour
Skateboard Joust).
Principe de fonctionnement de la routine
----------------------------------------
Le loader Firebird charge des blocs contenant &100 octets de datas
suivis d'une serie de valeurs utilisees par le chargeur. On y trouve
pele-mele le numero de bloc charge, l'adresse de recopie des &100
octets precedents, une adresse codee d'execution.
Apres le chargement d'un bloc, le programme fait systematiquement les
actions suivantes :
* Verification de l'integrite du bloc charge (en &3B15).
* recopie en memoire a leur emplacement definitif des &100 octets lus
depuis la cassette (en &3A6D).
* saut a une adresse d'execution apres son calcul a partir des
octets lus apres les &100 octets (en &3A55).
Tant qu'il a des blocs a charger, cette adresse est :
Le chargement du premier bloc est une exception. Il est recopie en
&AC00 et contient des donnees qui serviront au decodage du programme
une fois ce dernier charge completement.
Particularite interessante, il n'y a aucune condition d'arret au chargement
dans le loader. C'est le code contenu a l'adresse d'execution calculee apres
le chargement de chaque bloc qui determine si le chargement est fini ou pas.
L'adresse d'execution du dernier bloc pointe en general sur &100, mais pas
toujours ! A cet endroit,il y a une routine, partiellement codee elle aussi,
qui effectue le decodage du programme principal charge (en general, la page
ecran, situee en &4000) et du loader principal du jeu, s'il y en a un.
Comment detourner la routine
----------------------------
Apres de multiples essais, il s'avere que la methode la plus simple
pour passer cette protection consiste a patcher un appel systeme
utilise par la routine de decodage des donnees chargees. Le programmeur
a juge utile de faire un CALL &BD37 (initialisation des vecteurs) dans
la routine de decodage. Les adresses &BD37 et &BD39 sont verifiees par
le programme, mais pas &BD38 (voir le source plus loin).
Il est donc possible de desactiver cette reinitialisation en faisant
pointer ce vecteur sur un RET dans la ROM basse (zone &800-&8FF) du CPC.
Ensuite, il suffit de trouver un autre vecteur utilise par le programme
que l'on pourra detourner vers une routine de sauvegarde de la memoire et
le tour est joue. Bonheur du jour, la routine d'affichage d'une page
ecran 'en escalier', utilisee souvent dans les jeux Firebird, contient un
appel au vecteur &BD19.
Cette technique simple de detournement ne fonctionne pas lorsque le jeu n'a
pas ce type de page ecran (on ne sait alors pas si le programme fait appel a
un vecteur systeme apres son chargement).
Il faut alors utiliser les methodes numero 2 voire 3, cette derniere etant
plus complexe.
Methode numero 1
----------------
Teste sur : Willy Wino's Stag night, Stars firebird, Pogostick olympics.
* Si le loader Firebird charge une page ecran qui s'affiche avec un
effet d'escalier, cette technique est utilisable.
Il suffit alors de detourner le vecteur &BD19, systematiquement
utilise par le programme affichant la page ecran.
On retrouve dans la zone de memoire sauvee le programme affichant
la page ecran (en &4000) et un loader pour le programme principal,
en principe non code.
En pratique, il faut transferer sur disquette le premier fichier du
jeu (le chargeur Basic).
Une fois le programme transfere, il faut le modifier un peu en rajoutant
les lignes suivantes avant l'appel du chargeur Binaire :
LOAD "FIRESCR.BIN",&BE80
POKE &BD19,&C3:POKE &BD1A,&80:POKE &BD1B,&BE
POKE &BD38,&06 ' Pour un CPC 464
POKE &BD38,&1A ' Pour un CPC 6128
Desole, pas de valeur pour un CPC 664 (je n'en ai pas !).
Si vous n'etes pas sur de vous, editez le fichier exemple -STAR1.BAS.
Une fois les modifications effectuees, lancez le programme et attendez.
Si tout s'est bien passe, a la fin du chargement, au lieu de voir la page
de presentation du jeu, votre lecteur de disquette doit s'activer. Il
sauvegarde un fichier de 42ko toujours appele MAIN.BIN. Ensuite, le CPC
fait un reset.
Methode numero 2 (CPC 6128 seulement !)
---------------------------------------
Testee sur : Hybrid, I Ball 2, Skateboard joust, Thrust II
Si le loader Firebird charge un programme. La, il n'est pas possible
directement de savoir comment detourner la routine de decodage.
L'idee est alors de faire une sauvegarde de la memoire juste apres
le chargement du jeu, avant qu'il ne soit totalement decode et de faire le
decodage en utilisant une routine qui "rend la main" apres qu'elle ait
decode le jeu.
Le 6128 vient a notre rescousse car on peut encore utiliser la technique
de modification du vecteur &BD37 (comme la precedente methode).
L'idee est de se dire qu'avec un peu de chance, il y a dans la ROM basse
dans la plage memoire appelee par le vecteur &BD37 un appel a un autre
vecteur. Et c'est le cas sur 6128 ! (&BDF1).
Possesseurs de CPC 464, prenez vos mouchoirs, la methode 2 ne peut pas etre
utilisee, car, si vous desassemblez la zone memoire &800-&8FF de la ROM
basse (CALL &B906 pour voir son contenu avec Le Hacker), on ne trouve aucun
appel a un vecteur systeme...
Par rapport a la methode un, il y a un inconvenient. Lors du detournement,
le programme en memoire n'est pas totalement decode (regardez le source de
la routine en &0100). Il faut donc utiliser un deuxieme programme qui se
chargera de ce travail. C'est la raison d'etre de DECODE.BAS.
En pratique, il faut transferer sur disquette le premier fichier du
jeu (le chargeur Basic).
Une fois le programme sur disquette, il faut le modifier un peu en
rajoutant les lignes suivantes avant l'appel du chargeur Binaire :
LOAD "FIREP128.BIN",&BE80
POKE &BDF1,&C3:POKE &BDF2,&80:POKE &BDF3,&BE
POKE &BD38,&2F ' Pour un CPC 6128
Si vous n'etes pas sur de vous, editez le fichier exemple -JOUST2.BAS.
Une fois les modifications effectuees, lancez le programme et attendez.
Si tout s'est bien passe, a la fin du chargement, au lieu de voir la page
de presentation du jeu, votre lecteur de disquette doit s'activer. Il
sauvegarde deux fichiers, un de 42ko (M.BIN) et un fichier de 7ko (S.BIN).
Il faut ensuite lancer le programme DECODE.BAS. Il charger les deux
fichiers precedemment obtenus, et sauvegarde un fichier unique, MAIN.BIN.
Attention, si la routine de decodage n'est pas implantee en &0100, le
programme DECODE.BIN ne fonctionnera pas. En pratique, il vous faudra
adapter le source assembleur DECODE.ASM afin que le decodage se fasse
correctement. Ne tremblez pas, a ce jour, j'ai toujours vu cette routine
au bon endroit sauf sur Willy Wino's Stag Night (mais lui avait un bel
ecran en escalier !)
Note pour Chimera : le transfert de ce programme necessite la modification
et la recompilation du source FIRE128P.ASM. La routine de decodage finale
est en effet implantee non pas en &14B comme tous les logiciels rencontres
a ce jour, mais en &153.
Note pour I ball 2 : ce logiciel utilise rien moins que trois routines
differentes pour son chargement et empiete un poil sur la ram disque.
Pour le sauvegarder, il faudra adapter la routine DECODE.BIN pour que la
zone au dessus de &a67B soit sauvegardee.
A vos assembleurs...
Note pour Thrust II : bien que le transfert soit correct, si vous lancez
directement le programme genere sans passer par le loader Basic original
du jeu, le logo Thrust II sera endommage. Il faut soit garder le loader,
soit initialiser la table des caracteres redefinis par le programme avec
un CALL &BBAB (HL=&9FFC et DE=&0020) avant d'executer le jeu.
Methode numero 3 (preparez l'aspirine !) pour CPC 464
-----------------------------------------------------
Meme problematique que pour la methode numero 2, le jeu n'a pas de page
ecran ou n'utilise pas l'affichage par escalier, donc, pas possible a priori
de detourner le vecteur &BD19.
Bref, la, cela se complique. Notre routine va devoir compter les blocs que
charge le loader, et detourner au bon moment la routine de decodage (celle
normalement implantee en &0100). Si cette routine est stockee ailleurs,
cela plantera ! Il faudra alors trouver l'endroit ou elle se trouve en
modifiant la routine FIREPROG.ASM pour qu'elle effectue une sauvegarde
de la memoire juste apres le chargement du dernier bloc, et avant l'appel
a la routine de decodage.
Cette methode suppose que l'on connaisse les parametres suivants :
* Nombre de blocs lu.
Pas dur, il suffit de laisser le jeu se charger normalement une
fois et noter la derniere valeur affichee a l'ecran
(en hexadecimal, n'est ce pas !) avant que le jeu ne demarre.
* Adresse de detournement du loader du jeu.
Malheureusement, il va falloir jouer du dessassembleur pour
trouver l'adresse exacte, car elle varie en fonction des jeux.
Par contre, la sequence est toujours presente. Comparez avec le
source a la fin de ce texte (en &3A68)
DEC HL
AND &07
INC A
LD (&3246),A ; adresse de detournement
INC D
JP (HL)
* Adresse ou est stockee le checksum.
Cela tombe bien, sa valeur se trouve a l'endroit ou vous avez
trouve l'adresse de detournement ! Dans notre exemple, c'est la
valeur &3246.
Munis de ces precieux elements, chargez avec Maxam le programme source
FIREPROG.ASM. Modifiez les parametres indiques ci-dessus pour personnaliser
la routine au programme que vous avez deplomber, puis assemblez le.
Ensuite, il faut transferer le programme Basic et le loader binaire de la
cassette sur disquette.
Il sera necessaire de rajouter les commandes suivantes juste avant l'appel
du loader binaire.
LOAD "FIREPROG.BIN",&BE80
POKE detourne,&C3;poke detourne+1,&80:poke detourne+2,&BE
ou 'detourne' correspond a l'adresse de detournement trouvee plus
haut (on suit toujours ?).
Si vous n'etes pas sur de vous, editez le fichier exemple -JOUST3.BAS.
Si vous avez tout fait comme il faut, le loader doit charger le programme
normalement, puis sauvegarder deux fichiers, M et S (comme la methode 2).
A partir de la, on utilise le meme programme DECODE.BAS pour generer le
fichier MAIN.BIN. L'avertissement concernant ce programme indique en
methode 2 est aussi valable ici...
Que faire une fois que l'on a le fichier de 42ko decode ?
---------------------------------------------------------
Hacker ou moniteur quelconque chaudement recommande...
Il y a evidemment encore du boulot a faire ! Il faut dans un premier temps
retrouver le programme de decodage appele a la fin du chargement des donnees
que vous avez sauvees. En general, elle se situe en &0100, mais pas
toujours (cas de Willy Wino's stag Night, en &8600 !). Pour la retrouver,
rechercher un CALL &BD37 (ca ne vous rappelle rien ?). Si vous avez utilise
la methode numero 3 et que vous en etes a ce point, vous savez forcement ou
elle se trouve.
Etudiez ensuite ce bout de code. Apres la derniere boucle de decodage, le
code du jeu commence, ou bien on a un appel a la page ecran du jeu (en
&4000), un LDIR de &200 octets, puis un appel au bout de code deplace.
C'est le chargeur principal du jeu ! Il suffit de l'executer puis ensuite de
sauvegarder la memoire afin de recuperer le jeu. Vous pouvez eventuellement
utiliser la routine FIRESCR.BIN pour faire cette sauvegarde.
Si le jeu a un loader musical, la routine sera differente, mais ce n'est pas
l'objet de cette notice. Une etude de ce type de chargeur verra le jour...
un jour !
Une fois que vous connaissez les adresses d'implantation, de longueur et
d'execution du programme, vous pouvez utiliser le programme SAVER.BAS. Il
charge en memoire le fichier MAIN.BIN et en extrait un fichier FINAL.BIN, le
programme executable "nettoye".
Si vous n'arrivez pas a trouver ces adresses, consultez le tableau ci-dessous,
il y aura peut-etre le titre que vous convoitez...
Logiciel Implantation Longueur Execution Methode
-----------------------------------------------------------------------------
Chimera &2200 &8000 &7200 2
Hybrid &1964 &861C &1F25 2
I ball 2 &0500 &A260 &1518 2
NOTICE TEXTE n° 2 (1.78 Ko)
; Firebird loader toolkit (c) T&J/GPA 2003
; Maj du 10/03/2005
; Sauvegarde les zones ram &0040-&A67B et &AC00-&ACFF une fois tous les blocks
; charges par le loader d'un jeu Firebird
; Version CPC 6128 (pas utilisable avec un CPC 464, j'ai pas de 664 pour
; tester)
ORG &BE80
NOLIST
WRITE "FIREP128.BIN"
main2 JR saver
filesave db "M"
filesave2 db "S"
saver LD HL,&A600 ; recopie en memoire video zone de &100 octets en &AC00
LD DE,&C000 ; utile pour le decodage
LD BC,&1A00
LDIR
LD HL,&ABFF
LD DE,&40
LD C,&7
CALL &BCCE
LD HL,filesave
CALL openfil
LD HL,&0040
LD DE,&A63B
CALL todisk
LD HL,filesave2
CALL openfil
LD HL,&C000
LD DE,&1A00
CALL todisk
RST &0
openfil LD DE,&C000
LD B,&1
JP &BC8C
todisk LD A,&2
LD BC,&0000
CALL &BC98
JP &BC8F
; Routine de sauvegarde d'un fichier binaire
; Firebird's hacking tools * (c) T&J/GPA 01/2005
ORG &BE80
NOLIST
WRITE "SAVER.BIN"
main JR saver
start defw &0
length defw &0
exec defw &0
savename db "FINAL.BIN"
loadname db "MAIN.BIN"
saver LD HL,&B0FF
LD DE,&40
LD C,&7
CALL &BCCE
LD HL,loadname
LD DE,&C000
LD B,&8
CALL &BC77
EX DE,HL
CALL &BC83
CALL &BC7A
LD BC,&1A1A
CALL &BC38
CALL &BB18
LD HL,savename
LD B,&9
LD DE,&C000
CALL &BC8C
LD HL,(start)
LD DE,(length)
LD BC,(exec)
LD A,&2 ; fichier type binaire
CALL &BC98
CALL &BC8E
RST &0
NOTICE TEXTE n° 3 (2.77 Ko)
; Firebird loader Toolkit * (c) T&J GPA 2003
; Maj du 12/05/2003
; Routine de sauvegarde de la memoire &0040-&A67A
; A utiliser en completement de la technique de
; detournement du vecteur &BD19 s'il y a une page
; ecran en escalier dans le jeu.
ORG &BE80
NOLIST
WRITE "FIRESCR.BIN"
main JR saver
filesave db "MAIN"
saver LD HL,&ABFF
LD DE,&40
LD C,&7
CALL &BCCE
LD HL,filesave
LD DE,&c000
LD B,&4
CALL &BC8C
LD HL,&0040
LD DE,&A63B
LD BC,&0000
LD A,&2
CALL &BC98
CALL &BC8F
RST &00
; Firebird Hacker toolkit (c) T&J du GPA 2003
; Maj du 10/03/2005
; Routine de decodage des fichiers M et S (a lancer a la suite de la sauvegarde
; de ces fichiers si vous utilisez la methode 2).
; Attention, la routine part du principe que la routine de decodage finale est
; implantee en &0100 (comme tous les jeux ayant cette protection que j'ai vus).
; Si tel n'est pas le cas, il va falloir bricoler le source, ce qui vous
; l'avouerez, n'est pas si complique que cela !
ORG &C000
NOLIST
WRITE "DECODE.BIN"
boot JR main
file1 db "M"
file2 db "S"
file3 db "MAIN"
restoremain db &3A,&37,&BD
main LD HL,file1 ; chargement des fichiers M et S
LD DE,&E000
LD B,&1
CALL &BC77
LD HL,&40
CALL &BC83
CALL &BC7A
LD HL,file2
LD DE,&E000
LD B,&1
CALL &BC77
LD HL,&D000
CALL &BC83
CALL &BC7A
DI ; on remet a sa place d'origine les 256 octets
LD HL,&D000 ; necessaires au decodage.
LD DE,&A600 ; update, on recopie une zone de &1800 maintenant !
LD BC,&1800 ; En partie pour Chimera, qui utilise la ram en &AB00
LDIR
LD HL,&14B ; on recupere la routine de decodage
; LD HL,&153 ; Pour Chimera, la routine est implantee plus haut
LD DE,&BE80 ; dans le corps du programme principal
LD BC,&14 ; Elle doit etre implantee en &100 dans ce cas.
LDIR
LD HL,restoremain ; uniquement pour methode 3, on remet les valeurs
LD DE,&13A ; d'origine en memoire (alteree par routine
LD BC,&3 ; FIREPROG.BIN).
LDIR
LD A,&C9 ; appel de la routine de decodage
LD (&BE94),A
CALL &BE80
EI ; init systeme disque et sauvegarde
LD HL,&ABFF
LD DE,&40
LD C,&7
CALL &BCCE
LD HL,file3
LD DE,&E000
LD B,4
CALL &BC8C
LD HL,&40
LD DE,&A63B
LD BC,&0
LD A,&2
CALL &BC98
CALL &BC8F
RST &0