Au hasard des multiples tests d'images disque effectués dernièrement, je suis tombé sur le crack de Championship Wrestling signé Apple Chemical Software (ACS). Et intégré au détour des (nombreux) écrans de présentations ajoutés par le groupe, apparaît un petit défi concocté par Deny et The Gog's, défi consistant en une classique signature d'image. Classique ? Pas tant que ça car ACS nous a réservé quelques petites surprises rendant le défi particulièrement intéressant. À noter qu'à l'époque circulait aussi une version du jeu crackée et signée par un certain Godfather (mais sans défi cette fois)...

 

Allez, on attaque par la première phase qui est, comme d'habitude, une phase d'observation de ce qui se passe depuis le boot du disque jusqu'au moment où l'on arrive enfin sur le défi. Je dis "enfin" car effectivement, ce ne sont pas moins de trois écrans Hires (voire Double Hires) qui se succèdent avant l'apparition de l'image du défi (voir ci-contre). On comprend vite qu'il va falloir s'enfoncer relativement loin dans la séquence de boot avant de tomber sur la (ou les) routine(s) recherchée(s).

 

Ce petit jeu de piste, nous menant jusqu'à la localisation (et le code) de la routine de décryptage, fera l'objet de cette première partie, la seconde consistant en la résolution concrète du défi en lui-même. Comme vous allez le voir, cela va être assez longuet mais je vous rassure tout de suite, cela a été aussi laborieux pour moi à écrire que cela sera fastidieux pour vous à lire !

On commence par décortiquer la séquence du Boot 1. On peut l'obtenir en Boot Traçant ou tout simplement en allant checker ce qui se passe avec un éditeur de secteur Piste$00/Secteur$00 (option désassemblage).

0800-   01 ; un seul secteur chargé
 
0801-   E0 60       CPX   #$60    ; boot depuis le slot 6 ?
0803-   F0 03       BEQ   $0808   ; oui alors suite...
0805-   4C EB 08    JMP   $08EB   ; non ? alors message !
0808-   A9 B6       LDA   #$B6
080A-   85 27       STA   $27
080C-   BD 8C C0    LDA   $C08C,X ; $C080
080F-   10 FB       BPL   $080C
0811-   49 D5       EOR   #$D5
0813-   D0 F7       BNE   $080C
0815-   BD 8C C0    LDA   $C08C,X ; $C080
0818-   10 FB       BPL   $0815
081A-   C9 AA       CMP   #$AA
081C-   D0 F3       BNE   $0811
081E-   BD 8C C0    LDA   $C08C,X ; $C080
0821-   10 FB       BPL   $081E
0823-   C9 AD       CMP   #$AD
0825-   D0 EA       BNE   $0811
0827-   A9 00       LDA   #$00
0829-   A0 56       LDY   #$56
082B-   84 3C       STY   $3C
082D-   BC 8C C0    LDY   $C08C,X ; $C080
0830-   10 FB       BPL   $082D
0832-   59 D6 02    EOR   $02D6,Y
0835-   A4 3C       LDY   $3C
0837-   88          DEY
0838-   99 00 03    STA   $0300,Y
083B-   D0 EE       BNE   $082B
083D-   84 3C       STY   $3C
083F-   BC 8C C0    LDY   $C08C,X ; $C080
0842-   10 FB       BPL   $083F
0844-   59 D6 02    EOR   $02D6,Y
0847-   A4 3C       LDY   $3C
0849-   91 26       STA   ($26),Y
084B-   C8          INY
084C-   D0 EF       BNE   $083D
084E-   BC 8C C0    LDY   $C08C,X ; $C080
0851-   10 FB       BPL   $084E
0853-   59 D6 02    EOR   $02D6,Y
0856-   D0 48       BNE   $08A0
0858-   A0 00       LDY   #$00
085A-   A2 56       LDX   #$56
085C-   CA          DEX
085D-   30 FB       BMI   $085A
085F-   B1 26       LDA   ($26),Y
0861-   5E 00 03    LSR   $0300,X
0864-   2A          ROL
0865-   5E 00 03    LSR   $0300,X
0868-   2A          ROL
0869-   45 2B       EOR   $2B     ; EOR #$60
086B-   91 26       STA   ($26),Y
086D-   C8          INY
086E-   D0 EC       BNE   $085C
0870-   E6 27       INC   $27
0872-   A2 60       LDX   #$60
0874-   CE F5 08    DEC   $08F5   ; nb secteurs à lire
0877-   D0 93       BNE   $080C
0879-   20 58 FC    JSR   $FC58
087C-   A0 0C       LDY   #$0C
087E-   B9 A5 08    LDA   $08A5,Y ; message "ACS-DOS"
0881-   49 12       EOR   #$12    ; codé bien entendu...
0883-   20 ED FD    JSR   $FDED
0886-   88          DEY
0887-   10 F5       BPL   $087E
0889-   20 8F 08    JSR   $088F
088C-   4C 00 B6    JMP   $B600   ; JMP BOOT2
088F-   A9 00       LDA   #$00
0891-   8D F2 03    STA   $03F2
0894-   A9 C6       LDA   #$C6
0896-   8D F3 03    STA   $03F3
0899-   49 A5       EOR   #$A5
089B-   8D F4 03    STA   $03F4
089E-   A9 20       LDA   #$20
08A0-   85 E6       STA   $E6
08A2-   4C B2 08    JMP   $08B2
08A5-   B2          ???
08A6-   32          ???
08A7-   32          ???
08A8-   01 1D       ORA   ($1D,X)
08AA-   16 3F       ASL   $3F,X
08AC-   01 11       ORA   ($11,X)
08AE-   13          ???
08AF-   32          ???
08B0-   32          ???
08B1-   B2          ???
08B2-   20 F2 F3    JSR   $F3F2
08B5-   A0 94       LDY   #$94
08B7-   B9 00 04    LDA   $0400,Y
08BA-   4D B6 08    EOR   $08B6
08BD-   8D B6 08    STA   $08B6
08C0-   88          DEY
08C1-   D0 F4       BNE   $08B7
08C3-   C9 94       CMP   #$94
08C5-   D0 01       BNE   $08C8
08C7-   60          RTS
08C8-   6C F2 03    JMP   ($03F2)
08CB-   A0 C1       LDY   #$C1
08CD-   C3          ???
08CE-   D3          ???
08CF-   AD C4 CF    LDA   $CFC4
08D2-   D3          ???
08D3-   A0 CD       LDY   #$CD
08D5-   D5 D3       CMP   $D3,X
08D7-   D4          ???
08D8-   A0 C2       LDY   #$C2
08DA-   CF          ???
08DB-   CF          ???
08DC-   D4          ???
08DD-   A0 C6       LDY   #$C6
08DF-   D2          ???
08E0-   CF          ???
08E1-   CD A0 D3    CMP   $D3A0
08E4-   CC CF D4    CPY   $D4CF
08E7-   A0 B6       LDY   #$B6
08E9-   A0 A1       LDY   #$A1
08EB-   20 2F FB    JSR   $FB2F   ; INIT
08EE-   20 58 FC    JSR   $FC58   ; HOME
08F1-   A0 00       LDY   #$00
08F3-   B9 CB 08    LDA   $08CB,Y ; blabla...
08F6-   99 04 04    STA   $0404,Y ; ...boot slot 6 only!
08F9-   C8          INY
08FA-   C0 20       CPY   #$20
08FC-   D0 F5       BNE   $08F3
08FE-   F0 FE       BEQ   $08FE

Première remarque : l'utilisation originelle du softswitch $C080 (en lieu et place de $C08C) pour lire le latch empêche purement et simplement l'image disque de booter sous émulateur (notamment AppleWin). C'était une pratique relativement courante à l'époque que l'on retrouvera notamment sur certains Déplombage Mode d'Emploi. À signaler aussi l'emploi d'un EOR $2B (qui contient normalement #$60 dû au Slot 6) après dénibblelisation, et ce, juste avant de sauver l'octet final. C'était une façon assez classieuse de cacher sur disque ce qui se passe au boot et qu'on retrouvera là encore deci delà sur certaines productions Underground. Ceci ne concerne toutefois que le chargement du Boot 2. Une fois celui-ci chargé, l'EOR #$60 n'a plus lieu d'être et on ne le retrouve pas dans la RWTS. Le Boot 2 parlons-en justement puisque l'on accédera à lui par le très classique JMP $B600 (en $88C) une fois chargé. Dernière petite chose rigolotte à remarquer, le compteur du nombre de secteurs à charger localisé en $8F5 est en plein milieu du code utilisé pour le message d'erreur en cas de boot hors Slot 6. Raffiné n'est-ce pas ?

Pour récupérer le Boot 2, il faut bien sûr shunter le JMP $B600 par un JMP $FF59 par exemple, soit lors du Boot Tracing, soit directement en patchant le Boot Sector sur disque. L'essentiel étant de récupérer le code que voici :

B600-   A9 00       LDA   #$00
B602-   8D 4B BA    STA   $BA4B ; Piste
B605-   8D 4D BA    STA   $BA4D ; Buffer Low
B608-   A9 0F       LDA   #$0F
B60A-   8D 4C BA    STA   $BA4C ; Secteur
B60D-   A9 01       LDA   #$01
B60F-   8D 4F BA    STA   $BA4F ; nb Secteurs à charger
B612-   A9 BF       LDA   #$BF
B614-   8D 4E BA    STA   $BA4E ; Buffer High
B617-   A2 60       LDX   #$60
B619-   A9 06       LDA   #$06
B61B-   AD E9 C0    LDA   $C0E9
B61E-   20 6D B6    JSR   $B66D ; RWTS
B621-   A9 00       LDA   #$00
B623-   8D 4D BA    STA   $BA4D
B626-   A9 AE       LDA   #$AE
B628-   8D 4E BA    STA   $BA4E
B62B-   A9 00       LDA   #$00
B62D-   A0 01       LDY   #$01
B62F-   A2 08       LDX   #$08
B631-   20 90 BF    JSR   $BF90 ; appel RWTS
B634-   20 80 B5    JSR   $B580 ; jmp étape suivante !

Un petit coup d’œil sur le contenu en $B580 nous montre qu'il n'a pas encore été chargé. C'est justement l'objet de l'appel (indirect) à la RWTS en $B631. Notons bien ce $BF90 que l'on va retrouver à chaque fois que l'ACS-DOS aura besoin de charger quelque chose. Cet appel indirect utilise les registres A, X et Y pour le passage de paramètres vers la routine en $B66D où l'on retrouve la RWTS en elle-même.  On ne se disperse pas trop dans les détails, l'affichage de l'image qui nous intéresse est encore très (très) loin.

B634 : 4C 59 FF ; JMP $FF59
B600G ; exécution de la routine qui va charger la suite et nous rendre la main
B580L ; affichage du résultat
 
B580-   2C E9 C0    BIT   $C0E9
B583-   2C 52 C0    BIT   $C052
B586-   20 80 BF    JSR   $BF80
B589-   EA          NOP
B58A-   20 F0 BF    JSR   $BFF0
B58D-   A9 C5       LDA   #$C5
B58F-   85 1C       STA   $1C
B591-   A9 40       LDA   #$40
B593-   85 E6       STA   $E6
B595-   20 F6 F3    JSR   $F3F6
B598-   2C 50 C0    BIT   $C050
B59B-   2C 57 C0    BIT   $C057
B59E-   2C 55 C0    BIT   $C055
B5A1-   4C AA AE    JMP   $AEAA ; jmp suite
 
AEAA-   A0 00       LDY   #$00
AEAC-   B9 E0 AE    LDA   $AEE0,Y
AEAF-   8D 10 AE    STA   $AE10
AEB2-   B9 E8 AE    LDA   $AEE8,Y
AEB5-   8D 16 AE    STA   $AE16
AEB8-   B9 F0 AE    LDA   $AEF0,Y
AEBB-   8D 08 AE    STA   $AE08
AEBE-   B9 F8 AE    LDA   $AEF8,Y
AEC1-   8D 0C AE    STA   $AE0C
AEC4-   C9 FF       CMP   #$FF
AEC6-   F0 0B       BEQ   $AED3
AEC8-   C8          INY
AEC9-   98          TYA
AECA-   48          PHA
AECB-   20 03 AE    JSR   $AE03
AECE-   68          PLA
AECF-   A8          TAY
AED0-   4C AC AE    JMP   $AEAC
AED3-   4C 48 B5    JMP   $B548 ; on continue
 
B548-   A9 00       LDA   #$00
B54A-   85 0E       STA   $0E
B54C-   A5 0E       LDA   $0E
B54E-   A2 00       LDX   #$00
B550-   A0 00       LDY   #$00
B552-   20 11 F4    JSR   $F411
B555-   A0 00       LDY   #$00
B557-   B1 26       LDA   ($26),Y
B559-   48          PHA
B55A-   A5 27       LDA   $27
B55C-   49 60       EOR   #$60
B55E-   85 27       STA   $27
B560-   68          PLA
B561-   91 26       STA   ($26),Y
B563-   A5 27       LDA   $27
B565-   49 60       EOR   #$60
B567-   85 27       STA   $27
B569-   C8          INY
B56A-   C0 28       CPY   #$28
B56C-   D0 E9       BNE   $B557
B56E-   20 A4 B5    JSR   $B5A4
B571-   E6 0E       INC   $0E
B573-   A5 0E       LDA   $0E
B575-   C9 C0       CMP   #$C0
B577-   D0 D3       BNE   $B54C
B579-   2C 54 C0    BIT   $C054
B57C-   4C B0 B5    JMP   $B5B0 ; jmp étape suivante

Ce qu'il faut bien comprendre, c'est que lors de la résolution d'un tel défi, nul besoin d'analyser et de détailler ce qui se passe à chaque étape.Il y a 3 écrans graphiques avant celui qui nous intéresse, on se doute bien qu'ils vont devoir être chargés, probablement décryptés, de même que les routines graphiques et sonores. Notre objectif est d'arriver jusqu'au chargement de l'image du défi. On va donc progresser d'étape en étape en modifiant le saut vers la prochaine étape par un JMP $FF59 pour récupérer la main afin d'analyser ce qui aura été chargé avant son exécution. Jusqu'au JMP $B5B0 en $B57C, tout a été chargé d'un coup et est visible directement en mémoire. En $B5B0 par contre, cela se corse :

B5B0-   A0 00       LDY   #$00
B5B2-   B9 BE B5    LDA   $B5BE,Y
B5B5-   49 7F       EOR   #$7F
B5B7-   99 BE B5    STA   $B5BE,Y
B5BA-   C8          INY
B5BB-   C0 AE       CPY   #$AE
B5BD-   D0 8C       BNE   $B54B
B5BF-   DF          ???
B5C0-   7F          ???
B5C1-   C6 7F       DEC   $7F

Un petit décryptage basique à coup d'EOR. Seul problème ici, la routine qui est décodée suit immédiatement la routine de décodage. Une fois celle-ci terminée, le programme va donc enchaîner avec la suite. La solution ici est d'obtenir en $B5BF un JMP $FF59 après décodage de façon à récupérer la main.
JMP $FF59 = 4C 59 FF. Si on EOR tout ça avec #$7F, on obtient : 33 26 80.
En $B5BF, après décodage, on aurait dû obtenir (sans modification) : (DF 7F C6) EOR #$7F = A0 00 B9
Les plus perspicaces auront aussi noté que le BNE XX en $B5BD est modifié lors du premier passage de la routine de décodage. Le $8C devient $F3 permettant ainsi à la routine de boucler correctement.

B5BF : 33 26 80 ; on remplace par notre JMP $FF59 codé.
B580G ; on relance la routine à ce niveau ! On n'oublie pas que 
      ; c'est le JMP $B580 que l'on avait shunté tout à l'heure.
      ; Il faut donc reprendre au même endroit pour que le tout
      ; s'exécute normalement. On observe alors l'affichage
      ; de la première image et on récupère la main !
B5BF : A0 00 B9 ; on n'oublie pas de remettre les octets originaux !
B5B0L ; on peut maintenant voir ce que ça donne
 
B5B0-   A0 00       LDY   #$00
B5B2-   B9 BE B5    LDA   $B5BE,Y
B5B5-   49 7F       EOR   #$7F
B5B7-   99 BE B5    STA   $B5BE,Y
B5BA-   C8          INY
B5BB-   C0 AE       CPY   #$AE
B5BD-   D0 F3       BNE   $B5B2
 
B5BF-   A0 00       LDY   #$00
B5C1-   B9 00 AE    LDA   $AE00,Y
B5C4-   4D BF B5    EOR   $B5BF
B5C7-   8D BF B5    STA   $B5BF
B5CA-   C8          INY
B5CB-   D0 F4       BNE   $B5C1
B5CD-   EE C3 B5    INC   $B5C3
B5D0-   AD C3 B5    LDA   $B5C3
B5D3-   C9 B5       CMP   #$B5
B5D5-   D0 ED       BNE   $B5C4
B5D7-   AD BF B5    LDA   $B5BF
B5DA-   C9 45       CMP   #$45
B5DC-   F0 03       BEQ   $B5E1
B5DE-   20 C0 BF    JSR   $BFC0   ; WARNING
B5E1-   A0 00       LDY   #$00
B5E3-   B9 00 08    LDA   $0800,Y
B5E6-   4D D4 B5    EOR   $B5D4
B5E9-   8D D4 B5    STA   $B5D4
B5EC-   B9 00 B6    LDA   $B600,Y
B5EF-   4D D4 B5    EOR   $B5D4
B5F2-   8D D4 B5    STA   $B5D4
B5F5-   C8          INY
B5F6-   D0 EB       BNE   $B5E3
B5F8-   C9 D9       CMP   #$D9
B5FA-   F0 03       BEQ   $B5FF
B5FC-   20 C0 BF    JSR   $BFC0   ; WARNING
B5FF-   60          RTS           ; retour en $B637

Cette routine est intéressante car elle effectue une triple vérification : d'abord de la zone $AE00-$B4FF puis de la page $08 (le Boot 1 donc) et enfin de la page $B6 (Boot 2). Si le résultat n'est pas celui escompté, on saute vers une mystérieuse routine en $BFC0. Si tout se passe bien, on finit sur un RTS qui nous renverra en $B637. Souvenez-vous du JSR en $B634. Depuis nous n'avons effectué que des JMP pour aller d'étape en étape. Le RTS nous renvoie donc juste derrière ce JSR là. À noter que la partie en $B637 aura été décodée en même temps que la partie en $B5BF.
Que se passe-t'il si on exécute la routine telle quelle par un $B5BFG ? Je vous invite à le faire mais prenez la précaution de faire une sauvegarde votre disque (ou de votre image) d'abord...

 

Le petit voyant rouge allumé en bas à droite, ce n'est pas bon signe ! Et oui ACS n'a aucune pitié et efface votre disque si le checksum des pages précédentes n'est pas correct. N'oublions pas que pour arriver jusqu'ici, nous avons modifié d'abord la page $08 puis la page $B6 (pour y mettre à chaque fois un JMP $FF59). Le checksum l'a détecté et il n'est pas content !

 

Pour continuer, la meilleure solution sera de reprendre directement en $B637. On n'exécutera donc pas le code en $B5BF (aucune importance, ce n'était qu'une vérification). Évidemment avant de passer en $B637, il va d'abord falloir analyser ce qui nous attend :

B637-   20 80 BF    JSR   $BF80
B63A-   A9 00       LDA   #$00
B63C-   8D 4D BA    STA   $BA4D
B63F-   A9 A0       LDA   #$A0
B641-   8D 4E BA    STA   $BA4E   ; chargement en $A000
B644-   A9 16       LDA   #$16
B646-   A0 00       LDY   #$00
B648-   A2 10       LDX   #$10    ; 16 secteurs !
B64A-   20 90 BF    JSR   $BF90   ; appel RWTS
B64D-   A0 00       LDY   #$00
B64F-   98          TYA
B650-   59 00 A0    EOR   $A000,Y
B653-   99 00 A0    STA   $A000,Y ; décryptage de la zone $A000-$A0FF
B656-   C8          INY
B657-   D0 F6       BNE   $B64F
B659-   A9 9F       LDA   #$9F    ; on empile une
B65B-   48          PHA           ; nouvelle adresse
B65C-   A9 FF       LDA   #$FF    ; de retour pour
B65E-   48          PHA           ; le RTS de la routine HOME
B65F-   4C 58 FC    JMP   $FC58   ; HOME (puis go en $A000)

Faisons un premier point : arrivé à cette étape, avant l'exécution de la routine en $B637, seule la première image a été chargée et affichée. Nous avons découvert de plus qu'ACS n'hésitera pas à nous pourrir notre disque en cas de bad checksum rencontré... Méfiance donc.
Notre routine en $B637 que fait-elle ? Elle charge incontestablement la suite par l'appel à la RWTS. On a ensuite droit à un petit décryptage d'une partie de la zone nouvellement chargée (entre $A000 et $A0FF) et à un joli empilement de l'adresse $9FFF. Pourquoi faire me direz-vous ? En sortie de la routine Monitor HOME, le RTS rencontré dépilera l'adresse alors en haut de la pile (donc $9FFF), y ajoutera automatiquement 1 (c'est dans ses gènes) et y sautera : on arrivera donc en $A000. Là encore,  cette technique de saut par pile interposée a déjà été rencontrée quelques fois et était bien appréciée par quelques élites de la scène Underground.
Pour découvrir ce qui nous attend en $A000, rien de plus simple :

B65F : 4C 59 FF ; on shunte le JMP HOME (donc le RTS)
B637G ; on exécute pour le chargement (et le décryptage)
A000L
 
A000-   20 D4 A0    JSR   $A0D4    ; vérif !
A003-   2C 55 C0    BIT   $C055
A006-   A9 00       LDA   #$00
A008-   8D 4D BA    STA   $BA4D
A00B-   A9 20       LDA   #$20
A00D-   8D 4E BA    STA   $BA4E    ; chargement en $2000+
A010-   A9 12       LDA   #$12
A012-   A0 00       LDY   #$00
A014-   A2 20       LDX   #$20
A016-   20 90 BF    JSR   $BF90    ; appel RWTS
A019-   20 51 AE    JSR   $AE51
A01C-   A9 00       LDA   #$00
A01E-   85 3C       STA   $3C
A020-   A9 20       LDA   #$20
A022-   85 3D       STA   $3D
A024-   A9 F8       LDA   #$F8
A026-   85 3E       STA   $3E
A028-   A9 3F       LDA   #$3F
A02A-   85 3F       STA   $3F
A02C-   A9 00       LDA   #$00
A02E-   85 42       STA   $42
A030-   A9 20       LDA   #$20
A032-   85 43       STA   $43
A034-   38          SEC
A035-   20 11 C3    JSR   $C311    ; AUXMOVE
A038-   A9 00       LDA   #$00
A03A-   8D 4D BA    STA   $BA4D
A03D-   A9 20       LDA   #$20
A03F-   8D 4E BA    STA   $BA4E    ; chargement en $2000+
A042-   A9 14       LDA   #$14
A044-   A0 00       LDY   #$00
A046-   A2 20       LDX   #$20
A048-   20 90 BF    JSR   $BF90    ; appel RWTS
A04B-   2C 50 C0    BIT   $C050
A04E-   2C 57 C0    BIT   $C057
A051-   2C 54 C0    BIT   $C054
A054-   2C 52 C0    BIT   $C052
A057-   2C 5E C0    BIT   $C05E
A05A-   8D 0D C0    STA   $C00D
A05D-   20 A8 A0    JSR   $A0A8    ; vérif !
A060-   20 04 AE    JSR   $AE04    ;
A063-   8D 0C C0    STA   $C00C
A066-   2C 55 C0    BIT   $C055
A069-   8D 5F C0    STA   $C05F
A06C-   A9 00       LDA   #$00
A06E-   8D 4D BA    STA   $BA4D
A071-   A9 10       LDA   #$10
A073-   8D 4E BA    STA   $BA4E    ; chargement en $1000+
A076-   A9 00       LDA   #$00
A078-   8D 4D BA    STA   $BA4D
A07B-   A9 1A       LDA   #$1A
A07D-   A0 00       LDY   #$00
A07F-   A2 30       LDX   #$30
A081-   20 90 BF    JSR   $BF90    ; appel RWTS
A084-   A9 BB       LDA   #$BB     ; on empile
A086-   48          PHA            ; $BBDA pour un
A087-   A9 DA       LDA   #$DA     ; futur RTS et donc
A089-   48          PHA            ; sauter en $BBDB
A08A-   A0 00       LDY   #$00
A08C-   B9 00 A1    LDA   $A100,Y  ; déplacement $A100-$A9FF
A08F-   99 00 B7    STA   $B700,Y  ; vers $B700-$BFFF
A092-   C8          INY
A093-   D0 F7       BNE   $A08C
A095-   EE 8E A0    INC   $A08E
A098-   EE 91 A0    INC   $A091
A09B-   AD 91 A0    LDA   $A091
A09E-   C9 C0       CMP   #$C0
A0A0-   F0 03       BEQ   $A0A5
A0A2-   4C 8A A0    JMP   $A08A
A0A5-   4C 58 FC    JMP   $FC58    ; notre RTS vers $BBDB

Dans cette routine, nous avons plusieurs appels à la RWTS (ça tombe bien, il reste encore beaucoup de choses à charger) et on remarque surtout la sortie utilisant encore une fois la routine HOME pour sauter cette fois en $BBDB (toujours en utilisant la pile). Évidemment, nous pourrions allègrement mettre un JMP $FF59 en $A0A5 et exécuter le tout pour voir où nous allons arriver... Sauf que l'on sait maintenant que cela peut nous péter à la gueule à tout moment... Et ça commence par la routine en $A0D4 appelée dès $A000 :

A0D4-   A0 00       LDY   #$00
A0D6-   98          TYA
A0D7-   59 00 AE    EOR   $AE00,Y
A0DA-   99 00 AE    STA   $AE00,Y
A0DD-   4D D5 A0    EOR   $A0D5
A0E0-   8D D5 A0    STA   $A0D5
A0E3-   98          TYA
A0E4-   59 00 AF    EOR   $AF00,Y
A0E7-   99 00 AF    STA   $AF00,Y
A0EA-   4D D5 A0    EOR   $A0D5
A0ED-   8D D5 A0    STA   $A0D5
A0F0-   C8          INY
A0F1-   D0 E3       BNE   $A0D6
A0F3-   C9 58       CMP   #$58
A0F5-   F0 03       BEQ   $A0FA
A0F7-   4C C0 BF    JMP   $BFC0   ; WARNING
A0FA-   60          RTS

La routine décode et en profite pour faire un checksum et nous renvoie vers la routine maudite ($BFC0) si cela ne lui convient pas. Mais on trouve aussi d'autres vérifs dans la routine en $A0A8 :

A0A8-   A9 40       LDA   #$40
A0AA-   8D 4E BA    STA   $BA4E
A0AD-   A9 00       LDA   #$00
A0AF-   8D 4D BA    STA   $BA4D
A0B2-   A9 17       LDA   #$17
A0B4-   A0 00       LDY   #$00
A0B6-   A2 20       LDX   #$20
A0B8-   20 90 BF    JSR   $BF90  ; appel RWTS
A0BB-   A9 9A       LDA   #$9A
A0BD-   8D 4D BA    STA   $BA4D
A0C0-   A9 7F       LDA   #$7F
A0C2-   8D 4E BA    STA   $BA4E
A0C5-   A9 19       LDA   #$19
A0C7-   A0 00       LDY   #$00
A0C9-   A2 11       LDX   #$11
A0CB-   20 90 BF    JSR   $BF90  ; appel RWTS
A0CE-   EA          NOP
A0CF-   EA          NOP
A0D0-   EA          NOP
A0D1-   4C B8 AE    JMP   $AEB8  ; vérif

En fait on ne tarde pas à être noyé sous les routines qui s'appellent entre elles, font des vérifs etc. Notre objectif étant de parvenir à l'image du défi, pas d'entrer dans tous les sous-programmes, on va donc utiliser les grands moyens : arrivé en $AA05, on doit donc sauter en $BBDB. Or on voit que la partie commençant en $A08A déplace (entre autre) la page $A5 vers la page $BB. Comme les appels à la RWTS précédents ne chargent rien dans cet espace, on peut légitimement penser que la partie qui sera en $BB00 est déjà en mémoire en $A500 (elle a normalement été chargée précédemment par la routine en $B637)

Qu'avons-nous en $A5DB ?

A5DB-   A0 00       LDY   #$00
A5DD-   B9 00 11    LDA   $1100,Y  ; décodage
A5E0-   59 00 A0    EOR   $A000,Y
A5E3-   99 00 11    STA   $1100,Y  ; vers $1100+
A5E6-   4D DC BB    EOR   $BBDC
A5E9-   8D DC BB    STA   $BBDC
A5EC-   C8          INY
A5ED-   D0 EE       BNE   $A5DD
A5EF-   C9 21       CMP   #$21
A5F1-   D0 BB       BNE   $A5AE   ; bad boy
A5F3-   A9 11       LDA   #$11
A5F5-   48          PHA
A5F6-   A9 7F       LDA   #$7F
A5F8-   48          PHA           ; $117F empilé
A5F9-   4C 58 FC    JMP   $FC58   ; pour un RTS vers $1180

Ce code est très probablement celui qui sera exécuté en $BBDB. L'idée géniale (hum), c'est de chercher sur le disque si nous n'avons pas directement ce code quelque part. On l'a vu, les différents checksum mis en place par ACS posent problème dès lors que nous modifions le code pour reprendre la main. Si on localise le code en $BBDB sur disque, il suffira de mettre un 4C 59 FF au début de la routine pour prendre la main au moment où le code sautera à cette adresse. Ce qui nous permet de tenter cette approche audacieuse (rehum), c'est que le code en lui-même n'est pas encrypté (il a juste été déplacé) et surtout que les checksums qui posent problèmes ne vérifieront pas cette partie avant qu'elle ne soit exécutée.

Faisons donc une recherche Hexa sur le disque avec la chaine  : A0 00 B9 00 11 (début de la routine en $A5DB donc en $BBDB).
Croisons les doigts et bingo ! Nous trouvons le tout à l'emplacement : T$16/S$05/P :$DB. Notez que la position ($DB) dans le secteur correspond bien...
À partir d'une copie de la disquette de Championship Wrestling non modifiée (donc pas de modification sur le boot sector ou autre), on va donc changer le JMP $FC58 (4C 58 FC) en position $F9 par un 4C 59 FF (JMP $FF59). On n'a pas à nous occuper du checksum découlant du décodage vers $1100+ car il ne contrôle pas la partie que l'on vient de modifier. On aurait aussi pu effectuer la modif au début de la routine en $BBDB directement mais autant récupérer la main à la fin du décodage, nous permettant ainsi d'avoir lisible la partie qui nous intéresse à savoir $1100+ et donc le $1180, prochaine étape de notre chemin de croix.

Relancez votre disquette fraîchement modifiée, et sous vos yeux ébahis, le JMP Monitor vous rend la main juste avant le chargement (ou est-ce le décodage ? Mystère pour le moment...) de l'image du défi ! Nous n'arrivons pas ici par hasard. Si vous reprenez la routine en $A000, on repère deux chargements en $2000 et un déplacement en mémoire auxiliaire entre les deux. La seconde image étant une "Double Hires", la mémoire auxiliaire est logiquement utilisée. Nous avons ensuite encore un chargement pour finalement arriver vers le déplacement mémoire vu précédemment ($A100+ vers $B700+). Il est vrai que notre JMP $FF59 aurait très bien pu arriver après l'affichage du défi. Il aurait alors fallu "remonter" un peu pour trouver ce que nous cherchons. Mais cette méthode "empirique" de localisation, avec un peu d'expérience, est très efficace pour circonscrire une zone recherchée dans les méandres des multiples sous-routines d'un programme. La preuve !

Nous pouvons donc repartir maintenant sur une nouvelle base en étant nettement plus avancé dans le chargement de notre défi. D'ailleurs, par curiosité, il est toujours bon de vérifier régulièrement ce que contiennent les pages Hires.

Arrivé à ce point, en page 2, pas de surprise, nous trouvons la troisième image, celle affichée juste avant le défi. En page 1 par contre, apparaît un joli garbage. Il ne faut pas être devin pour prophétiser que nous tenons - sans doute - notre image encore encryptée. Un moyen simple de le vérifier ? Remettez en $BBF9 le 4C 58 FC attendu (nous avions mis 4C 59 FF directement sur le  disque rappelez-vous) pour éviter de nous faire mal si on tombait sur un checksum vérifiant cette portion. Passez ensuite sous affichage Hires/Page 1 ($C050/$C057) et (en aveugle) tapez 1180G pour reprendre là où le programme s'était interrompu. Vous assistez en direct au décodage de l'image. On voit d'ailleurs qu'il y a plusieurs passes avant l'obtention de l'image finale. Cela promet pour la seconde partie (ou pas)...

Le gros intérêt de notre modification disque c'est qu'il suffit de rebooter pour se retrouver au même point, c'est à dire juste avant le décodage de l'image de défi. Profitez-en d'ailleurs pour inspecter le contenu de la mémoire en $2000+ et repérer les premiers octets. Faites ensuite une petite recherche sur disque pour voir si ces octets, par un heureux hasard, ne seraient pas quelques part. Idem pour $3000+

2000 : 17 3F 0A 1B 6F 75
3000 : 80 29 70 49 00 4E

Vous avez trouvé la chaîne "2000" en T$1B/S$00 et la "3000" en T$1C/S$00 ? Bravo, vous venez (très) probablement de localiser l'image cryptée sur disque. Cela nous sera utile au moment de la réécrire signée (et ré-encryptée). Elle occupe donc les Pistes $1B et $1C au complet. Non, ce n'est pas jouer aux devinettes, c'est juste une question de bon sens. On peut aussi s'emmerder à remonter pour trouver quand et où l'image encryptée a été chargée en suivant les appels à la RWTS, repérer les paramètres passés etc. Parfois, il faut le faire, mais ici ce n'est pas nécessaire donc autant en profiter pour gagner du temps !

Allez, on reboote notre disquette modifiée pour se retrouver une fois encore avant le grand saut en $1180 et on inspecte un peu ce qui s'y passe :

1180-   A0 00       LDY   #$00
1182-   B9 00 BB    LDA   $BB00,Y
1185-   4D 81 11    EOR   $1181
1188-   8D 81 11    STA   $1181
118B-   C8          INY
118C-   C0 DA       CPY   #$DA
118E-   F0 03       BEQ   $1193
1190-   4C 82 11    JMP   $1182
1193-   C9 B8       CMP   #$B8    ; checksum OK ?
1195-   F0 03       BEQ   $119A
1197-   4C 1D AF    JMP   $AF1D   ; bad boy !
119A-   4C 00 11    JMP   $1100   ; vers la suite

Et encore un nouveau checksum qui vérifie une partie de la page $BB cette fois. Bizarrement celui-ci ne check que jusqu'en $BBD9. Notre modification ayant eu lieu en $BBF9, elle ne posera aucun problème avec ce checksum. Plutôt bon à prendre ! Passons donc à la suite en $1100 :

1100-   A2 00       LDX   #$00
1102-   BD D0 11    LDA   $11D0,X
1105-   85 0F       STA   $0F
1107-   A9 FF       LDA   #$FF
1109-   49 FF       EOR   #$FF
110B-   85 0E       STA   $0E
110D-   85 10       STA   $10
110F-   BD E0 11    LDA   $11E0,X
1112-   85 11       STA   $11
1114-   A0 00       LDY   #$00
1116-   98          TYA
1117-   5D F0 11    EOR   $11F0,X
111A-   51 0E       EOR   ($0E),Y ; décryptage Part I
111C-   91 10       STA   ($10),Y
111E-   88          DEY
111F-   D0 F5       BNE   $1116
1121-   E8          INX
1122-   E0 0C       CPX   #$0C
1124-   F0 03       BEQ   $1129
1126-   4C 02 11    JMP   $1102
1129-   A9 4C       LDA   #$4C
112B-   85 00       STA   $00
112D-   A9 08       LDA   #$08
112F-   85 01       STA   $01
1131-   A9 70       LDA   #$70
1133-   85 02       STA   $02
1135-   20 00 70    JSR   $7000   ; décryptage part II
1138-   A9 04       LDA   #$04
113A-   8D DE 60    STA   $60DE
113D-   A9 C8       LDA   #$C8
113F-   8D DF 60    STA   $60DF
1142-   4C A0 11    JMP   $11A0   ; vers suite
 
11D0-   12 13 14 15 16 17 18 19 1A 1B 1C 1D 00
11E0-   02 60 70 71 72 73 03 19 61 62 63 64 00
11F0-   01 45 D3 79 18 56 99 44 12 19 33 35 00
 
11A0-   A0 00       LDY   #$00    ; nettoyage...
11A2-   98          TYA
11A3-   99 00 70    STA   $7000,Y
11A6-   99 00 71    STA   $7100,Y
11A9-   99 00 72    STA   $7200,Y
11AC-   99 00 73    STA   $7300,Y
11AF-   99 00 74    STA   $7400,Y
11B2-   99 00 75    STA   $7500,Y
11B5-   99 00 76    STA   $7600,Y
11B8-   C8          INY
11B9-   F0 03       BEQ   $11BE
11BB-   4C A2 11    JMP   $11A2
11BE-   4C 60 11    JMP   $1160   ; vers suite
 
1160-   A9 11       LDA   #$11    ;
1162-   85 0F       STA   $0F
1164-   A9 EF       LDA   #$EF
1166-   85 0E       STA   $0E
1168-   A0 00       LDY   #$00
116A-   A9 A9       LDA   #$A9
116C-   51 0E       EOR   ($0E),Y
116E-   48          PHA            ; on empile $F6 EOR $A9 = $5F
116F-   A0 10       LDY   #$10
1171-   A9 FA       LDA   #$FA
1173-   51 0E       EOR   ($0E),Y  ; on empile $05 EOR $FA = $FF
1175-   48          PHA
1176-   4C 80 02    JMP   $0280    ; mettre JMP $FF59

Certains espéraient sans doute la fin de la quête, ce n'est pas tout à fait le cas... Ici nous sommes face aux routines qui vont décrypter non pas l'image du défi mais la routine qui va elle-même décrypter notre défi. Et vous savez quoi ? Et bien on s'en fout ! En effet, pour le moment nul besoin de comprendre ce que font ces routines, tout ce qui nous intéresse, c'est de savoir qu'on en sort en sautant en $280. On remarque bien évidemment l'empilement juste au-dessus du JMP de deux valeurs qu'il sera facile de récupérer une fois notre saut vers le Monitor effectué. Un indice chez vous : c'est $5FFF qui est empilé, ce qui laisse présager d'un RTS nous conduisant vers $6000.

1176 : 4C 59 FF ; on met un JMP Monitor à la place du JMP $280
1180G           ; et on relance !
280L            ; on admire le résultat
 
0280-   A9 21       LDA   #$21
0282-   8D F2 03    STA   $03F2 ; vector reset
0285-   A9 02       LDA   #$02
0287-   8D F3 03    STA   $03F3 ; redéfini
028A-   49 A5       EOR   #$A5
028C-   8D F4 03    STA   $03F4
028F-   A9 21       LDA   #$21
0291-   8D F0 03    STA   $03F0 ; idem
0294-   A9 02       LDA   #$02
0296-   8D F1 03    STA   $03F1 ; pour le vector BRK !
0299-   60          RTS ; sans surprise le RTS nous envoie vers $6000 !

Et nous voilà enfin face à la routine en $6000 qui est LA routine de décryptage de l'image car (et vous pouvez le vérifier) avant son exécution, l'image en Page 1 n'est toujours pas décryptée... Un rapide coup d'œil sur son contenu avant de rendre l'antenne :

6000-   20 9B 02    JSR   $029B   ; lalala !
 
6003-   A9 00       LDA   #$00
6005-   85 10       STA   $10
 
6007-   A9 00       LDA   #$00
6009-   85 0E       STA   $0E
600B-   A9 20       LDA   #$20
600D-   85 0F       STA   $0F
 
; décodage phase 1 : (A) =  (A) EOR (A+1) 
 
600F-   A2 20       LDX   #$20
 
6011-   A0 00       LDY   #$00
 
6013-   B1 0E       LDA   ($0E),Y
6015-   C8          INY
6016-   51 0E       EOR   ($0E),Y
6018-   88          DEY
6019-   91 0E       STA   ($0E),Y
601B-   C8          INY
601C-   D0 F5       BNE   $6013
 
601E-   E6 0F       INC   $0F
6020-   CA          DEX
6021-   D0 EE       BNE   $6011
 
6023-   E6 10       INC   $10
6025-   AD F1 20    LDA   $20F1
6028-   49 11       EOR   #$11    ; check 1
602A-   D0 DB       BNE   $6007
 
602C-   A5 10       LDA   $10
602E-   C9 0A       CMP   #$0A    ; check 1b
6030-   D0 FE       BNE   $6030   ; boucle infinie
 
; décodage phase 2 : (A) EOR XX
 
6032-   A9 00       LDA   #$00
6034-   85 0F       STA   $0F
6036-   A9 20       LDA   #$20
6038-   85 10       STA   $10
603A-   A2 20       LDX   #$20
 
603C-   A0 00       LDY   #$00
 
603E-   B1 0F       LDA   ($0F),Y
6040-   48          PHA
6041-   98          TYA
6042-   18          CLC
6043-   65 10       ADC   $10
6045-   48          PHA
6046-   8A          TXA
6047-   6A          ROR
6048-   85 11       STA   $11
604A-   68          PLA
604B-   2A          ROL
604C-   2A          ROL
604D-   2A          ROL
604E-   45 11       EOR   $11
6050-   85 11       STA   $11
6052-   68          PLA
6053-   45 11       EOR   $11
6055-   91 0F       STA   ($0F),Y
6057-   88          DEY
6058-   D0 E4       BNE   $603E
 
605A-   E6 10       INC   $10
605C-   CA          DEX
605D-   D0 DD       BNE   $603C
 
; décodage phase 3 :  A = A EOR (#$78 EOR Y)
 
605F-   A9 00       LDA   #$00
6061-   85 0E       STA   $0E
6063-   A9 20       LDA   #$20
6065-   85 0F       STA   $0F
6067-   AA          TAX   
 
6068-   A0 00       LDY   #$00
606A-   98          TYA
606B-   49 78       EOR   #$78
606D-   51 0E       EOR   ($0E),Y
606F-   91 0E       STA   ($0E),Y
6071-   C8          INY
6072-   D0 F6       BNE   $606A
 
6074-   E6 0F       INC   $0F
6076-   CA          DEX
6077-   D0 EF       BNE   $6068
 
6079-   A9 00       LDA   #$00
607B-   85 0E       STA   $0E
607D-   A9 B7       LDA   #$B7
607F-   85 0F       STA   $0F
6081-   A0 3D       LDY   #$3D
6083-   A9 C5       LDA   #$C5
6085-   91 0E       STA   ($0E),Y ; $C5 en $B73D
6087-   A0 46       LDY   #$46
6089-   A9 E7       LDA   #$E7
608B-   91 0E       STA   ($0E),Y ; $E7 en $B746
 
608D-   A0 00       LDY   #$00
608F-   B9 00 60    LDA   $6000,Y
6092-   4D 8E 60    EOR   $608E
6095-   8D 8E 60    STA   $608E
6098-   C8          INY
6099-   C0 8E       CPY   #$8E
609B-   D0 F2       BNE   $608F
609D-   C9 B8       CMP   #$B8    ; check 2 (routine décodage)
609F-   F0 03       BEQ   $60A4
60A1-   4C 00 C6    JMP   $C600   ; reboot
 
60A4-   A0 00       LDY   #$00
60A6-   B9 00 20    LDA   $2000,Y
60A9-   4D A5 60    EOR   $60A5
60AC-   8D A5 60    STA   $60A5
60AF-   C8          INY
60B0-   D0 F4       BNE   $60A6
60B2-   EE A8 60    INC   $60A8
60B5-   AD A8 60    LDA   $60A8
60B8-   C9 40       CMP   #$40
60BA-   D0 EA       BNE   $60A6
60BC-   AD A5 60    LDA   $60A5
60BF-   C9 DE       CMP   #$DE    ; check 3 (image décodée)
60C1-   F0 03       BEQ   $60C6
60C3-   4C 21 02    JMP   $0221   ; bad boy "ACS Lead Again !"
60C6-   2C 54 C0    BIT   $C054
60C9-   EA          NOP
60CA-   2C 10 C0    BIT   $C010
60CD-   A9 02       LDA   #$02
60CF-   20 20 64    JSR   $6420   ; go to check 4
60D2-   A0 00       LDY   #$00
60D4-   B9 00 AA    LDA   $AA00,Y
60D7-   C8          INY
60D8-   59 00 AA    EOR   $AA00,Y
60DB-   88          DEY
60DC-   99 00 04    STA   $0400,Y
60DF-   C8          INY
60E0-   D0 F2       BNE   $60D4
60E2-   EE D6 60    INC   $60D6
60E5-   EE DA 60    INC   $60DA
60E8-   EE DE 60    INC   $60DE
60EB-   AD DE 60    LDA   $60DE
60EE-   C9 08       CMP   #$08
60F0-   F0 03       BEQ   $60F5
60F2-   4C D4 60    JMP   $60D4
60F5-   20 2F FB    JSR   $FB2F
60F8-   A9 60       LDA   #$60
60FA-   85 2B       STA   $2B
60FC-   4C 00 BB    JMP   $BB00
 
6420-   4C 88 64    JMP   $6488
 
6488-   A0 00       LDY   #$00
648A-   B9 00 60    LDA   $6000,Y
648D-   4D 89 64    EOR   $6489
6490-   8D 89 64    STA   $6489
6493-   C8          INY
6494-   D0 F4       BNE   $648A
6496-   C9 04       CMP   #$04    ; check 4
6498-   F0 03       BEQ   $649D
649A-   6C F2 03    JMP   ($03F2) ; reboot !
649D-   A9 A0       LDA   #$A0
649F-   8D 20 64    STA   $6420
64A2-   A9 D1       LDA   #$D1
64A4-   8D 21 64    STA   $6421
64A7-   A9 B9       LDA   #$B9
64A9-   8D 22 64    STA   $6422
64AC-   4C 20 64    JMP   $6420

Passez en mode Hires, Page 1 et lancez la routine par $6000G et vous assistez au décryptage en direct. C'est comme tout à l'heure sauf que cette fois, nous sommes bien au cœur même du décodage en l'exécutant.
On peut déjà remarquer sans plus entrer dans les détails, qu'il y a différentes vérifications qui sont effectuées, vérifications qu'il faudra contourner d'une façon ou d'une autre. Mais tout ceci fera l'objet de la partie II normalement en ligne demain ou après-demain... Suspens !

 

Et pour finir, à l'occasion d'une fausse manœuvre ou d'un checksum assassin, il pourra très bien vous arriver de tomber sur ceci ! La routine se trouve en $221 et on y arrive, notamment, en cas de Reset intempestif ou de BRK ravageur !  C'est toute la mémoire qui sera alors rempli d'ACS !