Index du Forum
IDENTIFICATION SERVEUR : 10.14.20.199 - CLIENT : 44.192.253.106

 FAQFAQ   RechercherRechercher   Liste des MembresListe des Membres   Groupes d'utilisateursGroupes d'utilisateurs   S'enregistrerS'enregistrer 
 ProfilProfil   Se connecter pour vérifier ses messages privésSe connecter pour vérifier ses messages privés   ConnexionConnexion 

Drol (Broderbund - 1983)

 
Poster un nouveau sujet   Répondre au sujet     Index du Forum -> PROTECTION MALEFIQUE
Voir le sujet précédent :: Voir le sujet suivant  
Auteur Message
aloysiuscoincoin



Inscrit le: 17 Mar 2018
Messages: 24

MessagePosté le: Jeu 18 Fév 2021, 20:17    Sujet du message: Drol (Broderbund - 1983) Répondre en citant

Salut à tous !
Tout le monde connaît Drol, ce jeu super mignon avec son poulet cuit qui tressaute frénétiquement dans son plat. Je suis en train de tenter de le déplomber et je me propose de partager le processus ici si tant est que ça intéresse quelqu'un, dans ce qui va probablement ressembler à une sorte de feuilleton compte tenu de la protection que j'apprécie autant que le jeu lui-même.
Je déplombe à l'ancienne sur un vrai apple II avec le secours d'un wDrive connecté en tant que drive 2 pour cracker les images .woz puisque je n'ai pas de 'vrais' originaux à me mettre sous la dent.
Je commence toujours par tenter de faire une copie 'fonctionnelle' de l'image .woz vers une vraie disquette pour déplomber ensuite cette disquette, mais dans le cas de Drol, je n'ai pas réussi à faire une copie fonctionnelle, je tente donc de cracker l'image du soft insérée dans le drive 2. C'est pourquoi le boot-tracing passe sur le drive 2.
On peut toujours faire la copie du secteur 0 track 0 de n'importe quelle disquette c'est donc comme ça que je 'boote' le premier secteur de Drol sur le drive 1 pour basculer ensuite vers l'image sur le drive 2.

Comme dirait Dora l'exploratrice : "Allons-y let's go c'est parti les amis..."

Disque 1 : vraie disquette avec le secteur de boot de Drol
Disque 2 : wDrive avec l'image de Drol Piste 0

sur l'apple II, traditionnel début de boot tracing :
*9600<c600.c6ffM
*96f8:00
*9600G

Code:

; code chargé en $0800 mais relogé en $0200

0200: 01 a2      ORA ($A2,X)         
0202: 00         BRK                 
0203: bd 00 08   LDA $0800,X         ; reloge le code dans le buffer clavier
0206: 9d 00 02   STA $0200,X         
0209: e8         INX                 
020a: d0 f7      BNE $203           
020c: 4c 0f 02   JMP $020F           : << entrypoint réel


; ********************************
; entrypoint
; ********************************

020f: a0 ab      LDY #$AB           
0211: 98         TYA                 
0212: 85 3c      STA $3C             
0214: 4a         LSR A               
0215: 05 3c      ORA $3C             
0217: c9 ff      CMP #$FF           
0219: d0 09      BNE $224           
021b: c0 d5      CPY #$D5           
021d: f0 05      BEQ $224           
021f: 8a         TXA                 
0220: 99 00 08   STA $0800,Y         
0223: e8         INX                 
0224: c8         INY                 
0225: d0 ea      BNE $211         
 
0227: 84 3d      STY $3D             
0229: 84 26      STY $26             ; adresse de chargement pour le prochain secteur
022b: a9 03      LDA #$03            ; == $0300
022d: 85 27      STA $27             
022f: a6 2b      LDX $2B             

0231: 20 5d 02   JSR $025D           ; saut à chargement secteur suivant

0234: 20 d1 02   JSR $02D1           ; dénibbilisation en $0300
 
0237: 4c 01 03   JMP $0301           ; saut en $0301


Le secteur de boot charge un autre secteur en $0300, on peut le récupérer en modifiant le boot tracing du début comme ceci :

Code:
*9600<c600.c6ffM
96f8:   sta $c0eb   ; passe sur le drive 2
      lda #$13
      sta $082c
      lda #$00
       sta $0837
      jmp $0801


On obtient donc un code en $0300 :

Code:

0300: 99         ???                 ; code pour le décodage en EOR

;*************************************************
; Entrypoint phase 1
;*************************************************
0301: 84 48      STY $48
0303: a0 00      LDY #$00           
0305: 98         TYA                 
0306: a2 20      LDX #$20           
0308: 99 00 45   STA $4500,Y         
030b: c8         INY                 
030c: d0 fa      BNE $308           
030e: ee 0a 03   INC $030A           
0311: ca         DEX                 
0312: d0 f4      BNE $308            ; nettoyage page HGR2

0314: ad 57 c0   LDA $C057           
0317: ad 52 c0   LDA $C052           
031a: ad 55 c0   LDA $C055           
031d: ad 50 c0   LDA $C050           ; passage en HGR2

0320: b9 00 03   LDA $0300,Y         ; on prend le premier octet juste avant le code (octet == #$99)
0323: 45 48      EOR $48             ; EOR #$99
0325: 99 00 01   STA $0100,Y         ; on reloge le code en le décryptant vers $0100 (pile)
0328: c8         INY                 
0329: d0 f5      BNE $320           
032b: a2 cf      LDX #$CF            ; pointeur de pile modifié
032d: 9a         TXS                 
032e: 60         RTS                 ; saute à pointeur de pile+1 ($0130)

 
032f: 9b         ???                 ; inutile d'afficher le reste, c'est codé à coup de EOR #$99...
0330: 3b 9d 1f   rla $1F9D,Y         
0333: 1f 39 99   BBR1 $9939         
0336: 1d 1a 1f   ORA $1F1A,X         
0339: 1d 3f b2   ORA $B23F,X         


Jusque là c'est gentil mais il s'est quand même fait un petit plaisir en planquant l'adresse de saut finale via un RTS et une modification préalable du pointeur de pile...

On peut reconstituer l'état de la pile en exécutant le code ci-dessus.
La pile une fois décryptée montre ceci :
Code:

; bouillie d'octets provenant de la partie en clair encodée lors du 'décodage'
0100: 00         BRK                 
0101: 1d d1 39   ORA $39D1,X         
0104: 99 01 3b   STA $3B01,Y         
0107: b9 00 99   LDA $9900,Y         
010a: f9 51 49   SBC $4951,Y         
010d: 63 77      rra ($77,X)         
010f: 93 9a      sxa ($9A),Y         
0111: 53 49      sre ($49),Y         
0113: 6d 34 ce   ADC $CE34           
0116: 59 34 cb   EOR $CB34,Y         
0119: 59 34 cc   EOR $CC34,Y         
011c: 59 34 c9   EOR $C934,Y         
011f: 59 20 99   EOR $9920,Y         
0122: 9a         TXS                 
0123: dc d1 00   nop $00D1           
0126: 99 98 51   STA $5198,Y         
0129: 49 6c      EOR #$6C           
012b: 3b 56 03   rla $0356,Y         
012e: f9 02      ???

;*****************************************************
; entrypoint boot 2
;*****************************************************

0130: a2 04      LDX #$04            ; 4 secteurs à charger
0132: 86 86      STX $86
0134: A0 00      LDY #$00                         
0136: 84 83      STY $83             
0138: 86 84      STX $84             ; adresse de chgt == $0400 == page text
013a: a6 2b      LDX $2B             
013c: bd 8c c0   LDA $C08C,X         
013f: 10 fb      BPL $13C           
0141: c9 bf      CMP #$BF            ; bf ... trois marqueurs comme prologue
0143: d0 f7      BNE $13C           
0145: bd 8c c0   LDA $C08C,X         
0148: 10 fb      BPL $145           
014a: c9 d7      CMP #$D7            ; d7
014c: d0 f3      BNE $141           
014e: bd 8c c0   LDA $C08C,X         
0151: 10 fb      BPL $14E           
0153: c9 d5      CMP #$D5            ; d5
0155: d0 f3      BNE $14A           
0157: bd 8c c0   LDA $C08C,X         
015a: 10 fb      BPL $157           
015c: 2a         ROL A               
015d: 85 85      STA $85             
015f: bd 8c c0   LDA $C08C,X         
0162: 10 fb      BPL $15F           
0164: 25 85      AND $85             
0166: 91 83      STA ($83),Y         ; décodage en 4&4, ce n'est pas du 6&2
0168: c8         INY                 
0169: d0 ec      BNE $157           
016b: 0e 00 c0   ASL $C000           
016e: bd 8c c0   LDA $C08C,X         
0171: 10 fb      BPL $16E           
0173: c9 d4      CMP #$D4            ; marqueur de fin de secteur == $d4
0175: d0 b9      BNE $130           
0177: e6 84      INC $84             
0179: c6 86      DEC $86             ; un secteur en moins
017b: d0 da      BNE $157           
017d: 60         RTS                 ; saute à l'adresse suivante dans la pile ($0400) <<< bloquer ce saut dans le boot-tracing suivant


017e: e3 b1      ins ($B1,X)   

; ******************************************************
; retour après le RTS suite au chargement de la nouvelle pile (on verra ça plus tard)
; ******************************************************
; évidemment les données ci-dessous sont remplacées par celles qui seront chargées plus tard.     
0180: e6 91      INC $91             
0182: e4 e6      CPX $E6             
0184: e4 d0      CPX $D0             
0186: 02 e6      hlt                 
0188: e5 e6      SBC $E6             
018a: e6 d0      INC $D0             
018c: 02 e6      hlt                 
018e: e7 a5      SMB6 $A5           
0190: e6 c5      INC $C5             
0192: 4c a5 e7   JMP $E7A5           
0195: e5 4d      SBC $4D             
0197: 90 e6      BCC $17F           
0199: a2 fe      LDX #$FE           
019b: b5 e6      LDA $E6,X           
019d: 95 4e      STA $4E,X           
019f: b5 cc      LDA $CC,X           
01a1: f5 dc      SBC $DC,X           
01a3: 95 cc      STA $CC,X           
01a5: e8         INX                 
01a6: d0 f3      BNE $19B           
01a8: a6 d8      LDX $D8             
01aa: 60         RTS                 
01ab: b1 4c      LDA ($4C),Y         
01ad: 91 ce      STA ($CE),Y         
01af: a5 ce      LDA $CE             
01b1: d0 02      BNE $1B5           
01b3: c6 cf      DEC $CF             
01b5: c6 ce      DEC $CE             
01b7: a5 4c      LDA $4C             
01b9: d0 02      BNE $1BD           
01bb: c6 4d      DEC $4D             
01bd: c6 4c      DEC $4C             
01bf: c5 ca      CMP $CA             
01c1: a5 4d      LDA $4D             
01c3: e5 cb      SBC $CB             
01c5: 90 e4      BCC $1AB           
01c7: b0 d0      BCS $199           
01c9: 20 15 e7   JSR $E715           
01cc: a4 ce      LDY $CE             
01ce: c0 ca      CPY #$CA   
       
01d0: 2f 01 ff   BBR2 $FF01          ; << vecteur du RTS précédent (2f  01) + 1 == $130 == adresse de retour lors du premier RTS

01d3: 03 ff      slo ($FF,X)         ; l'adresse suivante est celle à laquelle saute le soft lors du RTS après le chgt des 4 secteurs en $0400 ($3ff +1 == $400)
01d5: 04 4f      TSB $4F             ; ensuite, retour en $0500 au prochain RTS (on verra ça dans la phase de chargement suivante)
01d7: 04 ff      TSB $FF             ; puis en $450
01d9: 1f 85 4b   BBR1 $4B85         
01dc: 4c b7 e5   JMP $E5B7           
01df: 86 d8      STX $D8             
01e1: 20 1e f1   JSR $F11E           
01e4: 20 fd fe   JSR $FEFD           
01e7: a2 ff      LDX #$FF           
01e9: 38         SEC                 
01ea: b5 4d      LDA $4D,X           
01ec: f5 cf      SBC $CF,X           
01ee: 95 db      STA $DB,X           
01f0: e8         INX                 
01f1: f0 f7      BEQ $1EA           
01f3: 90 87      BCC $17C           
01f5: a5 cc      LDA $CC             
01f7: c5 da      CMP $DA             
01f9: a5 cd      LDA $CD             
01fb: e5 db      SBC $DB             
01fd: b0 d5      BCS $1D4   


Il va falloir s'arrêter à l'adresse $017D au prochain boot-tracing, mais on voit déjà que cette protection aime bien la pile, le buffer clavier, la page TXT pour y mettre du code et sautiller comme un poulet cuit via des RTS plutôt que des appels normaux, histoire de simplifier la tâche certainement Wink. On peut voir également que c'est un format de 'secteurs' maison avec un encodage 4&4 et des marqueurs minimalistes : une séquence prologue + 512 nibbles + un nibble de fin + 512 nibbles + un nibble de fin + etc...
Plutôt sympa.
Smile

Pour charger la phase suivante, on va modifier l'ancien boot tracer avec ceci :

Code:
; Bidouillage de la recopie de la routine contrôleur disquette vers $8600
; 8600 < c600.c6ffM puis on ajoute cette partie pour tracer jusqu'à la phase suivante de boot

      .cr 6502 ; = choix du microprocesseur à assembler

      .or $86f8 ; = ORG
      .tf Drol_boot1.bin ,bin    ; target file (fichier assemblé)

; constantes
DRIVE2      .eq $c0eb   
MONITOR      .eq $ff59

prog_begin               ; début du prog

;   début de la routine   
      sta DRIVE2
      lda #boot0  ; adresse basse du label en $0838
      sta $0838   ; renvoie vers ici pour bidouiller le boot suivant
      lda /boot0  ; adresse haute du label en $0839
      sta $0839
      jmp $0801
boot0   lda #$8d   ; modifie l'adresse de retour dans la pile pour l'envoyer vers un peu plus bas et recopier le contenu
            ; de la page TEXT vers $1400 à $1800 (les valeurs remplacées tiennent compte du EOR #$99)
      sta $03d2
      lda #$1e
      sta $03d3
      jmp $0301 ; saute à l'exécution de la phase 1
retour   ldx #$00    ; la phase 1 revient ici après le chargement des 4 secteurs en $0400

read           lda $0400,x   ; recopie des 4 secteurs vers la zone $1400-$1800 avant le retour au moniteur
store   sta $1400,x       ; indispensable sinon on bousille la page TEXT en revenant au moniteur, bien entendu
      inx
      bne read
      inc read+2
      inc store+2
      lda store+2
      cmp #$18   ; on est à $1800 ?
      bne read
      jmp MONITOR

prog_end               ; fin du programme


Désolé, c'est assez moche à lire, mais on comprend le principe j'espère :/

Une fois qu'on a récupéré le code chargé en page TEXT, on peut y jeter un oeil :

Code:

Boot 3 - DROL
cette partie se charge normalement en $0400
-------------------------------
$4400 : A0 00      LDY #$00
$4402 : B9 00 06   LDA $0600,Y
$4405 : 99 00 BE   STA $BE00,Y
$4408 : B9 00 07   LDA $0700,Y
$440B : 99 00 BF   STA $BF00,Y
$440E : C8         INY
$440F : D0 F1      BNE $4402
$4411 : A6 2B      LDX $2B
$4413 : 8E 49 BF   STX $BF49
$4416 : 20 E0 BE   JSR $BEE0        ; recopie de la carte langage sur elle-même

$4419 : AD 83 C0   LDA $C083
$441C : AD 83 C0   LDA $C083
$441F : A0 00      LDY #$00
$4421 : A9 BF      LDA #$BF
$4423 : 8C FC FF   STY $FFFC
$4426 : 8D FD FF   STA $FFFD
$4429 : 8C F2 03   STY $03F2         ; revectorise le reset vers $BF00 dans la rom et en $3f2 et $3f3
$442C : 8D F3 03   STA $03F3         ; pour faciliter le boulot du déplombeur :D
$442F : A0 03      LDY #$03
$4431 : 8C F0 03   STY $03F0
$4434 : 8D F1 03   STA $03F1
$4437 : 84 36      STY $36
$4439 : 85 37      STA $37
$443B : 84 38      STY $38
$443D : 85 39      STA $39
$443F : 49 A5      EOR #$A5
$4441 : 8D F4 03   STA $03F4
$4444 : BA         TSX
$4445 : 9A         TXS ; ne fait rien
$4446 : E8         INX ; ne sert à rien
$4447 : BA         TSX ; car TSX lui redonne une valeur
$4448 : 9A         TXS ; ne sert à rien
$4449 : E8         INX
$444A : BA         TSX
$444B : 9A         TXS ; ne fait rien
$444C : E8         INX
$444D : BA         TSX ; met le stack pointer dans X
$444E : 60         RTS               ; saute en $0500 si l'on en croit la pile (celle plus haut dans le post) pour déplacer la le bras

en $0500 on trouve :
; ******************************************************
; adresse de retour après le RTS
; si l'on en croit la pile
; ******************************************************
$4500 : A0 00      LDY #$00
$4502 : A2 20      LDX #$20
$4504 : 98         TYA
$4505 : 99 00 20   STA $2000,Y
$4508 : C8         INY
$4509 : D0 FA      BNE $4505
$450B : EE 07 05   INC $0507
$450E : CA         DEX
$450F : D0 F4      BNE $4505            ; nettoie la page HGR1

$4511 : 2C 54 C0   BIT $C054
$4514 : A9 02      LDA #$02            ; 2 phases
$4516 : 4C 40 05   JMP $0540            ; déplacement piste 01


en $0540 :

$4540 : A2 13      LDX #$13
$4542 : 2C A2 0A   BIT $0AA2            ; cette instruction BIT est une astuce pour planquer le LDX #$0A à l'octet qui suit...
$4545 : 8E AE 05   STX $05AE
$4548 : 8D D0 05   STA $05D0            ; $05d0 == #$02 == piste 1 désirée (puis #$08 pour piste 4)
$454B : CD 48 BF   CMP $BF48            ; #$00 == piste actuelle
$454E : F0 59      BEQ $45A9            ; on y est déjà ? OK alors on sort...
.
.
.
.

$45A9 : AE 49 BF   LDX $BF49            ; LDX slot 6
$45AC : 60         RTS                  ; saute à la nouvelle adresse dans la pile ($0450)

Ce soft adore sautiller via la pile, c'est rigolo !

en $0450 :

$4450 : BA         TSX            ; pointeur de pile vers x
$4451 : 8A         TXA            ; vers accumulateur
$4452 : 18         CLC
$4453 : 69 28      ADC #$28      ; bidouillage pointeur de pile ... une manie...
$4455 : AA         TAX
$4456 : 9A         TXS            ; hop !

$4457 : A2 00      LDX #$00
$4459 : AC 49 BF   LDY $BF49      ; slot
$445C : B9 8C C0   LDA $C08C,Y
$445F : 10 FB      BPL $445C
$4461 : C9 DF      CMP #$DF      ; df      << Bien sûr, les marqueurs sont différents de ceux précédemment utilisés
$4463 : D0 F7      BNE $445C
$4465 : EA         NOP
$4466 : B9 8C C0   LDA $C08C,Y
$4469 : 10 FB      BPL $4466
$446B : C9 DE      CMP #$DE      ; de
$446D : D0 ED      BNE $445C
$446F : EA         NOP
$4470 : B9 8C C0   LDA $C08C,Y
$4473 : 10 FB      BPL $4470
$4475 : C9 DD      CMP #$DD      ; dd
$4477 : D0 E3      BNE $445C
$4479 : EA         NOP
$447A : B9 8C C0   LDA $C08C,Y
$447D : 10 FB      BPL $447A
$447F : 38         SEC
$4480 : 2A         ROL
$4481 : 85 00      STA $00
$4483 : B9 8C C0   LDA $C08C,Y
$4486 : 10 FB      BPL $4483
$4488 : 25 00      AND $00         ; encodage 4&4
$448A : 48         PHA            ; on remplace intégralement la pile avec les datas chargés directement (256 octets poussés)
$448B : CA         DEX            
$448C : D0 EC      BNE $447A      ; boucle sur les 256 octets à décoder en 4&4

$448E : B9 8C C0   LDA $C08C,Y
$4491 : 10 FB      BPL $448E
$4493 : C9 D5      CMP #$D5      ; marqueur de fin = D5 ? (différent de celui précédemment utilisé :D )
$4495 : D0 C5      BNE $445C      ; non ? on recommence
$4497 : 60         RTS            ; sinon saute à une adresse en fonction du pointeur de pile + #$28 et de la nouvelle pile
                           ; comme le pointeur de pile pointe vers l'adresse contenue en $0100 de la [color=orange]nouvelle[/color] pile, on ne sait pas où
                           ; il saute... trop malin... (il saute en fait à l'adresse $0180 mais bon, c'est quand même malin).



Donc, ce petit malin nous oblige à refaire un nouveau boot-tracer pour récupérer l'intégralité de la pile nouvellement chargée par cette routine et trouver l'adresse de saut $0180 appelée pour la poursuite du chargement du programme.
Very Happy
Code:

      .cr 6502 ; = choix du microprocesseur à assembler

      .or $86f8 ; = ORG
      .tf Drol_pileboot2.bin ,bin    ; target file (fichier assemblé)
*      .da prog_begin      ; insère l'adresse de début dans le fichier bin
*      .da prog_end - prog_begin    ; insère la taille en octets dans le fichier bin

; constantes
DRIVE2      .eq $c0eb   ; EQU
MONITOR      .eq $ff59

prog_begin               ; début du prog

;   début de la routine   
      sta DRIVE2
      lda #boot0  ; adresse basse du label en $0838
      sta $0838   ; renvoie vers ici pour bidouiller le boot suivant
      lda /boot0  ; adresse haute du label en $0839
      sta $0839
      jmp $0801
boot0   lda #$8d   ; modifie l'adresse de retour dans la pile pour l'envoyer vers un peu plus bas (retour)
      sta $03d2
      lda #$1e
      sta $03d3
      jmp $0301   ; saute à l'exécution de la phase 1

retour   lda #$4c   ; jmp
      sta $0497   ; notre dernier RTS remplacé par JMP
      lda #boot1 
      sta $0498   
      lda /boot1 
      sta $0499   ; on a ajouté JMP boot1 à la fin du remplacement de la pile dans le code du jeu
      jmp $0400   ; on saute là où devait revenir le soft au lieu de 'retour' plus haut


boot1   ldx #$00   ; la phase 2 revient ici après le chargement des de la nouvelle pile

.loop   lda $0100,x   ; on recopie la pile vers l'adresse $1100
      sta $1100,x
      inx
      bne .loop
      jmp MONITOR   ; et on rend la main

prog_end               ; fin du programme


La nouvelle pile a cette tête là :
Code:

0100: 7f 01 3F   BBR7 $9201          ; détermine l'adresse de saut du dernier RTS... puis saute en $0540 après la routine en $180
0103: 05 0c      ORA $0C             ; puis saut à $BE0D après le déplacement en piste 8
0105: be 01 05   LDX $0501,Y         
0108: ff 0e 04   BBS7 $040E         
010b: 01 05      ORA ($05,X)         
010d: de a2 06   DEC $06A2,X         


On voit que le soft saute en $017f + 1 (donc $0180) au rts sur lequel on a collé un breakpoint.

Voici la routine :

Code:

; chargement d'un secteur page zéro
0180: b9 8c c0   LDA $C08C,Y       
0183: 10 fb      BPL $0180
0185: c9 d5      CMP #$D5            ; d5  << pour changer... nouveau prologue :D
0187: d0 f7      BNE $180           
0189: ea         NOP                 
018a: b9 8c c0   LDA $C08C,Y         
018d: 10 fb      BPL $18A           
018f: c9 aa      CMP #$AA            ; aa 
0191: d0 ed      BNE $180           
0193: ea         NOP                 
0194: b9 8c c0   LDA $C08C,Y         
0197: 10 fb      BPL $194           
0199: c9 b5      CMP #$B5            ; b5 
019b: d0 e3      BNE $180             
 
019d: ea         NOP                 
019e: b9 8c c0   LDA $C08C,Y         
01a1: 10 fb      BPL $19E           
01a3: 38         SEC                 
01a4: 2a         ROL A               
01a5: 8d ff 01   STA $01FF           ; 4&4
01a8: b9 8c c0   LDA $C08C,Y         
01ab: 10 fb      BPL $1A8           
01ad: 2d ff 01   AND $01FF           ; décodage 4&4
01b0: 95 00      STA $00,X           
01b2: e8         INX                 ; remplit la page zéro
01b3: d0 e8      BNE $19D           

01b5: b9 8c c0   LDA $C08C,Y         
01b8: 10 fb      BPL $1B5           
01ba: c9 d4      CMP #$D4            ; marqueur de fin == d4 comme le premier
01bc: d0 c2      BNE $180            ; on recommence tout si pas trouvé
01be: a9 08      LDA #$08            ; déplacement sur une nouvelle piste
01c0: 60         RTS                 ; saute à $0540 ($053f + 1) conformément à la pile actuelle (déplace le bras)


Ce soft est un obsédé des sauts via RTS, c'est pas fini ^^'
La suite au prochain épisode.
Smile
Revenir en haut de page
Voir le profil de l'utilisateur Envoyer un message privé
toinet
Site Admin


Inscrit le: 15 Juin 2007
Messages: 3077
Localisation: Le Chesnay, France

MessagePosté le: Ven 19 Fév 2021, 17:07    Sujet du message: Répondre en citant

On veut la suite !

C'est une protection de Roland Gustaffson. Toujours long et sciant à suivre, à la mode Karateka...
Revenir en haut de page
Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web de l'utilisateur
aloysiuscoincoin



Inscrit le: 17 Mar 2018
Messages: 24

MessagePosté le: Dim 21 Fév 2021, 11:06    Sujet du message: Répondre en citant

Re !
Sans m'étaler plus avant, j'ai beaucoup de boulot et assez peu de temps pour faire le rigolo sur internet, il y a un risque assez élevé que ce feuilleton se prolonge à coup de posts erratiques.
Embarassed

Allez, on reprend tranquillou.
Notre dernier RTS revient en $0540, rappelez-vous :
cf. la tête de la pile...
Code:
0100: 7f 01 3F   BBR7 $9201          ; détermine l'adresse de saut du dernier RTS... puis saute en $0540 après la routine en $180
0103: 05 0c      ORA $0C             ; puis saut à $BE0D après le déplacement en piste 8
0105: be 01 05   LDX $0501,Y         
0108: ff 0e 04   BBS7 $040E     


Il nous faut aller jeter un oeil en $0540 rapidement :
Code:

;*************************************************************
; retour de la deuxième pile (déplacement de la tête )
;*************************************************************
$4540 : A2 13      LDX #$13            ; valeur de temporisation
$4542 : 2C A2 0A   BIT $0AA2            ; cette instruction BIT est une astuce pour planquer le LDX #$0A à l'octet qui suit...
$4545 : 8E AE 05   STX $05AE
$4548 : 8D D0 05   STA $05D0            ; puis #$08 pour piste 4 ??
$454B : CD 48 BF   CMP $BF48            ; piste actuelle
$454E : F0 59      BEQ $45A9            ; on y est déjà ? OK alors on sort...

$4550 : A9 00      LDA #$00            ; routine SEEK pour déplacer la tête sur la piste voulue...
.
.
.
$45A6 : BD 80 C0   LDA $C080,X         ; << déplace le moteur pas à pas

$45A9 : AE 49 BF   LDX $BF49            ; LDX slot 6
$45AC : 60         RTS                  ; saute à la nouvelle adresse dans la pile ($BE0D)


Donc le soft continue à nous balader à coup de RTS. J'adore ce Roland Gustaffson Very Happy

Code:
be0d: ae 49 bf   LDX $BF49           ; #$60, slot 6
be10: a9 04      LDA #$04            ; nb de secteurs à charger
be12: 85 a1      STA $A1             
be14: a0 00      LDY #$00           
be16: a9 5c      LDA #$5C            ; ($A2) = $5c00 = adresse de chargement de la suite.
be18: 84 a2      STY $A2             
be1a: 85 a3      STA $A3             

be1c: bd 8c c0   LDA $C08C,X         ; ici on est piste 4
be1f: 10 fb      BPL $BE1C           
be21: c9 b5      CMP #$B5            ; B5
be23: d0 f7      BNE $BE1C           
be25: bd 8c c0   LDA $C08C,X         
be28: 10 fb      BPL $BE25           
be2a: c9 b6      CMP #$B6            ; B6
be2c: d0 f3      BNE $BE21           
be2e: bd 8c c0   LDA $C08C,X         
be31: 10 fb      BPL $BE2E           
be33: c9 b7      CMP #$B7            ; B7
be35: d0 f3      BNE $BE2A           

be37: bd 8c c0   LDA $C08C,X         
be3a: 10 fb      BPL $BE37           
be3c: 2a         ROL A               
be3d: 85 a0      STA $A0             ; adresse temporaire de décodage des nibbles
be3f: bd 8c c0   LDA $C08C,X         
be42: 10 fb      BPL $BE3F           
be44: 25 a0      AND $A0             ; octet reconstitué
be46: 91 a2      STA ($A2),Y         ; on stocke en $5c00 et plus
be48: c8         INY                 
be49: d0 ec      BNE $BE37           

be4b: 0e ff ff   ASL $FFFF           
be4e: bd 8c c0   LDA $C08C,X         
be51: 10 fb      BPL $BE4E           
be53: c9 d4      CMP #$D4            ; marqueur de fin de secteur
be55: d0 b9      BNE $BE10           ; si pas trouvé, on recommence

be57: e6 a3      INC $A3             ; sinon, on incrémente l'adresse haute de chgt
be59: c6 a1      DEC $A1             ; il reste un secteur de moins à charger
be5b: d0 da      BNE $BE37           ; tant que le nb de secteurs =/= 0 on continue

be5d: 4c a0 be   JMP $BEA0           ; on saute à la suite


Cette routine s'avère être un loader 'statique' en mémoire qui charge la routine de chargement à chaque 'fin' (oui... le soft prend pour ainsi dire tout l'espace mémoire disponible et lors d'un chargement (changement de niveau vers niveau supérieur ou retour au niveau 0 après la mort), il passe en HGR1 où il anime un rideau qui se ferme et charge ensuite dans l'espace mémoire HGR2 la routine qui va charger le nouveau niveau.


Code:
bea0: 20 00 5c   JSR $5C00           ; continue le chargement en sautant vers ce qu'il vient de charger (JSR donc on en revient normalement !)
bea3: 20 7f bf   JSR $BF7F           ; routine de déplacement en HGR2
bea6: a2 21      LDX #$21           
bea8: bd 80 73   LDA $7380,X         ; vide une partie de la mémoire (valeur : 00)
beab: 85 a0      STA $A0             
bead: bd 40 74   LDA $7440,X         
beb0: 85 a1      STA $A1             
beb2: a0 27      LDY #$27           
beb4: a9 00      LDA #$00           
beb6: 91 a0      STA ($A0),Y         
beb8: 88         DEY                 
beb9: 10 fb      BPL $BEB6           
bebb: e8         INX                 
bebc: e0 bc      CPX #$BC           
bebe: 90 e8      BCC $BEA8   
       
bec0: a9 00      LDA #$00           
bec2: a0 40      LDY #$40           
bec4: 85 a0      STA $A0             
bec6: 84 a1      STY $A1             
bec8: a2 20      LDX #$20           
beca: a0 78      LDY #$78           
becc: 91 a0      STA ($A0),Y         
bece: c8         INY                 
becf: 10 fb      BPL $BECC           
bed1: a0 f8      LDY #$F8           
bed3: 91 a0      STA ($A0),Y         
bed5: c8         INY                 
bed6: 30 fb      BMI $BED3           
bed8: e6 a1      INC $A1             
beda: ca         DEX                 
bedb: d0 ed      BNE $BECA           
bedd: 60         RTS              ; encore un RTS :D


Bien sûr, la routine en $5c00 nous intéresse, il faut donc la récupérer... et pour ça, un petit loader :
Code:
      .cr 6502 ; = choix du microprocesseur à assembler

      .or $86f8 ; = ORG
      .tf Drol_loadboot5.bin ,bin    ; (fichier assemblé)


; constantes
DRIVE2      .eq $c0eb   ; EQU
MONITOR      .eq $ff59

prog_begin               ; début du prog

;   début de la routine   
      sta DRIVE2
      lda #boot0  ; adresse basse du label en $0838
      sta $0838   ; renvoie vers ici pour bidouiller le boot suivant
      lda /boot0  ; adresse haute du label en $0839
      sta $0839
      jmp $0801
boot0   lda #$8d   ; modifie l'adresse de retour dans la pile pour l'envoyer vers un peu plus bas (retour)
      sta $03d2
      lda #$1e
      sta $03d3
      jmp $0301   ; saute à l'exécution de la phase 1

retour   lda #$59   ; au lieu de sauter en $5c00 après le chargement, on saute au moniteur
      sta $06a1 ; et on reprend la main
      lda #$ff
      sta $06a2
      
      jmp $0400   ; on saute là où devait revenir le soft au lieu de 'retour' plus haut

prog_end               ; fin du programme


Maintenant, on peut aller jeter un œil curieux du côté de $5c00, la fameuse routine de chargement... qui fait 4 secteurs, il y a un peu de monde...

Code:
5c00: a9 04      LDA #$04            ; phase 4 ou piste 4 ?
5c02: 20 00 5f   JSR $5F00             ; déplacement de la tête sur quelle piste ?
       
5c05: a9 00      LDA #$00            ; index pour les marqueurs
5c07: 85 e1      STA $E1             ; dans $E1
5c09: 20 00 5e  [b] JSR $5E00           ; charge 8 secteurs de $5000 à 5800...[/b]
[color=violet][b]5c0c:[/b][/color]

[b][color=red]5c0c: 4c 00 50   JMP $5000           ; <<<<<<<< on saute à BOOT 6 (Il faut modifier le boot loader pour reprendre la main ICI)[/b][/color]


Bien sûr, les commentaire au-dessus proviennent de l'analyse des routines ci-dessous...

Code:

; déplacement du bras
5f00: a2 13      LDX #$13            ; temporisation
5f02: 2c                         ; astuce qui permet de passer l'instruction suivante
                                    ; en faisant un BIT $xxxx sans intérêt :)
[color=red]5f03: a2 0a      LDX #$03           ; instruction ignorée à la première itération[/color]
                                    ; mais exécutée au second appel
5f05: 8e 6e 5f   STX $5F6E           ; temporisation qui change selon l'appel ?
5f08: 8d 90 5f   STA $5F90           ; << valeur A == 4 au premier passage mais 01 au second passage (nb de phases par piste ?)
5f0b: cd 48 bf   CMP $BF48           ; cmp #$00 ?
5f0e: f0 59      BEQ $5F69           ; si 0, on sort

5f10: a9 00      LDA #$00            ; sinon on continue
.
.
.
5f65: aa         TAX                 
5f66: bd 80 c0   LDA $C080,X         ; déplacement du bras

5f69: ae 49 bf   LDX $BF49           ; sortie
5f6c: 60         RTS               
 


et aussi :

Code:

;*********************************************************
; chargement des secteurs 2 par 2
;*********************************************************
5e00: a0 00      LDY #$00         
5e02: a9 50      LDA #$50           
5e04: 84 e2      STY $E2             ; $E2 == 00 == 'passe' actuelle de 2 secteurs
5e06: 48         PHA                 ; << 50
5e07: 20 30 5e   JSR $5E30           ; chargement Y secteurs ayant les mêmes marqueurs (d'abord 2)
 
5e0a: a4 e2      LDY $E2             
5e0c: 18         CLC                 
5e0d: ad 48 bf   LDA $BF48           ; 00
5e10: 79 28 5e   ADC $5E28,Y         ; on ajoute 1
5e13: 20 03 5f   [color=red]JSR $5F03[/color]           ; déplace le bras
5e16: 68         PLA                 ; A == 50
5e17: 18         CLC                 
5e18: 69 02      ADC #$02            ; augmente l'adresse haute de chgt ($5200 now)
5e1a: a4 e2      LDY $E2             ; 00
5e1c: c8         INY                 ; 01
5e1d: c0 04      CPY #$04            ; on charge 3 x 2 secteurs de plus en changeant les marqueurs...
5e1f: 90 e3      BCC $5E04           ; boucle si on n'est pas arrivé à Y = 4
5e21: 60         RTS                 ; revient en [b]$5c0c[/b]

5e22: 00         BRK                 
5e23: 00         BRK                 
5e24: 00         BRK                 
5e25: 00         BRK                 
5e26: 00         BRK                 
5e27: 00         BRK         
       
;*********************************************************
; table de ???
;*********************************************************
5e28: 01 ff      ORA ($FF,X)         
5e2a: 01 00      ORA ($00,X)         
5e2c: 00         BRK                 
5e2d: 00         BRK                 
5e2e: 00         BRK                 
5e2f: 00         BRK   

;*********************************************************
; vers le chargement des secteurs
;*********************************************************             
5e30: 48         PHA                 ; << 50
5e31: a5 e1      LDA $E1             ; index de la table
5e33: 29 07      AND #$07           
5e35: a8         TAY                 
5e36: b9 50 5e   LDA $5E50,Y         ; table des marqueurs de début de secteur
5e39: 85 90      STA $90             ; marqueur 1 stocké en $90
5e3b: a5 e1      LDA $E1             
5e3d: 4a         LSR A               
5e3e: 09 aa      ORA #$AA           
5e40: 85 91      STA $91             ; marqueur 2 en $91 calculé à partir de [u]l'[b]index[/b][/u] du premier marqueur
5e42: a5 e1      LDA $E1             
5e44: 09 aa      ORA #$AA           
5e46: 85 92      STA $92             ; marqueur 3 en $92 calculé à partir de [u][b]l'index[/b] [/u]du premier marqueur
5e48: 68         PLA                 ; <<A>$5800
prog_end         ; fin du programme


On peut maintenant regarder ce qui se passe en $5000 et plus
Code:

;******************************************************************************
; BOOT 6 - sert à charger un level (si l'on meurt ou si l'on passe au suivant)
;******************************************************************************
5000: ae 4a bf   LDX $BF4A           ; FF au premier appel donc négatif donc chgt phase 6
                               ; cet octet est le type de level à charger
                               ; la valeur FF correspond au tout premier chargement (jeu non démarré)
5003: 10 03      BPL $5008           ; on ne saute pas mais si $BF4A positif, on saute pour charger le niveau suivant
[b]5005: 4c 00 53   JMP $5300           ; entrypoint de la phase 6 qui est le loader final[/b]
; la suite est intéressante car cette routine n'est pas appelée qu'une seule fois, elle fait déjà partie du jeu

5008: e8         INX                 ; admettons que c'est le nb de vies restantes ou le level courant
5009: 8a         TXA                 
500a: 29 03      AND #$03            ; le 'level' à charger ne peut être que de zéro à 3
500c: aa         TAX                 
500d: 24 44      BIT $5053           ; test l'état du jeu (mort / pas mort) et donc si on revient au level 0 ?
500f: 30 02      BMI $5013           ; Le flag minus est triggered si le joueur est mort, sinon on ne recharge pas le Level 00

5011: a2 00      LDX #$00            ; remise à zéro du n° de level (après la mort ?)

5013: 8e 4a bf   STX $BF4A           ; n° de level à charger
5016: bc f0 50   LDY $50F0,X         ; #$A0 == offset dans la table de chgt à venir en $5500
5019: a9 14      LDA #$14            ; piste 20 (ou 10 si c'est des phases)
501b: 20 00 55   JSR $5500           ; chargement

501e: ae 4a bf   LDX $BF4A           ; n° de level
5021: a0 40      LDY #$40            ; offset dans la table de chgt à venir en $5500
5023: bd f8 50   LDA $50F8,X         ; phase $22 ? (donc piste $11 ?) prise dans la table des phases
5026: 20 00 55   JSR $5500           ; chargement

5029: a9 08      LDA #$08            ; piste 4 ?
502b: 20 00 57   JSR $5700           ; remet le bras piste 4 ?
502e: bd 88 c0   LDA $C088,X         ; éteint le moteur  ! c'est toujours bon signe !
5031: 60         RTS                 ; << revient à l'appelant
Revenir en haut de page
Voir le profil de l'utilisateur Envoyer un message privé
aloysiuscoincoin



Inscrit le: 17 Mar 2018
Messages: 24

MessagePosté le: Dim 21 Fév 2021, 11:41    Sujet du message: Répondre en citant

Je continue ici parce que tout mettre dans un seul post fait bugger l'affichage du post sur le forum :/

Code:

;*********************************************************************************   
; table des offsets à attribuer vers la table de chgt en $5500 - chgt partie 1
;*********************************************************************************   
50f0: 90 a0      BCC $5092           
50f2: b0 c0      BCS $50B4         
50f4: 00         BRK                 
50f5: 00         BRK                 
50f6: 00         BRK                 
50f7: 00         BRK   

;*********************************************************************************   
; table des phases à attribuer vers la table de chgt en $5500 - chgt partie 2
;*********************************************************************************               
50f8: 16 22      ASL $22,X           
50fa: 2e 3a 00   ROL $003A           
50fd: 00         BRK                 
50fe: 00         BRK                 
50ff: 00         BRK     


en $5300 :

;****************************************************************
; BOOT 6 - entrypoint - le nouveau chargement se fait en 3 parties
;****************************************************************
5300: a9 0a      LDA #$0A            ; piste ou phase $0a ?           
5302: a0 00      LDY #$00            ; offset dans la table des adresses hautes de chgt
5304: 20 00 55   JSR $5500           ; chargement partie 1

5307: a0 00      LDY #$00           
5309: b9 00 5c   LDA $5C00,Y         ; déplacement des portions $5c00 vers $100 et $5d00 vers $300
530c: 99 00 01   STA $0100,Y         
530f: b9 00 5d   LDA $5D00,Y         
5312: 99 00 03   STA $0300,Y         
5315: c8         INY                 
5316: c0 f0      CPY #$F0           
5318: 90 ef      BCC $5309           
531a: ee 4a bf   INC $BF4A           ; $BF4A ?

531d: a2 ff      LDX #$FF            ; reset du pointeur de pile
531f: 9a         TXS                 

5320: a9 14      LDA #$14            ; piste $14 ?
5322: a0 90      LDY #$90            ; offset dans la table des adresses hautes de chgt
5324: 20 00 55   JSR $5500           ; chargement partie 2

5327: a9 16      LDA #$16            ; piste $16 ?
5329: a0 40      LDY #$40            ; offset dans la table des adresses hautes de chgt
532b: 20 00 55   JSR [b]$5500           ; chargement partie 3

532e: a9 08      LDA #$08            ; piste $08 ou phase (donc piste 4) ?
5330: 20 00 57   JSR $5700           ; déplacement du bras
5333: bd 88 c0   LDA $C088,X         ; on éteint le drive ! youpi !

;******************************************
;******************************************
; à partir d'ici LE JEU COMMENCE
;******************************************
;******************************************
; mais on arrive ici via un JSR ce qui veut dire que l'état de la pile est important et qu'à un moment,
; il reviendra à l'adresse $BEA3 via un RTS !
;******************************************
5336: 20 00 40   JSR $4000           ; ADRESSE DE FIN DE BOOT TRACING
                               ; cette routine en $4000 affiche le bandeau haut et bas de DROL en HGR1 (image fixe)
5339: a9 00      LDA #$00           
533b: 8d f8 03   STA $03F8           
533e: 8d ff 03   STA $03FF           
5341: a9 43      LDA #$43           
5343: 8d f9 03   STA $03F9           
5346: a9 6b      LDA #$6B           
5348: 8d fa 03   STA $03FA           
534b: a9 93      LDA #$93           
534d: 8d fb 03   STA $03FB           
5350: a9 bb      LDA #$BB           
5352: 8d fc 03   STA $03FC           
5355: ad 70 c0   LDA $C070           ; manette
5358: a2 04      LDX #$04           
535a: a0 00      LDY #$00           
535c: ad 64 c0   LDA $C064           ; manette
535f: 0d 65 c0   ORA $C065           ; manette... on est dans la boucle principale ?
5362: 10 15      BPL $5379           ; on sort vers la suite
5364: 88         DEY                 
5365: d0 f5      BNE $535C           
5367: ca         DEX                 
5368: d0 f2      BNE $535C           

536a: a9 19      LDA #$19           
536c: 85 52      STA $52             
536e: 85 54      STA $54             
5370: a9 62      LDA #$62           
5372: 85 53      STA $53             
5374: 85 55      STA $55             
5376: d0 0f      BNE $5387           ; vers suite 2

5378: 00         BRK                 


Bien sûr, il nous faut le boot-tracer final qui va nous amener ici comme breakpoint :

Code:

5336: 20 00 40   JSR $4000           ; ADRESSE DE FIN DE BOOT TRACING
                               ; cette routine en $4000 affiche le bandeau haut et bas de DROL (image fixe)


Le voici :

Code:

.cr 6502 ; = choix du microprocesseur à assembler

      .or $86f8
      .tf Drol_loadFinal.bin ,bin


; constantes
DRIVE2      .eq $c0eb   ; EQU
MONITOR      .eq $ff59
PILE      .eq $bf00   ; le stockage de l'état du pointeur de pile se fait en dehors de la zone de chgt
                  ; pour qu'il ne soit pas écrasé... par le chargement...
                  ; la routine de gestion du reset semble un bon endroit pour ça
                  ; le reset revectorisé ne sert à rien tant qu'on appuie pas sur reset

prog_begin               ; début du prog

;   début de la routine   
      sta DRIVE2   ; mon wDrive est branché en tant que drive 2
      lda #boot0  ; adresse basse du label
      sta $0838   ; renvoie vers ici pour bidouiller le boot suivant
      lda /boot0  ; adresse haute du label
      sta $0839
      jmp $0801

boot0   
      sta saveA
      lda #retour-1    ; modifie l'adresse de retour dans la pile pour l'envoyer vers un peu plus bas (retour)
      eor #$99        ; il faut l'adapter pour le décodage à base de XOR et enlever 1 car on saute à cette adresse
      sta $03d2       ; via un RTS
      lda /retour2
      eor #$99
      sta $03d3
      lda saveA

      jmp $0301   ; saute à l'exécution de la phase 1

retour   
      ; ATTENTION, cette modification, une fois relogée ne sera pas écrasée par les chargements suivants
      ; En effet, elle est relogée en $Bea1 et $BEa2 (et cette partie n'est jamais rechargée !)
      ; tant qu'on ne veut pas démarrer le jeu, pas de souci si on n'oublie pas de 'réparer' cette instruction
      ; avant de sauvegarder la portion mémoire, mais si on laisse le jeu se lancer, lors d'un changement de niveau
      ; le jeu plante... évidemment :D
      sta saveA
      lda #retour2   ; au lieu de sauter en $5c00 après le chargement, on saute à la modification retour2
      sta $06a1
      lda /retour2
      sta $06a2
      lda saveA

      jmp $0400   ; on saute là où devait revenir le soft au lieu de 'retour' plus haut

retour2
      ; rétablissement de l'adresse en $Bea1 et $Bea2
      lda #$00
      sta $bea1
      lda #$5c
      sta $bea2

      sta saveA
      lda #retour3   
      sta $5c0d   ; modifie le JMP $5000 en JMP retour3 (moniteur)
      lda /retour3
      sta $5c0e
      lda saveA

      jmp $5c00   ; saute à la dernière routine modifiée qui charge $5000->$5800

retour3
      sta saveA   ; backup A
      stx saveX   ; backup X
      tsx         ; pointeur de pile vers X
      stx PILE   ; backup pointeur de pile
      ldx #$06   ; 6
.boucle   lda chgt3,x   ; ici on modifie les tables d'adresse haute de chgt des phases 1 et 3
      sta $5440,x   ; pour charger la partie 'fragile' (page texte etc.) dans la page HGR1
      dex
      bpl .boucle

bckPZ   
      ldx #$00   ; il est préférable de sauvegarder également la page zéro et la pile pour étude ultérieure du code
      stx $03f4   ; défonce la revectorisation du reset... ça peut toujours servir...
rd      .db $bd,$00,$00 ; (lda $0000,x) backup $0000-->$01ff (PZ et pile) ATTENTION il ne faut pas que l'assembleur produise LDA $00,X !
wt      sta $2000,x
      inx
      bne rd
      inc rd+2
      inc wt+2
      lda rd+2
      cmp #$02   ; stop à l'adresse $0200
      bne rd

      ldx #15      ; 21
.loop   lda chgt1,x
      sta $5402,x
      dex
      bpl .loop
      lda #$59   ; saut au moniteur au lieu du saut vers $4000
      sta $5337
      lda #$ff
      sta $5338
      lda saveA    ; A intact
      ldx PILE   
      tsx       ; on remet la pile comme avant
      ldx saveX   ; X intact
      jmp $5000   ; on continue l'exécution du code modifié et qui va stopper en $5336

chgt3
      .db $22,$33,$34,$35,$36,$37,$38
chgt1
      .db $24,$25,$26,$27,$28,$29,$2a,$2b,$2c,$2d,$2e,$2f,$30,$31
      .db $32,$39,$3a,$3b,$3c,$3d,$3e,$3f
saveA   .db $00
saveX   .db $00



Après ce loader, le jeu est totalement chargé et on peut sauvegarder toutes les plages mémoire que l'on veut pour une analyse en 'dead listing' tranquillou.
On peut aussi bidouiller ce loader pour lancer le jeu au lieu de reprendre la main et ainsi être en mesure de récupérer la page zéro à divers moments du jeu, par exemple pour faire un patch qui met plus de vies à ce jeu assez difficile.
A ce propos, c'est ce que j'ai fait et si l'on fait ceci, on peut lancer l'ORIGINAL du jeu avec 70 vies à chaque départ plutôt que 4 vies :

no comment :


Ensuite on tape le patch en ram


et si l'on a la chance d'avoir l'original et qu'on le boote direct du drive 1, il faut supprimer le passage au drive 2


*8600G
et le jeu original se lance avec 70 vies au lieu de 4
Very Happy

A ce stade, on peut aussi reconstituer une disquette bootable du jeu à l'arrache pour jouer le premier niveau en chargeant tout l'espace mémoire auquel on a maintenant accès.

D'ailleurs, c'est ce que j'ai fait :

crack de Drol en cours :
https://uptobox.com/y6mmoiu82ky1

Bien sûr, en bootant cette image, on constatera que le chien/reptile à réaction a un petit problème graphique et bien entendu, on ne peut à ce stade jouer que le premier niveau parce que les routines de chargement ne sont pas modifiées et le jeu plante quand on passe au niveau suivant, mais c'est un premier stade du déplombage pour rigoler et ça se copie au locksmith 5.0.

Maintenant, le plus compliqué sera de trouver la place pour modifier les routines de chargement sans trop déborder car celles de Drol sont très courtes et charger des secteurs 'normaux' en 6&2, ça prend plus de place. Il faudra également récupérer 'manuellement' les données chargées lors des autres niveaux afin de finaliser le tout et d'accorder ça avec les nouvelles routines de chargement.

C'est pas gagné du tout vu le sac de noeuds qu'est ce système de chargement mais tant qu'on s'amuse Wink
Revenir en haut de page
Voir le profil de l'utilisateur Envoyer un message privé
amauget



Inscrit le: 06 Déc 2009
Messages: 969
Localisation: Nantes

MessagePosté le: Dim 21 Fév 2021, 15:01    Sujet du message: Répondre en citant

Impressionnant !
_________________
Antony
Apple II forever
Revenir en haut de page
Voir le profil de l'utilisateur Envoyer un message privé
aloysiuscoincoin



Inscrit le: 17 Mar 2018
Messages: 24

MessagePosté le: Dim 21 Fév 2021, 18:21    Sujet du message: Répondre en citant

Ouaip, le type qui a pondu ce schéma n'était probablement pas un néophyte Laughing
Sacré foufou ce Roland... Shocked
Mais c 'est l'éclate d'essayer de comprendre comment il a agencé tout ça en écoutant du Madonna avec un walkman et en buvant du Get27. Effet "Machine à remonter dans le temps" assuré Mr. Green
Revenir en haut de page
Voir le profil de l'utilisateur Envoyer un message privé
toinet
Site Admin


Inscrit le: 15 Juin 2007
Messages: 3077
Localisation: Le Chesnay, France

MessagePosté le: Dim 21 Fév 2021, 21:09    Sujet du message: Répondre en citant

Well (temporary) done!
av
Revenir en haut de page
Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web de l'utilisateur
aloysiuscoincoin



Inscrit le: 17 Mar 2018
Messages: 24

MessagePosté le: Ven 26 Fév 2021, 20:52    Sujet du message: Répondre en citant

Hop hop hop !
J'ai eu un peu de temps pour jeter un œil un peu moins distrait au code de chargement de Drol et je pense que le crack va pouvoir se faire.
On a la place en RAM et une fois le chargement bien compris, il faudra simplement un peu de temps pour remplacer les routines de lecture et refabriquer une disquette structurée convenablement.
Ce que j'ai pu déduire :
1 - l'émulateur que j'utilise afin de produire les listings (non, je ne retape pas tout ce que j'ai sorti sur une applewriter Wink ) est buggé au niveau du désassembleur et même si c'est rigolo, il a fallu que je m'étonne de certaines parties du code pour me rendre compte qu'il affichait parfois des trucs bizarres. Super émulateur à part ça : MicroM8.

Je ne sais pas s'il produit d'autres erreurs d'interprétation du code, on verra.
ps : je ne corrigerai pas les listing plus haut, trop de boulot.

2 - Drol :
La progression dans le jeu s'effectue via 4 'rounds' qui bouclent
0 - scorpion
1 - bestioles bizarres qui ressemblent à des lapins flippants quand on est myope
2 - serpents
3 - saynète résumant la progression

Chaque fois qu'on boucle sur ces 4 rounds, la difficulté augmente (ennemis qui crachent - aspirateur - plante carnivore - trucs explosifs - variation des paramètres de vitesse etc...)
Le soft appelle à chaque fois la routine en $5000 pour charger le niveau suivant, ce qui colle avec la logique d'écriture de cette routine :
Code:
5000: ae 4a bf   LDX $BF4A           ; FF au premier appel donc négatif donc chgt phase 6
                               ; cet octet est le type de level à charger
                               ; la valeur FF correspond au tout premier chargement (jeu non démarré)
5003: 10 03      BPL $5008           ; toutes les fois suivantes (donc les niveaux suivants) on saute au dessus du chgt en $5300
5005: 4c 00 53   JMP $5300           ; entrypoint de la phase 6 : cette partie n'est chargée qu'une seule fois !

5008: e8         INX                 ; C'est le level courant
5009: 8a         TXA                 
500a: 29 03      AND #$03            ; le 'level' à charger ne peut être que de 0 à 3, ce sont les 4 'rounds' cycliques
500c: aa         TAX                 
500d: 24 44      BIT $44              ; test l'état du jeu (mort / pas mort) et donc si on revient au level 0 ?
500f: 30 02      BMI $5013           ; Le flag minus est triggered si le joueur est mort, sinon on ne recharge pas le Level 00

5011: a2 00      LDX #$00            ; remise à zéro du n° de level (après la mort ?)

5013: 8e 4a bf   STX $BF4A           ; n° de level à charger
5016: bc f0 50   LDY $50F0,X         ; #$90 == offset dans la table des marqueurs à venir en $5500
5019: a9 14      LDA #$14            ; piste 20 (ou 10 si c'est des phases)
501b: 20 00 55   JSR $5500           ; chargement : A = phase et Y = index des marqueurs à employer

501e: ae 4a bf   LDX $BF4A           ; n° de level
5021: a0 40      LDY #$40            ; offset dans la table de chgt à venir en $5500
5023: bd f8 50   LDA $50F8,X         ; phase $22 ? (donc piste $11 ?) prise dans la table des phases
5026: 20 00 55   JSR $5500           ; chargement

5029: a9 08      LDA #$08            ; piste 4 ?
502b: 20 00 57   JSR $5700           ; remet le bras piste 4 ?
502e: bd 88 c0   LDA $C088,X         ; éteint le moteur également !
5031: 60         RTS                 ; << revient à l'appelant


Comme on peut le voir, il y a plusieurs appels en $5500 et c'est là que tout se passe :

Code:
;*********************************************************
; Chargement de la totalité de chaque "ROUND"
;*********************************************************             
5500: 48         PHA                 ; phase
5501: 84 88      STY $88             ; $88 == offset dans la table des adresses hautes de chgt
5503: 20 00 57   JSR $5700           ; SEEK - déplacement du bras
5506: a2 00      LDX #$00           
5508: a4 88      LDY $88             
550a: b9 00 54   LDA $5400,Y         ; remplit la table des 12 adresses hautes
550d: 9d 03 57   STA $5703,X         ; dans la routine de chargement
5510: c8         INY                 
5511: e8         INX                 
5512: e0 0c      CPX #$0C            ;
5514: 90 f4      BCC $550A           ;

5516: 20 30 55   JSR $5530           ; vers le chargement des 12 secteurs (1 piste)

5519: a5 88      LDA $88             ; offset de la table des adresse hautes de chgt
551b: 18         CLC                 
551c: 69 0c      ADC #$0C            ; plus douze
551e: a8         TAY                 
551f: b9 00 54   LDA $5400,Y         ; adresse haute suivante
5522: f0 07      BEQ $552B           ; si c'est zéro, on a fini ?
5524: 68         PLA                 ; piste récupérée
5525: 18         CLC                 
5526: 69 02      ADC #$02            ; phase +2
5528: d0 d6      BNE $5500           ; et on boucle tant qu'on n'a pas tout chargé (table complète)
552a: 00         BRK                 
552b: 68         PLA                 
552c: 60         RTS     


Comme on peut le voir, cette routine ne sait charger qu'une 'piste' complète à la fois (12 pseudo 'secteurs'). A chaque 'round', il charge 6 pistes complètes plus trois secteurs situés sur la piste $0A, c'est le pourquoi de cette table (un peu mieux commentée que précédemment) :

Code:
;*********************************************************     
; ces quatre tables (une par 'round') représentent des datas à charger pour chacun des rounds
; comme ils sont tous sur la même piste mais pas sur le même secteur
; le chargement utilise une sorte de masque qui permet de savoir quels secteurs charger sur cette piste
; l'adresse haute $5e00 en RAM est une 'adresse poubelle' qui joue comme 'chargement invalide ou inutile'
; on remarque que les secteurs 'utiles' sont toujours chargés à la même adresse.
; secteur : 00 01 02 03 04 05 06 07 08 09 0A 0B
; adresse : bb bc bd -- -- -- -- -- -- -- -- --     
             
5490: bb         ???                 ; adresses de chgt level 0 : caractéristiques de jeu
5491: bc bd 5e   LDY $5EBD,X         
5494: 5e 5e 5e   LSR $5E5E,X         
5497: 5e 5e 5e   LSR $5E5E,X         
549a: 5e 5e 00   LSR $005E,X         
549d: 00         BRK                 
549e: 00         BRK                 
549f: 00         BRK           

;*********************************************************   
; secteur : 00 01 02 03 04 05 06 07 08 09 0A 0B
; adresse : -- -- -- bb bc bd-- -- -- -- -- --
   
54a0: 5e 5e 5e   LSR $5E5E,X         ; adresses de chgt levels : caractéristiques de jeu
54a3: bb         ???                 
54a4: bc bd 5e   LDY $5EBD,X         
54a7: 5e 5e 5e   LSR $5E5E,X         
54aa: 5e 5e 00   LSR $005E,X         
54ad: 00         BRK                 
54ae: 00         BRK                 
54af: 00         BRK             

;*********************************************************
; secteur : 00 01 02 03 04 05 06 07 08 09 0A 0B
; adresse : -- -- -- -- -- -- bb bc bd -- -- --   

54b0: 5e 5e 5e   LSR $5E5E,X         ; adresses de chgt levels : caractéristiques de jeu
54b3: 5e 5e 5e   LSR $5E5E,X         
54b6: bb         ???                 
54b7: bc bd 5e   LDY $5EBD,X         
54ba: 5e 5e 00   LSR $005E,X         
54bd: 00         BRK                 
54be: 00         BRK                 
54bf: 00         BRK             

;*********************************************************
; secteur : 00 01 02 03 04 05 06 07 08 09 0A 0B
; adresse : -- -- -- -- -- -- -- -- -- bb bc bd
   
54c0: 5e 5e 5e   LSR $5E5E,X         ; adresses de chgt levels : caractéristiques de jeu
54c3: 5e 5e 5e   LSR $5E5E,X         
54c6: 5e 5e 5e   LSR $5E5E,X         
54c9: bb         ???                 
54ca: bc bd      ???
 
54cc: 00         BRK                 ; <<< fin de chargement.


Pour information, les datas spécifiques à chaque 'round' sont répartis comme suit :
round 0 : pistes $0B à $10 + 3 secteurs piste A
round 1 : pistes $11 à $16 + 3 secteurs piste A
round 2 : pistes $17 à $1C + 3 secteurs piste A
round 3 : pistes $1D à $22 + 3 secteurs piste A
... disposition tout à fait logique par ailleurs.

On peut en déduire que le jeu ne démarrait pas vraiment en $4000 comme je le croyais mais on pourrait situer le véritable démarrage à l'adresse $5C0C qui va lancer la boucle vers $5000 et qui reviendra toujours en $Be00 (qui est je le rappelle la routine rechargeant systématiquement tout ce qui est au dessus à chaque fin de 'round'.
En gros :
La partie $5xxx est en page HGR2 et sera détruite à chaque démarrage de partie, il est donc nécessaire de boucler sur un cycle :
- chargement du loader de level -> lancement du loader pour charger le level -> jeu qui détruit le loader -> fin du niveau -> chargement du loader de level -> etc...
C'est la routine en $BE00 qui est appelée par le jeu pour se charger de cela, car son espace mémoire n'est jamais écrasé.

On sait qu'on est un peu à l'étroit dans la routine de chargement principale ($BE00) mais il est possible d'utiliser la ROM du contrôleur disque pour charger (assez lentement) directement la nouvelle routine de chargement en $5500 en zappant la partie $5C00 qui me semble inutile (à creuser). Cette nouvelle routine de chargement dont la taille ne dépassera pas quelques secteurs serait alors assez rapide et efficace pour charger rapidos les 6 pistes de chaque level.

Ca vaut le coup de tenter l'affaire. Heureusement, demain c'est le W.E.
Very Happy
Revenir en haut de page
Voir le profil de l'utilisateur Envoyer un message privé
toinet
Site Admin


Inscrit le: 15 Juin 2007
Messages: 3077
Localisation: Le Chesnay, France

MessagePosté le: Sam 27 Fév 2021, 17:23    Sujet du message: Répondre en citant

Top, bientôt la fin !
Revenir en haut de page
Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web de l'utilisateur
aloysiuscoincoin



Inscrit le: 17 Mar 2018
Messages: 24

MessagePosté le: Lun 01 Mar 2021, 13:29    Sujet du message: Répondre en citant

Bientôt..... Rolling Eyes euh... ça prend un peu de temps quand même Mr. Green mais ça avance...
Revenir en haut de page
Voir le profil de l'utilisateur Envoyer un message privé
aloysiuscoincoin



Inscrit le: 17 Mar 2018
Messages: 24

MessagePosté le: Jeu 11 Mar 2021, 21:13    Sujet du message: Répondre en citant

Bonsoir à tous.
Je sais, ça traîne un peu cette histoire, mais c'est le printemps, la tondeuse est de sortie, tout ça... et trop de boulot.
Pour être honnête, il n'y a pas que le printemps... j'ai également eu quelques soucis avec ce crack tout simplement parce que je suis trop distrait ou trop vieux ou les deux et j'ai fait des erreurs (totalement) idiotes qui généraient des anomalies graphiques. C'est réglé et le crack fonctionne.

Voici le fichier image copiable au Locksmith 5.0 :
https://gofile.io/d/xOmrRA

Bien entendu, je n'ai pas la capacité de tester le jeu jusqu'à la fin, et même en ajoutant une tonne de vies, c'est beaucoup trop difficile pour moi alors j'ai bricolé une version (celle ci-dessus) dans laquelle le personnage du joueur est invincible.

Mr. Green

Franchement, même si depuis mon adolescence, j'ai toujours pensé que ce jeu était un pur bijou (pour un jeu sur apple II) en terme de design et de programmation (j'aime tout : jouabilité - sons mignons - graphismes mignons- et maintenant protection - tout quoi...) j'ai toujours été nullissime à ce jeu et j'ai rarement passé le level 3 alors il semble évident que je n'avais pas d'autre choix que la triche pour être en mesure de le tester.

Même invincible, j'ai abandonné à la fin du level 6 donc je n'ai pas encore fini la vérification... si quelqu'un a le courage de s'y mettre pour tester Wink



Le jeu fonctionne néanmoins et il n'y a aucune raison pour qu'il plante avant la fin... mais on ne sait jamais, autant tester par acquis de conscience.
OK... Pour le moment c'est moche lors du chargement car tout se passe dans la page HGR1 et ça nous fait un rideau tout cradingue, mais la version définitive sera propre. En effet, je pense que tout peut se reloger tranquillement à l'adresse $5800 et au delààààà (vers l'infini Wink )

Je mettrai les codes sources en ligne ainsi que la 'stratégie de remplacement des routines' et la structure des données sur la disquette crackée... une fois la version propre disponible, probablement ce W.E.

A bientôt !
Smile

Bon, j'ai la version définitive... ou plutôt les deux versions (une version 'normale' et une version 'invincible') :

https://www.mediafire.com/file/ns8uz7lm1q1ep2y/Drol_%255BK%255D_CCB2021_invincible.dsk/file
https://www.mediafire.com/file/vazv9x66vsj5nsr/Drol_%255BK%255D_CCB2021_normal.dsk/file

Après avoir fait un peu de mon mieux pour progresser dans le jeu aussi loin que possible, je pense qu'il n'y a tout simplement pas de fin Very Happy ... le truc super frustrant avec un jeu super difficile >_<"

C'est très "années 80" neverending story Wink


Ouaip... round 21 et ça continuait... c'est humainement impossible à atteindre donc je considère que le crack est 100% propre.
\o/ youpi !
A demain pour les morceaux d'assembleur 6502.
Revenir en haut de page
Voir le profil de l'utilisateur Envoyer un message privé
aloysiuscoincoin



Inscrit le: 17 Mar 2018
Messages: 24

MessagePosté le: Sam 13 Mar 2021, 16:38    Sujet du message: Répondre en citant

Salut à tous.
Nouveau post pour le séparer du précédent, il y a pas mal de texte sur celui-ci.
Les images disque des deux versions de Drol sont sur le post plus haut.

C'est parti, voici la structure des données sur le disque :

piste : $00 -----> Loader Fastboot piqué à Peter Ferrie sur Github pour aller plus vite
Chouette fastboot appelé qboot... efficace et bien tordu, mais incompatible avec microM8 :'(
https://github.com/peterferrie/qboot

piste : $03 + secteur 1 de la piste 4 -----> Drol - chargement préliminaire

C'est ce que charge le fastboot, il charge la piste 3 et le premier secteur de la piste 4 (ça ne sert à rien de charger tout ça, c'est simplement pour positionner la tête piste 4 car je garde le principe qui consiste à revenir piste 4 tout le temps pour charger le loader qui charge le loader qui charge le round.

Le premier fastboot charge donc la routine qui va remplacer ce qui existait à l'adresse $Be00.

En gros, voici la structure des données chargées à l'adresse $0200:

$0200-$05ff : données du jeu $0200-05ff intactes
$0600-$0800 : ma routine qui sera relogée en $be00 (chargeur de la piste 4 via le contrôleur de disquette)
$0800-$09ff : données du jeu de $0000 à $01ff (P.Z. + pile)
$0a00-$0aff : routine qui reloge tout ça et démarre via un JMP $BE0D

Bien entendu, le qboot est modifié pour nettoyer la page hgr1 et passer en mode HGR avant de charger la suite, ça permet un chargement 'propre' qui évite d'afficher le code chargé en page TEXT.

Voici la routine exécutée après le tout premier chargement :

Code:
.cr 6502 ; = choix du microprocesseur à assembler

      .or $0a00 ;
      .tf lancement_Drol.bin ,bin    ; target file (fichier assemblé)



prog_begin               ; début du prog

      sta $c0e9          ; on rallume le moteur pour la suite

;   copie de $0800 à $0a00 vers $0000   

copie1
      ldx #$00
l1      lda $0800,x
s1      .db $9d, $00, $00    ; sta $0000,x
      inx
      bne l1
      inc l1+2
      inc s1+2
      lda l1+2
      cmp #$0A
      bne l1

;   copie de $0600 à $0800 vers $bd00
copie2
l2      lda $0600,x
s2      .db $9d, $00, $BE    ; sta $BE00,x
      inx
      bne l2
      inc l2+2
      inc s2+2
      lda l2+2
      cmp #$08
      bne l2

      lda #$08         ; ne pas oublier de dire au soft que l'on est piste 4 après le chargement
      sta $bf48         ; phase actuelle pour la routine seek de Drol

modeHGR1
      sta $c050
      sta $c057
      sta $c052
      
registres
      lda #$3e
      ldx #$ff         ; rétablit le pointeur de pile
      txs            ; mais ça ne sert à rien, c'est trop tôt et redondant
      ldx #$60         ; pareil : trop tôt
      ldy #$00

gogogo
      jmp $BE0D   ; entrypoint Drol level 0
prog_end         ; fin du programme


Maintenant, le mini-loader de Drol modifié qui est déplacé en $Be00 par la routine plus haut :


Code:
      .cr 6502 ; = choix du microprocesseur à assembler

      .or $be00
      .tf BE00.bin ,bin    ;(fichier assemblé)



; constantes

temp        .eq $3c
sect      .eq $3d
track      .eq $41
slot      .eq $2b
bufLow      .eq $26
bufHigh      .eq $27
trick1      .eq $0800
trick2      .eq $0801

         LDX $bf49        ; slot
         LDA $C089,X         ; allume le moteur
         JSR $BF50           ; routine du jeu page HGR2

         INC $A0             
         INC $A1             ; ne sert à rien mais bon....
         
prog_begin                  ; début du prog


; d'abord, backup de $0000 à $0400 vers $5000 à cause de la table de conversion utilisée par le code de la carte contrôleur
; inutile de sauvegarder l'état de $0800 et $0801 même si on les écrase car le chargement suivant (initialisation du jeu) écrase la page $08
; par contre, la seconde routine de chargement devra remettre $0800 et $0801 à leur valeur initiale respective après chaque chargement de ROUND
; car aucun ROUND (de 0 à 3) n'écrase la page 08 et donc ne peut rétablir les valeurs en $0800 et $0801... :/

         ldx #$00
         ldy #$50         ; ---------------------------------------------------------
         sty w+2            ; initialise les adresses hautes de départ : $5000 et $0000
         sty r2+2         ;
         stx r+2            ;
         stx w2+2         ; ---------------------------------------------------------

         ldy #$04
r         .db $bd,$00,$00      ; LDA $0000,x
w         sta $5000,x
         INX
         bne r
         inc r+2
         inc w+2
         dey
         bne r


         lda #$08         ; on force la piste 4 dans la RAM, car c'est là qu'est la tête de lecture pour la routine de chargement à venir
         sta $bf48

;   construction de la table de translation pour la routine en ROM
createTable                     
          LDX #$03           
trans        STX temp             
          TXA                 
          ASL               
          BIT temp         
          BEQ suivant           
          ORA temp             
          EOR #$FF 
          AND #$7E         
shift       BCS suivant         
          LSR               
          BNE shift           
          TYA                 
          STA $0356,X         
          INY                 
suivant     INX               
          BPL trans     
         

; bidouillage en $0800 pour que la routine revienne ici
         lda #$07      ; on charge 7 secteurs via la carte contrôleur
         sta trick1
         lda $bf49      ; slot
         sta slot
         lsr
         lsr
         lsr
         lsr
         ora #$c0
         sta saut+2
         lda #$60      ; RTS à placer en $0801 pour que la routine de la carte contrôleur revienne
         sta trick2
         lda #$04
         sta track      ; piste 4 déjà en place via le fastboot précédent
         lda #$00
         sta sect       ; secteur 0
         sta bufLow
         lda #$48
         sta bufHigh      ; buffer = $4800
         lda #$00
         ldx slot
saut         jsr $FF5c      ; devient $c65c on lit les 7 secteurs en $5000

; rétablissement des données sauvegardées
         ldx #$00
         ldy #$04
r2         lda $5000,x
w2         .db $9d,$00,$00      ; STA $0000,x
         INX
         bne r2
         inc r2+2
         inc w2+2
         dey
         bne r2

         ;lda b800
         ;sta $0800
ici         jmp retourAuJeu      ; saut à la suite du chargement avec ma routine


alignement   .db $00,$00,$00,$00,$00,$00,$00
      
retourAuJeu   JSR $4800         ; au lieu de $5c00 originellement

;====================================================================================================
; ICI, c'est le code du jeu recopié, tout simplement : il est aligné et les adresses sont conservées
; CE QUI EST DESSOUS DOIT ETRE ASSEMBLE A L'ADRESSE $BEA3 !
;====================================================================================================
         JSR $BF7F           ; deuxième routine de déplacement en HGR2
         LDX #$21           
         LDA $7380,X         ; vide une partie de la mémoire (valeur : 00)
         STA $A0             
         LDA $7440,X         
         STA $A1             
         LDY #$27           
         LDA #$00           
         STA ($A0),Y         
         DEY                 
         BPL $BEB6           
         INX                 
         CPX #$BC           
         BCC $BEA8   
         LDA #$00           
         LDY #$40           
         STA $A0             
         STY $A1             
         LDX #$20           
         LDY #$78           
         STA ($A0),Y         
         INY                 
         BPL $BECC           
         LDY #$F8           
         STA ($A0),Y         
         INY                 
         BMI $BED3           
         INC $A1             
         DEX                 
         BNE $BECA           
         RTS              ; Ce RTS saute en $450 (cf.la pile à l'adresse $1d5)
         .db $80,$83       

         LDA $C081           
         LDA $C081           ; carte langage
         LDY #$00           
         LDA #$D0           
         STY $A0             
         STA $A1             
         LDA ($A0),Y         
         STA ($A0),Y         
         INY                 
         BNE $BEEE           
         INC $A1             
         BNE $BEEE           
         BIT $C080           ; recopie de la carte langage sur elle-même
         RTS                 

         JMP $1255   

prog_end         ; fin du programme



Le saut vers le 'vrai' chargement se fait vers l'adresse $4800. Cette adresse permet de loger la routine dans un espace mémoire qui ne compromet pas le bon fonctionnement du jeu... on peut le comprendre en regardant les adresses hautes de chargement de la phase d'initialisation et de la phase 'round 0-1-2-3' dans le code ci-dessous :

En toute logique, le début de la routine est un copié/collé de celle de Drol qui fait le tri entre les types de chargement à effectuer, et j'ai gardé la routine de déplacement du bras originale, pas de raison de la changer.
Le chargement qui était originellement fait en 2 parties (1/4 de piste avec masque + plusieurs pistes complètes) est fait en une fois dans la routine 16 secteurs 'normaux' ci-dessous j'ai regroupé les secteurs spécifiques à chaque 'round'.


Code:
            .cr 6502 ; = choix du microprocesseur à assembler

            .or $4800 ; code assemblé à l'adresse $4800
            .tf ChargeurDrolComplet_4800.bin ,bin    ; target file (fichier assemblé)

slot         .eq $BF49
cpteur          .eq $a0
temp1         .eq $a2
temp2         .eq $a3
adrChgtHte      .eq $A5
adrChBasse      .eq $A4


            LDX $BF4A           
            BPL chgtlevel       ; c'est un 'round'
            JMP premierchgt     ; entrypoint de la phase 6 : cette partie n'est chargée qu'une seule fois, elle initialise le jeu.

chgtlevel         INX                   ; C'est le level courant
            TXA                 
            AND #$03            ; le 'level' à charger ne peut être que de zéro à 3, ce sont les 4 'rounds' cycliques
            TAX                 
            BIT $44               ; test l'état du jeu (mort / pas mort) et donc si on revient au level 0
            BMI pasMort         ; Le flag minus est triggered si le joueur est mort, sinon on ne recharge pas le Level 00

            LDX #$00            ; remise à zéro du n° de level (après la mort ?)

pasMort            STX $BF4A           ; n° de level à charger incrémenté
            LDA tablePiste,X    ; piste de départ x 2
            LDY #$05       ; 05 == nb de pistes
            JSR chargement      ; on charge tout (72 + 3 secteurs == 5 pistes)

            LDA #$08            ; piste 4
            JSR SEEK            ; remet le bras piste 4
         
            LDA #$FE       ; il faut restaurer les adresse $0800 et $0801 car le précédent loader a mis le bazar (loader via $c65c)
            STA $0800
            LDA #$9d
            STA $0801

            STA $c0E8            ; éteint le moteur

            RTS                ; << revient à l'appelant



premierchgt
            ; on charge la partie à charger une seule fois
            LDA #$0C          ; phase de départ (== piste 6) x 2
            LDY #$04      ; 04 == nb de pistes
            JSR chargement      ; on charge tout (60 secteurs == 4 pistes)

            ; ensuite on charge le ROUND 0
            LDX #$00       ; la première fois, on charge le level 0
            LDA tablePiste,X    ; piste de départ x 2
            LDY #$05       ; 05 == nb de pistes
            JSR chargement      ; on charge tout (72 + 3 secteurs == 5 pistes)

            LDA #$08            ; piste 4
            JSR SEEK            ; remet le bras piste 4
            LDA $C0E8       ; éteint le moteur

            ; on déplace la partie $5000 à $5fff vers $0000 avant démarrage
copieSnapshot
            ldx #$00
            STX $BF4A         ; c'est pour signifier au jeu que c'est bon, il est chargé : on ne chargera plus que des 'rounds'
csl1            lda $5000,x
css1            .db $9d, $00, $00       ; sta $0000,x
            inx
            bne csl1
            inc csl1+2
            inc css1+2
            lda csl1+2
            cmp #$56         ; jusqu'à $5FFF
            bne csl1

            ; à partir d'ici on rétablit les conditions de départ du jeu original
            LDX #$FF
            TXS               ; hop la pile
            LDX #$60
            lda #$15
            LDY #$00
            JMP debutjeu        ; on saute à l'exécution du début du jeu

;*********************************************************
; déplacement du bras - SEEK
;*********************************************************     
SEEK     
              STA $A6             ; phase voulue
              CMP $BF48           ; on est déjà au bon endroit ?
              BEQ quitte          ; oui, on sort sans rien faire

              LDA #$00           
              STA $A7             ; $A7 = steps
l3                  LDA $BF48           
             STA $A8             ; $A8 = phase en cours
             SEC                 
             SBC $A6             
             BEQ l9           
             BCS l8           
             EOR #$FF           
             INC $BF48           
             BCC l7           
l8              ADC #$FE           
              DEC $BF48           
l7                  CMP $A7             
              BCC l6           
              LDA $A7             
l6                  CMP #$0C           
              BCS l5           
              TAY                 
l5                  SEC                 
              JSR l4           
              LDA tablePH,Y         
              JSR wait           
              LDA $A8             
              CLC                 
              JSR l2           
              LDA tablePH2,Y         
              JSR wait           
              INC $A7             
              BNE l3           
l9               JSR wait           
              CLC                 
l4                  LDA $BF48           
l2              AND #$03           
              ROL A               
              ORA $BF49           
              TAX                 
              LDA $C080,X         ; déplacement
              LDX $BF49           
quitte                   RTS                 

wait                   LDX #$13           
l1              DEX                 
              BNE l1           
              SEC                 
              SBC #$01           
              BNE wait           
              RTS     
;*********************************************************


chargement                     ; Y = nb de pistes à charger et A = phase de la piste de départ
            STA phase
            STY nbPistes
            TYA             ; A == Y
            AND #$01         ; fait le tri entre chargement de ROUND et chargement de PHASE6
            BNE loadRound         ; 5 tracks = charger ROUND

                        ; sinon c'est qu'on charge la phase d'initialisation
loadInit
            LDA #tableInit        ; adresse basse de la table INIT
            STA load16Index+1       ; code de load16 automodifié - on charge une piste complète à la fois, comme les fastboots à l'ancienne
            STA l04+1
            STA l03+1
            LDA /tableInit        ; adresse haute de la table INIT
            STA load16Index+2       ; idem avec l'adresse haute
            STA l04+2
            STA l03+2
            JMP boucle

;*********************************************************

loadRound      
            LDA #tableRound        ; adresse basse de la table ROUND
            STA load16Index+1       ; code de load16 automodifié
            STA l04+1
            STA l03+1
            LDA /tableRound        ; adresse haute de la table ROUND
            STA load16Index+2       ; idem avec l'adresse haute
            STA l04+2
            STA l03+2

boucle            LDY nbPistes
            CPY #$00         ; il reste 0 pistes ?
            BNE continue         ; on continue ?
            JMP stop          ; non, c'est chargé
continue
            LDA phase
            JSR SEEK         ; on déplace la tête au début de la piste qui correspond.

            JSR load16         ; on charge les 16 secteurs grâce au code automodifié qui pointe vers la table et à l'index
                        ; dans cette table

            INC phase          ; on avance d'une piste
            INC phase

            CLC
            LDA load16Index+1      ; on ajoute 16 à l'adresse à partir de laquelle on lit les adresses hautes dans lesquelle charger les secteurs lus
            ADC #$10         ; à chaque piste chargée, on avance de 16 secteurs, évidemment
            STA load16Index+1
            STA l04+1
            STA l03+1
            DEC nbPistes         ; une piste en moins
            JMP boucle

stop            RTS

err            SEC                       ; retour avec erreur, mais ça ne sert à rien, le code ne vérifie pas les erreurs, trop fainéant
            RTS

;************************************************************************
;************************************************************************
; CHARGEMENT D'UN SECTEUR
;************************************************************************
;************************************************************************

loadSect         
             LDA #$00                     ; adresse basse de chargement
             LDY adrChgtHte             
             STA store+1           
             STY store+2           
             SEC                 
             SBC #$54           
             BCS ls01           
             DEY                 
             SEC                 
ls01               STA store2+1           
              STY store2+2           
              SBC #$57           
              BCS ls02           
              DEY                 
ls02                STA store3+1           
              STY store3+2           
              LDY #$20           
ls04               DEY                 
               BEQ err           
ls03               LDA $C0EC           
               BPL ls03           
ls06               EOR #$D5                     ; début champ données
              BNE ls04           
              NOP                 
ls05              LDA $C0EC           
              BPL ls05           
              CMP #$AA           
              BNE ls06           
              NOP                 
ls07               LDA $C0EC           
              BPL ls07           
              CMP #$AD           
              BNE ls06                    
             
              LDY #$AA                     
              LDA #$00           
ls09               STA temp1             
ls08               LDX $C0EC           
              BPL ls08           
              LDA transTable2-$96,X              
              STA buffDenib,Y                 
              EOR temp1             
              INY                 
              BNE ls09                 
              LDY #$AA                  
              BNE ls10           
store3               STA $FF55,Y                  
ls10               LDX $C0EC           
              BPL ls10           
              EOR transTable2-$96,X         
              LDX buffDenib,Y         
              EOR transTable-$96,X         
              INY                 
              BNE store3 

              PHA                 
              AND #$FC           
              LDY #$AA           
ls11               LDX $C0EC           
              BPL ls11           
              EOR transTable2-$96,X      
              LDX buffDenib,Y         
              EOR transTable-$95,X           
store2               STA $FFAC,Y                  
             INY                 
             BNE ls11           
ls12               LDX $C0EC           
              BPL ls12           
              AND #$FC           
              LDY #$AC           
ls14               EOR transTable2-$96,X       
              LDX buffDenib-2,Y            
              EOR transTable-$94,X         
store               STA $FF00,Y               ; adresse de destination
ls13               LDX $C0EC           
              BPL ls13           
              INY                 
              BNE ls14           
              AND #$FC           
              EOR transTable2-$96,X
              LDX slot             
              TAY                 
              BNE err2           
ls15               LDA $C0EC           
              BPL ls15           
              CMP #$DE           
              BEQ good           
err2               SEC              ; erreur             
               .db $24         ; simule l'instruction BIT pour passer le CLC en dessous
good               CLC           
              PLA             

              LDY #$55           
              STA (adrChBasse),Y            ; adresse de chgt après décryptage = $44 + $45
              RTS 

err3                  SEC                       ; erreur
                  RTS

step             .db $02
youpi              .db $00                       




;************************************************************************
;************************************************************************
; Lecture Champ d'adresse
;************************************************************************
;************************************************************************
rdAddrField        
             LDY #$FC           
              STY temp1             
a02               INY                 
             BNE a01           
             INC temp1             
             BEQ err3           
a01               LDA $C0EC           
              BPL a01           
a04               CMP #$D5           
             BNE a02           
             NOP                 
a03               LDA $C0EC           
              BPL a03           
              CMP #$AA           
              BNE a04           
              LDY #$03           
a10              LDA $C0EC           
              BPL a10           
              CMP #$96            ; prologue champ adresse
              BNE a04           
              LDA #$00           
a07               STA temp2             
a05               LDA $C0EC           
             BPL a05           
             ROL               
             STA temp1             
a06               LDA $C0EC           
              BPL a06           
              AND temp1             
              STA infos,Y         ; volume, piste, secteur
              EOR temp2             
              DEY                 
              BPL a07           
              TAY                 
              BNE err3           

a08               LDA $C0EC           
             BPL a08           
             CMP #$DE            ; fin de champ d'adresse
             BNE err3            ; erreur si pas trouvé
             NOP                 
a09               LDA $C0EC           
              BPL a09           
              CMP #$AA            ; double check au cas où
              BNE err3            ; erreur
              CLC                 ; pas d'erreur
              RTS                 







espace            .db       $00,$00,$00,$00,$00,$00,$00

; on peut voir dans les tables ci-dessous que l'espace mémoire situé après $4800 et jusqu'à $5000 n'est pas touché par ces chargements et que l'on dispose de l'espace pour y coller cette routine.
 
; table des adresses hautes (4 pistes) à remplir une seule fois au tout premier chargement

tableInit         .db      $5c,$5d,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0f,$10,$11
            .db      $12,$19,$1a,$1b,$1c,$1d,$1e,$1f,$40,$41,$42,$43,$44,$45,$46,$47
            .db      $60,$61,$62,$63,$64,$65,$66,$73,$74,$7b,$7c,$7d,$7e,$7f,$80,$81
            .db      $82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$50,$51,$52,$53,$54,$55      ; on ajoute de $5000 à $55ff pour avoir le vrai snapshot mémoire
                                             ; de l'état du jeu avant démarrage



; table des adresses hautes (5 pistes) à remplir à chaque 'ROUND'
tableRound      .db       $02,$13,$14,$15,$16,$17,$18,$67,$68,$69,$6a,$6b,$6c,$6d,$6e,$6f
            .db       $70,$71,$72,$75,$76,$77,$78,$79,$7a,$8c,$8d,$8e,$8f,$90,$91,$92
            .db       $93,$94,$95,$96,$97,$98,$99,$9a,$9b,$9c,$9d,$9e,$9f,$a0,$a1,$a2
            .db       $a3,$a4,$a5,$a6,$a7,$a8,$a9,$aa,$ab,$ac,$ad,$ae,$af,$b0,$b1,$b2
            .db       $b3,$b4,$b5,$b6,$b7,$b8,$b9,$ba,$bb,$bc,$bd,$bd,$bd,$bd,$bd,$bd      ; le dernier secteur est dupliqué plusieurs fois idem


;interlace              .db    $00,$07,$0e,$06,$0d,$05,$0c,$04,$0b,$03,$0a,$02,$09,$01,$08,$0f

;align1         .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00


;=====================================================================================================================
   

transTable2
             .db   $00,$04,$98,$99,$08,$0c,$9c,$10
             .db   $14,$18,$a0,$a1,$a2,$a3,$a4,$a5            
             .db   $1c,$20,$a8,$a9,$aa,$24,$28,$2c                         
             .db   $30,$34,$b0,$b1,$38,$3c,$40,$44            
             .db   $48,$4c,$b8,$50,$54,$58,$5c,$60
             .db   $64,$68,$c0,$c1,$c2,$c3,$c4,$c5
             .db   $c6,$c7,$c8,$c9,$ca,$6c,$cc,$70            
             .db   $74,$78,$d0,$d1,$d2,$7c,$d4,$d5            
             .db   $80,$84,$d8,$88,$8c,$90,$94,$98            
             .db   $9c,$a0,$e0,$e1,$e2,$e3,$e4,$a4            
             .db   $a8,$ac,$e8,$b0,$b4,$b8,$bc,$c0            
             .db   $c4,$c8,$f0,$f1,$cc,$d0,$d4,$d8            
             .db   $dc,$e0,$f8,$e4,$e8,$ec,$f0,$f4            
             .db   $f8,$fc,$00,$00,$00,$96,$02,$00            
             .db   $00,$97,$01,$00,$00,$9a,$03,$00            
             .db   $00,$9b,$00,$02,$00,$9d,$02,$02            
             .db   $00,$9e,$01,$02,$00,$9f,$03,$02            
             .db   $00,$a6,$00,$01,$00,$a7,$02,$01            
             .db   $00,$ab,$01,$01,$00,$ac,$03,$01            
             .db   $00,$ad,$00,$03,$00,$ae,$02,$03            
             .db   $00,$af,$01,$03,$00,$b2,$03,$03            
             .db   $00,$b3,$00,$00,$02,$b4,$02,$00            
             .db   $02,$b5,$01,$00,$02,$b6,$03,$00            
             .db   $02,$b7,$00,$02,$02,$b9,$02,$02            
             .db   $02,$ba,$01,$02,$02,$bb,$03,$02            
             .db   $02,$bc,$00,$01,$02,$bd,$02,$01            
             .db   $02,$be,$01,$01,$02,$bf,$03,$01            
             .db   $02,$cb,$00,$03,$02,$cd,$02,$03            
             .db   $02,$ce,$01,$03,$02,$cf,$03,$03            
             .db   $02,$d3,$00,$00,$01,$d6,$02,$00            
             .db   $01,$d7,$01,$00,$01,$d9,$03,$00
             .db   $01,$da,$00,$02,$01,$db,$02,$02

transTable
             .db    $01,$dc,$01,$02,$01,$dd,$03,$02
             .db    $01,$de,$00,$01,$01,$df,$02,$01
             .db    $01,$e5,$01,$01,$01,$e6,$03,$01
             .db    $01,$e7,$00,$03,$01,$e9,$02,$03
             .db    $01,$ea,$01,$03,$01,$eb,$03,$03         
             .db    $01,$ec,$00,$00,$03,$ed,$02,$00            
             .db    $03,$ee,$01,$00,$03,$ef,$03,$00            
             .db    $03,$f2,$00,$02,$03,$f3,$02,$02            
             .db    $03,$f4,$01,$02,$03,$f5,$03,$02
             .db    $03,$f6,$00,$01,$03,$f7,$02,$01            
             .db    $03,$f9,$01,$01,$03,$fa,$03,$01            
             .db    $03,$fb,$00,$03,$03,$fc,$02,$03
             .db    $03,$fd,$01,$03,$03,$fe,$03,$03
             .db    $03,$ff


;************************************************************************
;************************************************************************
; LOAD16 - chargement d'une piste complète
;************************************************************************
;************************************************************************

load16   

             LDX slot            ; slot
             LDA #$60           
             STA cpteur             

l02                DEC cpteur             
             BEQ quit           

             JSR rdAddrField     ; lecture champ d'adresse
             BCS l02             ; si erreur
             LDY secteur         ; secteur
load16Index       LDA $FFFF,Y        ; table des adresses de chgt avec secteur en index qui est auto-modifiée précédemment
             BEQ l02             ; si déjà chargé, on sort
             STA adrChgtHte     
             LDA #$00           
             STA adrChBasse     

             JSR loadSect        ; charge secteur

             BCS l02             ; si erreur, compteur d'erreurs
             LDY secteur         ; secteur
             LDA #$00            ; 00
l04             STA $FFFF,Y         ; on passe l'adresse de chgt à 0 car déjà lu
             LDY #$0F            ; dernière adresse de chgt

l03                LDA $FFFF,Y         ; == 0 ?
             BNE l02        ; non, alors on n'a pas lu toute la piste
             DEY                 ; secteur suivant
             BPL l03             ; on n'a pas fini la piste donc go ?
             RTS                 

quit             INC youpi           ; inutile maintenant
              RTS     





align2         .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00

buffDenib         .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
            .db    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00

;-----------------------------------------------------------------------------------------------

index            .db    $00
phase            .db    $00
nbPistes         .db    $00

tablePH          .db   $01,$30,$28,$24,$20,$1e,$1d,$1c,$1c,$1c,$1c,$1c

tablePH2          .db     $70,$2c,$26,$22,$1f,$1e,$1d,$1c,$1c,$1c,$1c,$1c
            
tablePiste         .db    $14,$1e,$28,$32                  ; emplacement des pistes des rounds 0, 1, 2 et 3

                                    ; datas lus à partir du champ d'adresse
infos            .db     $00                     
secteur            .db     $00
            .db     $00                     ; piste champ d'adresse
            .db     $00                     ; volume champ d'adresse



;-----------------------------------------------------------------------------------------------
; ci-dessous, le début du jeu est recopié pour le lancer comme le fait le 'Drol' original
;-----------------------------------------------------------------------------------------------
 
debutjeu      
            JSR $4000                       ; dessine le bas et le haut de l'écran HGR1
                     
             LDA #$00                        ; initialisations
             STA $03F8 
             STA $03FF 
             LDA #$43   
             STA $03F9 
             LDA #$6B   
             STA $03FA 
             LDA #$93   
             STA $03FB 
             LDA #$BB   
             STA $03FC 
             LDA $C070 
             LDX #$04   
             LDY #$00 

dj2             LDA $C064                          ; manettes
             ORA $C065 
             BPL dj1 
             DEY       
             BNE dj2 
             DEX       
             BNE dj2 
             LDA #$19   
             STA $52   
             STA $54   
             LDA #$62   
             STA $53   
             STA $55   
             BNE dj3 
             BRK   

dj1             LDA #$61   
             STA $52   
             LDA #$62   
             STA $54   
             LDA #$C0   
             STA $53   
             STA $55 

dj3             LDA #$08   
             STA $72BA 
             LDA $FBB4 
             CMP #$08   
             BNE run 
             LDA #$CB   
             STA $6022 
             LDA #$CC   
             STA $600E

run             JMP ($004E)                        ; le jeu démarre pour de bon


Ah oui, j'oubliais : pour devenir invincible, il suffit de rechercher sur le disque toutes les occurences de : a9 ff 85 1e (LDA #$FF - STA $1E) et les remplacer par : a9 01 85 1e (01 à la place de FF quoi...). C'est disséminé à plusieurs endroits sur le disque car ça se trouve à des adresses mémoire différentes en fonction du 'ROUND' dans lequel on se trouve en cours de jeu.

Voilà, c'est fini pour Drol et c'était bien rigolo ! Etant gamin, je n'imaginais pas le boulot que les crackers avaient fait sur ce jeu tandis que je tentais péniblement d'atteindre le level 2 comme un gros looser... eheh ça fait plaisir de le savoir 38 ans plus tard ^^'

Merci le format .woz, applesauce et ses concepteurs, les rippeurs qui sauvegardent ces précieuses protections et bien sûr kboohk et son génial wDrive. Sans vous je n'aurais pas pû m'éclater avec cette sympathique protection.

Very Happy

a+
Revenir en haut de page
Voir le profil de l'utilisateur Envoyer un message privé
toinet
Site Admin


Inscrit le: 15 Juin 2007
Messages: 3077
Localisation: Le Chesnay, France

MessagePosté le: Sam 13 Mar 2021, 17:41    Sujet du message: Répondre en citant

Top ! Bravo ! Super crack, merci.
Ton image des niveaux 6 et 21, euh, ben, ça me fait réaliser que je n'ai jamais dû dépasser le niveau 1 Smile

Well done,
antoine
Revenir en haut de page
Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web de l'utilisateur
Montrer les messages depuis:   
Poster un nouveau sujet   Répondre au sujet     Index du Forum -> PROTECTION MALEFIQUE Toutes les heures sont au format GMT + 1 Heure
Page 1 sur 1

 
Sauter vers:  
Vous ne pouvez pas poster de nouveaux sujets dans ce forum
Vous ne pouvez pas répondre aux sujets dans ce forum
Vous ne pouvez pas éditer vos messages dans ce forum
Vous ne pouvez pas supprimer vos messages dans ce forum
Vous ne pouvez pas voter dans les sondages de ce forum


Powered by phpBB © 2001, 2005 phpBB Group
Traduction par : phpBB-fr.com