|
|
IDENTIFICATION SERVEUR : 10.14.20.84 - CLIENT : 3.235.108.188 |
|
Voir le sujet précédent :: Voir le sujet suivant |
Auteur |
Message |
aloysiuscoincoin
Inscrit le: 17 Mar 2018 Messages: 21
|
Posté le: Jeu 18 Fév 2021, 20:17 Sujet du message: Drol (Broderbund - 1983) |
|
|
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 . 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.
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.
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.
 |
|
Revenir en haut de page |
|
 |
toinet Site Admin
Inscrit le: 15 Juin 2007 Messages: 3074 Localisation: Le Chesnay, France
|
Posté le: Ven 19 Fév 2021, 17:07 Sujet du message: |
|
|
On veut la suite !
C'est une protection de Roland Gustaffson. Toujours long et sciant à suivre, à la mode Karateka... |
|
Revenir en haut de page |
|
 |
aloysiuscoincoin
Inscrit le: 17 Mar 2018 Messages: 21
|
Posté le: Dim 21 Fév 2021, 11:06 Sujet du message: |
|
|
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.
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
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 |
|
 |
aloysiuscoincoin
Inscrit le: 17 Mar 2018 Messages: 21
|
Posté le: Dim 21 Fév 2021, 11:41 Sujet du message: |
|
|
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
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  |
|
Revenir en haut de page |
|
 |
amauget
Inscrit le: 06 Déc 2009 Messages: 968 Localisation: Nantes
|
Posté le: Dim 21 Fév 2021, 15:01 Sujet du message: |
|
|
Impressionnant ! _________________ Antony
Apple II forever |
|
Revenir en haut de page |
|
 |
aloysiuscoincoin
Inscrit le: 17 Mar 2018 Messages: 21
|
Posté le: Dim 21 Fév 2021, 18:21 Sujet du message: |
|
|
Ouaip, le type qui a pondu ce schéma n'était probablement pas un néophyte
Sacré foufou ce Roland...
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é  |
|
Revenir en haut de page |
|
 |
toinet Site Admin
Inscrit le: 15 Juin 2007 Messages: 3074 Localisation: Le Chesnay, France
|
Posté le: Dim 21 Fév 2021, 21:09 Sujet du message: |
|
|
Well (temporary) done!
av |
|
Revenir en haut de page |
|
 |
aloysiuscoincoin
Inscrit le: 17 Mar 2018 Messages: 21
|
Posté le: Ven 26 Fév 2021, 20:52 Sujet du message: |
|
|
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 ) 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.
 |
|
Revenir en haut de page |
|
 |
toinet Site Admin
Inscrit le: 15 Juin 2007 Messages: 3074 Localisation: Le Chesnay, France
|
Posté le: Sam 27 Fév 2021, 17:23 Sujet du message: |
|
|
Top, bientôt la fin ! |
|
Revenir en haut de page |
|
 |
aloysiuscoincoin
Inscrit le: 17 Mar 2018 Messages: 21
|
Posté le: Lun 01 Mar 2021, 13:29 Sujet du message: |
|
|
Bientôt..... euh... ça prend un peu de temps quand même mais ça avance... |
|
Revenir en haut de page |
|
 |
|
|
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
|
|