Après la loooooooonnnngue introduction au défi de Déplombage Mode d'Emploi 4, il était bien évident que j'allais devoir revenir dessus pour un décorticage en règle. Alors oui, Kristo lui-même dans DEPME 5 en avait fourni une solution complète. On va donc prendre une voie différente de la sienne en Boot Traçant pour retrouver par nous-même les routines intéressantes. Cette approche est une nouvelle fois facilement utilisable car l'affichage de la page à signer ne se trouve pas très loin après le Boot du Disk. Allez c'est parti !
]CALL -151 *1600 ; Le principe est toujours le même. On cherche le JMP vers le Boot1 ; (la phase suivante). Il se trouve forcément en page 08. ; J'ai mis ici une bonne partie de cette page car il y a quelques petites ; choses à remarquer qui pourraient bien nous être utiles pour la suite : 0801- E0 60 CPX #$60 0803- A9 62 LDA #$62 0805- 20 8D 08 JSR $088D ; à suivre ! 0808- A9 B6 LDA #$B6 080A- 85 27 STA $27 080C- BD 8C C0 LDA $C08C,X 080F- 10 FB BPL $080C 0811- 49 D5 EOR #$D5 0813- D0 F7 BNE $080C 0815- BD 8C C0 LDA $C08C,X 0818- 10 FB BPL $0815 081A- C9 AA CMP #$AA 081C- D0 F3 BNE $0811 081E- BD 8C C0 LDA $C08C,X 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 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 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 0851- 10 FB BPL $084E 0853- 59 D6 02 EOR $02D6,Y 0856- D0 41 BNE $0899 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- 91 26 STA ($26),Y 086B- C8 INY 086C- D0 EE BNE $085C 086E- E6 27 INC $27 0870- A2 60 LDX #$60 0872- CE EE 08 DEC $08EE 0875- D0 95 BNE $080C 0877- 20 D0 08 JSR $08D0 087A- A0 27 LDY #$27 087C- B9 A4 08 LDA $08A4,Y 087F- 49 A0 EOR #$A0 ; décodage du message texte d'accueil 0881- 99 00 04 STA $0400,Y 0884- 88 DEY 0885- 10 F5 BPL $087C 0887- 4C 00 B6 JMP $B600 ; JMP vers le BOOT1 088A- 4C A9 FA JMP $FAA9 088D- 8D F4 03 STA $03F4 ; octet de contrôle du Hi Reset 0890- AD 51 C0 LDA $C051 0893- A9 00 LDA #$00 0895- 8D F2 03 STA $03F2 ; Vector RESET (Lo) 0898- A9 C6 LDA #$C6 089A- 8D F3 03 STA $03F3 ; et Hi 089D- 2C 10 C0 BIT $C010 08A0- 60 RTS |
Bien on a trouvé le JMP vers le Boot1. Il faut donc shunter ce JMP $B600 pour reprendre la main juste avant. On modifie donc "notre" routine chargement Boot0 en RAM :
16F8 : 4C 10 17 ; on remplace le JMP $801 par un JMP $1710 ; on place le patch qui viendra modifier le JMP $B600 une fois le Boot0 chargé ; en $800, patch qui nous fera sauter en $1720 1710 : A9 20 8D 88 08 A9 17 8D 89 08 4C 01 08 1720 : 4C 65 FF ; on récupère la main ! |
Et on garde dans un coin de notre tête les infos concernant le Vecteur de Reset. On pourrait en avoir besoin plus tard...
Et on continue :
*1600G ; on relance notre boot et on récupère la main ; après l'affichage du message texte * B600L ; on regarde un peu ce que contient le Boot1 ; note : j'ai supprimé dans la suite tous les NOP du code pour éclaircir un peu. B600- EE F4 03 INC $03F4 ; à noter ! Concerne le Reset Vector B603- A9 00 LDA #$00 B605- 8D 9A B7 STA $B79A B608- AD E8 C0 LDA $C0E8 B60B- A9 20 LDA #$20 B60D- 85 E6 STA $E6 B611- 8D 52 C0 STA $C052 ; plein écran B614- 8D 54 C0 STA $C054 ; page 1 B617- 8D 57 C0 STA $C057 ; Hires B61A- 8D 50 C0 STA $C050 ; mode graphique B631- AD E9 C0 LDA $C0E9 B634- A9 46 LDA #$46 B637- 8D 4F BA STA $BA4F B63A- A9 01 LDA #$01 B63D- 8D 4B BA STA $BA4B B640- A9 00 LDA #$00 B643- 8D 4C BA STA $BA4C B646- A9 00 LDA #$00 B649- 8D 4D BA STA $BA4D B64C- A9 60 LDA #$60 B64F- 8D 4E BA STA $BA4E B652- A9 00 LDA #$00 B655- 8D 6B B6 STA $B66B ; modification du $C600 B658- A9 60 LDA #$60 B65B- 8D 6C B6 STA $B66C ; en $6000 B65E- 8D 51 C0 STA $C051 B661- 20 6D B6 JSR $B66D B664- 8D E8 C0 STA $C0E8 B667- 20 2F FB JSR $FB2F B66A- 4C 00 C6 JMP $C600 ; saut vers BOOT2 B66D- AD 4B BA LDA $BA4B |
On ne tombe bien sûr pas dans le panneau du JMP $C600. Il est modifié juste avant. On voit donc que le Boot2 se fera en $6000. On doit donc patcher cette modification ( !) pour pouvoir récupérer la main après le chargement du Boot2 :
*1720 : A9 65 8D 53 B6 A9 FF 8D 59 B6 4C 00 B6 *1720L 1720 : LDA #$65 1722 : STA $B653 1725 : LDA #$FF 1727 : STA $B659 172A : JMP $B600 *1600G ; on relance notre boot * *6000L ; et on inspecte le résultat : 6000- 20 1D 60 JSR $601D 6003- A9 00 LDA #$00 6005- 85 6A STA $6A 6007- 20 67 60 JSR $6067 600A- 20 CF 64 JSR $64CF 600D- 20 80 64 JSR $6480 6010- 20 54 64 JSR $6454 6013- 20 9A 63 JSR $639A 6016- A9 00 LDA #$00 6018- 85 FF STA $FF 601A- 20 10 7B JSR $7B10 601D- A9 D5 LDA #$D5 601F- 20 F4 F3 JSR $F3F4 6022- 60 RTS |
Arrivé à ce point, on sait que l'on n'est plus très loin. On doit encore passer l'intro et ensuite on aura l'affichage de notre fameuse page. On pourrait entrer dans chaque JSR pour voir un peu ce qu'il s'y passe. Mais c'est ici que doit agir le feeling, l'instinct du chasseur, le sixième sens du bidouilleur ! J'avoue que le mien, sur Apple II est un peu rouillé et finalement n'a jamais été très très affûté (mais j'y travaille...).
Par contre sur PC ayant un peu plus de bouteille par quelques longues années de tripatouillage d'Exe, j'ai finis par avoir quelques bons réflexes (et sur PC quand le code fait plusieurs kilo pour ne pas dire mega octets de longueur, y'a intérêt à pas trop se perdre).
Bref tout ça pour dire que face à ce genre de code, à savoir une suite de JSR vers des adresses relativement proches et finalement un JSR vers une adresse plus éloignée, quand on sait qu'il reste encore un gros passage avant ce qui nous intéresse (ça y est, ça fait tilt ?) et bien oui, on va directement vers l'adresse la plus éloignée ! De deux choses l'une, soit ce JSR arrive après affichage de notre cible (dans ce cas, on recommencera en prenant le JSR d'avant), soit il arrive avant et là on est généralement plutôt bon... Pragmatisme ? Empirisme ? Bourrinage ? Choisissez le nom que vous voulez...
Quoiqu'il en soit, concrètement que fait-on ? Et bien on y va franco :
*601A : JMP $FF59 ! |
On est en Boot2, plus besoin de notre routine en $1600 et des brouettes, le truc se démerde tout seul maintenant. J'ai utilisé le $FF59 plutôt que le $FF65 pour récupérer la main en mode texte et non pas à l'aveugle derrière une page Hires. N'oubliez pas les commutateurs les plus utiles dès qu'on tripatouille des programmes faisant appel au mode Hires pour pouvoir repasser d'un mode à l'autre :
C050 / C051 : Texte / Graphique
C052 / C053 : Plein Ecran / Mixte
C054 / C055 : Page 1 / Page 2
C056 / C057 : LoRes / HiRes
On peut les utiliser directement sous Monitor...
Voyons voir le résultat :
*6000G * |
Bingo ! L'intro se déroule sous nos yeux ébahis et on récupère la main juste avant notre défi !
J'attire aussi votre attention sur un point crucial : l'observation. Après le sens du chasseur, l'oeil de lynx !
Il faut donc faire particulièrement attention à l'état du Disk. Face à un vrai Apple II, vu le bruit de la bête pas de souci, on le remarque. Face à un émulateur, c'est déjà plus discret. Prêtez donc attention à la petite loupiote verte sur AppleWin par exemple. Et que nous indique-t'elle ? En boot normal, on a le chargement de l'intro, nouveau chargement et apparition de l'image à signer.
Là on a récupéré la main juste après l'intro mais AVANT le chargement de ce qu'on peut supposer être l'image... Ce détail est particulièrement important pour la suite.
Bon inspection du résultat :
7B10- A9 20 LDA #$20 7B12- 8D 4F BA STA $BA4F 7B15- A9 21 LDA #$21 7B17- 8D 4B BA STA $BA4B 7B1A- A9 00 LDA #$00 7B1C- 8D 4C BA STA $BA4C 7B1F- A9 00 LDA #$00 7B21- 8D 4D BA STA $BA4D 7B24- A9 40 LDA #$40 7B26- 8D 4E BA STA $BA4E 7B29- 20 7D 7B JSR $7B7D |
On aime bien les adresses en $BA00 souvent signe d'une RWTS. Ça tombe bien, à priori y'a une image à charger. Il est drôle ici de voir que ceux qui auront lu l'article Fast Boot Maker sur ce même DEPME IV, auront un certain avantage pour repérer les infos intéressantes. Ceux qui n'ont rien lu n'ont qu'à utiliser le sens du chasseur !
Que nous apprend (entre autre) cette doc :
Utilisation de la routine RWTS du FastBoot
BA4B : Piste
BA4C : Secteur
BA4D : Buffer Lo
BA4E : Buffer Hi
BA4F : Nombre Secteurs à charger.
Si on compare avec le code du dessus, je crois que tout est maintenant clair, le programme va donc charger à partir de :
Piste : $21 ($BA4B) - Secteur : $00 ($BA4C), $20 ($BA4F) secteurs vers $4000 ($BA4D/$BA4E).
Quand on sait que $4000 c'est le début de la page 2 Hires, que $20 c'est 32, la taille classique en secteur d'une image Hires, on se dit que finalement on tient le bon bout !
Vérifions un peu ce qui se passe dans le JSR qui suit :
*7B7DL 7B7D- 2C 54 C0 BIT $C054 ; page 1 (pour qu'on ne voit pas ce qui se passe) 7B80- 2C E9 C0 BIT $C0E9 ; drive on 7B83- 20 6D B6 JSR $B66D ; appel RWTS 7B86- 2C E8 C0 BIT $C0E8 7B89- AD 05 40 LDA $4005 ; tiens tiens ! 7B8C- C9 CC CMP #$CC ; vérification de l'octet en $4005 7B8E- 4C B5 7B JMP $7BB5 *7BB5L 7BB5- D0 D2 BNE $7B89 ; on boucle si la valeur n'est pas OK ! 7BB7- 4C E9 7B JMP $7BE9 ; sinon on va charger la suite du prog et RTS ! |
On sait déjà qu'un octet de la page Hires sera vérifié (avant tout décodage). Voyons voir la suite, on reprend après le JSR $7B7D :
7B2C- A2 00 LDX #$00 7B2E- BD 00 7C LDA $A400,X 7B31- 9D 00 97 STA $BF00,X 7B34- E8 INX 7B35- D0 F7 BNE $7B2E 7B37- CE 30 7B DEC $7B30 7B3A- CE 33 7B DEC $7B33 7B3D- AD 33 7B LDA $7B33 7B40- C9 97 CMP #$97 7B42- D0 E8 BNE $7B2C 7B44- A0 00 LDY #$00 ; décryptage 7B46- B9 00 60 LDA $4000,Y ; de la page HIRES2 7B49- 59 01 60 EOR $4001,Y ; par EOR 7B4C- 4C 60 7B JMP $7B60 7B4F- EA NOP 7B50- A2 DB LDX #$DB 7B52- BD E5 7A LDA $7AE5,X ; modifie $7BC0+ 7B55- 49 A0 EOR #$A0 ; par décodage 7B57- 9D E5 7A STA $7AE5,X ; EOR 7B5A- E8 INX 7B5B- D0 F5 BNE $7B52 7B5D- 4C 91 7B JMP $7B91 7B60- 99 00 60 STA $4000,Y ; 7B63- C8 INY 7B64- D0 E0 BNE $7B46 7B66- EE 62 7B INC $7B62 7B69- EE 4B 7B INC $7B4B 7B6C- EE 48 7B INC $7B48 7B6F- AE 62 7B LDX $7B62 7B72- E0 60 CPX #$60 7B74- D0 D0 BNE $7B46 7B76- 4C 50 7B JMP $7B50 7B79- 00 BRK 7B7A- 00 BRK 7B7B- 00 BRK 7B7C- 80 ??? 7B91- A2 2F LDX #$2F 7B93- BD 51 9E LDA $9E51,X 7B96- 9D D0 03 STA $03D0,X 7B99- CA DEX 7B9A- 10 F7 BPL $7B93 7B9C- A9 60 LDA #$60 7B9E- 8D E4 9D STA $9DE4 7BA1- 8D E7 9D STA $9DE7 7BA4- 20 50 7C JSR $7C50 7BA7- A9 6C LDA #$6C 7BA9- EA NOP 7BAA- EA NOP 7BAB- EA NOP 7BAC- EA NOP 7BAD- EA NOP 7BAE- EA NOP 7BAF- A2 B7 LDX #$B7 7BB1- 9A TXS 7BB2- 4C 65 FF JMP $7BC0 ; saut vers partie décodée |
Que se passe-t'il donc ici ? On rencontre pas mal de JMP. Je ne pense pas que le but véritable soit de compliquer le code mais tout simplement, il a bien fallu que Kristo et Godfather fassent tenir leur code de décryptage (et autres joyeusetés) dans le code par défaut d'un FAST BOOT. Ce qui explique que les instructions sont éparpillées et reliées entre elles par des JMP.
Pour simplifier :
- en $7B44+ : On a un décryptage par un EOR de la page Hires avec elle-même :
selon l'algo : A = A EOR A+1 pour A de $4000 à $5FFF.
- en $7B50+ : On a un décryptage d'une zone de code. Pour voir ce qui s'y trouve il va donc falloir laisser le programme se décrypter et récupérer la main au moment où il saute en $7BC0 vers le code décrypté.
On modifie donc le $7BB2 en conséquence et on check ce qui doit se passer en $7BC0 :
*7BB2 : 4C 59 FF ; on patch le JMP $7BC0 *7B10G ; on relance la routine * ; et quand on récupère la main, on peut voir ce qui se passe en $7BC0 donc ! *7BC0L 7BC0- A2 00 LDX #$00 ; décryptage image part II 7BC2- BD 00 40 LDA $4000,X ; EOR fixe avec $EA 7BC5- 49 EA EOR #$EA ; pour tous les octets 7BC7- 9D 00 40 STA $4000,X ; de la page HIRES 2 7BCA- E8 INX 7BCB- D0 F5 BNE $7BC2 7BCD- EE C4 7B INC $7BC4 7BD0- EE C9 7B INC $7BC9 7BD3- AD C9 7B LDA $7BC9 7BD6- C9 60 CMP #$60 7BD8- D0 E8 BNE $7BC2 7BDA- 2C 55 C0 BIT $C055 ; Page 2 à l'affichage ! 7BDD- 2C 10 C0 BIT $C010 ; attente 7BE0- AD 00 C0 LDA $C000 ; d'une 7BE3- 10 FB BPL $7BE0 ; touche 7BE5- 4C 20 7C JMP $7C20 ; sortie vers la suite |
Et voilà, on y arrive. On a donc un nouveau décryptage de l'image avec cette fois :
B = B EOR $EA pour B de $4000 à $5FFF.
On a maintenant tout ce qu'il nous faut pour résoudre ce défi. Si si je vous assure...
Evidemment, avant de pouvoir signer l'image, il va déjà falloir commencer par la récupérer. Ici deux solutions :
- on sait où elle est sur le disque, on peut aller la lire en accès direct et faire un petit programme de décodage pour la décrypter et ainsi avoir une base pour la signature.
- on peut la récupérer dès maintenant à la hussarde ! Bah oui, le JMP $7C20 en $7BE5 a lieu quand tout est fini, il y a eu les deux décodages de l'image. Pourquoi ne pas coller un JMP $FF59 en $7BE5 et relancer en $7BC0 ?
Attention, n'oubliez pas les commutateurs dont je parlais plus haut car vous allez récupérez la main en page 2. Un C054 réglera le problème. Il ne reste plus alors qu'à booter un DOS 3.3 et à sauver l'image par un BSAVE PI.314116,A$4000,L$2000.
Vous avez bien entendu le droit de mettre un nom différent...
Une fois qu'on a l'image, on la signe avec un programme de dessin style Blazzing Paddles (d'où le PI. pour débuter le nom de l'image sinon B.P. ne retrouve pas ses petits !).
Et maintenant on va devoir créer le programme de codage inverse du double décodage utilisé par le défi, l'utiliser sur l'image, et replacer celle-ci sur le Disk, en accès direct bien sûr (cette fois, pas le choix).
<PUB> : n'oubliez pas qu'aussi bien pour la lecture que pour l'écriture, Accès Direct est à votre disposition ! (le monde est bien fait quand même...). </PUB>
Voici le source Merlin du programme de cryptage fait spécialement pour vous :
1 ORG $1500 2 3 BUF1 EQU $06 4 BUF2 EQU $08 5 6 LDA #$00 7 STA BUF1 8 LDA #$01 9 STA BUF2 10 LDA #$5F 11 STA BUF1+1 12 STA BUF2+1 13 14 LDX #$20 15 B1 LDY #$FF 16 B2 LDA (BUF1),Y 17 EOR #$EA 18 EOR (BUF2),Y 19 STA (BUF1),Y 20 DEY 21 CPY #$FF 22 BNE B2 23 DEC BUF1+1 24 DEC BUF2+1 25 DEX 26 BNE B1 27 RTS |
Le cryptage se fait en une seule passe (le EOR A+1 et le EOR $EA sont groupés). De plus le programme une fois compilé reste entièrement relogeable par un BLOAD,A$xxxx car il utilise l'adressage indexé en page zéro, évitant ainsi des DEC d'adresses fixes.
Et comme d'habitude le source n'est pas commenté ! Mais après avoir suivi la résolution de ce défi, je pense que tout doit être clair...
Vous pouvez retrouver sur cette image DSK :
- le programme Accès Direct (DIRECT)
- l'image originale décryptée (enfin celle déjà signée par d'autres dont Captain Crack et Lot !) (PI.DEFI)
- l'image signée par mes soins (PI.SIGNED)
- l'image signée par mes soins recryptée (PI.CRYPTED)
- le programme CRYPT et son source Merlin
- le programme DECRYPT et son source Merlin
- des trucs effacés mais qu'on peut voir quand même avec DiskFixer !
Et bien sûr voici le DSK de DEPME 4 complet avec l'image nouvellement signée !
Un dernier petit mot sur le Reset Vector dont je parlais au début. Tous ceux adorant faire du CTRL+RESET à tour de bras auront noté que DEPME IV reboote irrésistiblement, ne redonnant jamais la main.
On a vu que DEPME IV (en fait le FastBoot utilisé) modifie les vecteurs lors du BOOT0 mais aussi lors du BOOT1, par un astucieux INC $3F4 !
Pourquoi astucieux ? Et bien je vais vous le dire... (oulà...)
Le Vector Reset se caractérise par 3 adresses en page 03 :
$3F2 : adresse Lo du vecteur
$3F3 : adresse Hi du vecteur
cela définit l'adresse sur laquelle foncera l'Apple quand vous ferez CTRL+RESET !
MAIS uniquement si $3F4 (l'octet de "contrôle") contient le contenu de $3F3 EOR $A5 !
Donc pour faire en sorte que DEPME IV vous rende la main après un CTRL+RESET, il faudra modifier directement avec un éditeur de secteur le Boot0 (Piste 0/Secteur 0 donc) pour y mettre :
P00:S00:93 : A9 69 (LDA #$69 ->$3F2)
P00:S00:98 : A9 FF (LDA #$FF ->$3F3)
qui définit $FF69 en vecteur Reset
d'où (normalement) $FF EOR $A5 = $5A pour l'octet de contrôle !
Mais comme en $B600 cet octet sera incrémenté d'un, on va donc devoir mettre $5A-1 pour retomber sur nos pieds !
d'où :
P00:S00:03 : A9 59 (LDA #$59 -> $3F4)
Et voilà, vous devriez pouvoir interrompre ainsi DEPME à peu près quand vous voulez et reprendre la main !
Comme vous avez pu le remarquer, on peut très bien arriver à faire le défi sans avoir besoin de CTRL+RESET du tout. Mais cela peut éventuellement aider pour récupérer l'image décryptée sans même savoir où et comment elle l'a été !