Le Maitre des Ames - Protection anti-copie

Réduire
X
 
  • Heure
  • Afficher
Tout nettoyer
nouveaux messages
  • ergonomy_joe
    Swordsman


    • août 2010
    • 245

    #1

    Le Maitre des Ames - Protection anti-copie

    En farfouillant dans les binaires de nos anciens jeux, on trouve parfois des choses interessantes. Par exemple, la fonction de protection anti-copie du jeu Le Maitre des Ames est exactement la meme que celle du jeu Le Necromancien. Ces deux jeux ont tous les deux ete ecrits en Turbo Pascal, et en se donnant un peu de mal (mais pas trop) on peut remonter au code source.... que voici:
    Code:
    {THE COPY PROTECTION ROUTINE FROM Le Maitre Des Ames}
    {is also found in Le Necromancien}
    
    FUNCTION C_2835:BOOLEAN;
    VAR
        x86regs:RECORD CASE INTEGER OF
            1:(AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags:INTEGER);
            2:(AL,AH,BL,BH,CL,CH,DL,DH:BYTE);
        END;
        sectorBuff:ARRAY[0..$1ff] OF CHAR;
        sectorNum,i,driveNum:INTEGER;
        driveFlag:ARRAY[0..1] OF BOOLEAN;
        strBuff:STRING[10];
    BEGIN
        driveFlag[0] := TRUE;
        driveFlag[1] := TRUE;
        strBuff := keyStr;
        {0 TO 0, maybe defined as constants ?}
        FOR driveNum := 0 TO 0
        DO BEGIN
            sectorNum := 0;
            x86regs.AX := 0;
            INTR($13, x86regs);
            {READ SECTORS}
            WHILE(driveFlag[driveNum] AND (sectorNum < 19))
            DO BEGIN
                x86regs.AX := $0201; {read one sector}
                x86regs.CX := $2700 + sectorNum; {track:39, sector:sectorNum}
                x86regs.DX := $0100 + driveNum; {head:1, drive:driveNum}
                x86regs.ES := SEG(sectorBuff);
                x86regs.BX := OFS(sectorBuff);
                INTR($13, x86regs);
                IF(LO(x86regs.Flags) MOD 2 = 1)
                THEN driveFlag[driveNum] := FALSE;
                sectorNum := sectorNum + 1
            END;
            {COMPARE STRINGS}
            FOR i := 0 TO LENGTH(strBuff) - 1
            DO BEGIN
                IF(sectorBuff[i + $1F8] <> strBuff[i + 1])
                THEN driveFlag[driveNum] := FALSE;
            END;
        END;
        {return value}
        C_2835 := driveFlag[0];
    END;
    Il y a cette constante, keyStr a declarer quelque part dans le source (elle vaut ' MASTER ' et '1379' pour nos deux jeux respectifs), mais a part ca cette fonction est totalement reutilisable... enfin bien qu'anachronique.
    Techniquement, elle va chercher a lire sur la piste 39 de la disquette les secteurs de 0 a 19 en utilisant les appels au bios (la fameuse int 13h). Puis a comparer les derniers octets du dernier secteur lu avec la constante keyStr, et ne renvoie la valeur vraie que si ils sont egaux.
    C'est schema de protection qui m'a l'air archi-repandu dans les jeux de cette epoque, mais je n'ai jamais vraiment compris comment ca marchait.
    Existe-t-il un programme special qui permette de formatter une piste avec le nombre de secteurs que l'on veut ? Puis d'y ecrire les donnees voulues ?
    Enfin voila, je part un peu dans toutes les directions, mais mon idees est que, connaissant les "coordonnees" de ces secteurs caches sur nos anciens floppy, il doit etre possible de recuperer leur contenu et de les stocker quelque part avec l'archive du jeu, histoire de se dire qu'on a vraiment archive toutes les donnees originales du jeu. non ?
    Je ne sais pas si ca interesse quelqu'un, ou bien si ce projet existe deja, mais je serais bien content de recupere le secteur cache des deux jeux en questions en tous cas.... si quelqu'un a toujours ses disquettes en etat de marche....
    Merci d'avance
  • stephh
    General

    • janvier 2009
    • 1721

    #2
    Es-tu sûr que ça lit bien 19 secteurs (0 à 18) et non 18 (0 à 17) ? A noter que si tu peux formater une piste avec le nombre de secteurs que tu veux avec la fonction 05h de ton interruption 13h (même si dans la pratique, tu te débrouilles pour avoir 9, 15 ou 18 secteurs pour une piste) ...

    En tout cas, avec un outil d'édition de disquette (par exemple PCTools 4.3 sous DOS), il est facile ensuite de naviguer parmi les différentes pistes et secteurs et d'écrire ce que tu veux où tu veux ...

    Steph

    Commentaire

    • ergonomy_joe
      Swordsman


      • août 2010
      • 245

      #3
      Ah oui dans mon message j'avais ecrit "de 0 a 19" mais en regardant le code, on voit bien que le secteur 19 n'est pas lu.
      Donc, autant pour moi, il fallait lire de "0..18".
      A part ca, ca m'a l'air correct. Alors est-ce que c'est ca l'astuce de la protection justement.
      En principe une disquette 5.1/4 de 360Ko est formattee avec 40 pistes de 18 secteurs.
      Si les pistes sont numerotees de 0 a 39 et les secteurs de 0 a 17, ce bout de code va en fait lire sequentiellement tous les secteurs de la derniere piste de la disquette, et enfin, lire un secteur supplementaire, le numero 18 !
      J'espere ne pas avoir trop dit d'aneries. Enfin il y aura certainement quelqu'un pour me corriger si c'est le cas.

      Et puis je reitere ma requete. Est-ce que quelqu'un possedant les originaux de ces jeux se sentirait de faire un dump de cette fameuse piste ? Je serais curieux de savoir si en dehors de la "cle" ces fameux secteurs comportent d'autres informations interessantes ....

      Commentaire

      • stephh
        General

        • janvier 2009
        • 1721

        #4
        Envoyé par ergonomy_joe Voir le message
        Ah oui dans mon message j'avais ecrit "de 0 a 19" mais en regardant le code, on voit bien que le secteur 19 n'est pas lu.
        Donc, autant pour moi, il fallait lire de "0..18".
        A part ca, ca m'a l'air correct. Alors est-ce que c'est ca l'astuce de la protection justement.
        En principe une disquette 5.1/4 de 360Ko est formattee avec 40 pistes de 18 secteurs.
        Si les pistes sont numerotees de 0 a 39 et les secteurs de 0 a 17, ce bout de code va en fait lire sequentiellement tous les secteurs de la derniere piste de la disquette, et enfin, lire un secteur supplementaire, le numero 18 !
        J'espere ne pas avoir trop dit d'aneries. Enfin il y aura certainement quelqu'un pour me corriger si c'est le cas.
        Si ton code en Turbo Pascal est bon, effectivement ça va lire un secteur supplémentaire sur la dernière piste, secteur qui contient la clé (8 caractères au maximum) ...

        Et puis je reitere ma requete. Est-ce que quelqu'un possedant les originaux de ces jeux se sentirait de faire un dump de cette fameuse piste ? Je serais curieux de savoir si en dehors de la "cle" ces fameux secteurs comportent d'autres informations interessantes ....
        Je n'ai pas les originaux de ces jeux, mais je doute qu'il y ait autre chose sur ce secteur "bonus" que la fameuse clé car c'était déjà une protection "chiante" à l'époque pour imaginer y mettre au chose dessus (une partie du code par exemple) ...

        Mais comme toi, je serais curieux de voir une image exacte de la disquette pour voir s'il y avait vraiment quelque chose d' "utile" ou un message disant je ne sais pas quoi ...

        Steph

        Commentaire

        • ergonomy_joe
          Swordsman


          • août 2010
          • 245

          #5
          Alors il ne reste plus qu'a attendre que quelqu'un:
          1. possedant les disquettes originales
          2. un lecteur adapte (5.1/4 dans notre cas)
          3. pret a tenter l'experience

          passe par ici et nous fasse part de son interet

          Par ailleurs, j'ai vu un exemple assez elegant de "crack" qui consiste a ecrire un petit programme, genre .com, qui redirige des interruptions systeme (21h dans l'exemple, mais on peut imaginer facilement 13h dans notre cas) vers son propre code avant de lancer l'executable du jeu.
          En l'adaptant, ca permettrait d'intercepter les tentatives de lecture de secteurs caches et de renvoyer les valeurs attendues sans avoir a toucher a l'executable. Ca pourrait etre sympa d'avoir ce genre d'approche "non invasive" pour faire sauter les protections en question, non?
          Si ca interesse quelqu'un je veux bien tenter sur les deux jeux en question... pour commencer.

          Commentaire

          • stephh
            General

            • janvier 2009
            • 1721

            #6
            Envoyé par ergonomy_joe Voir le message
            Par ailleurs, j'ai vu un exemple assez elegant de "crack" qui consiste a ecrire un petit programme, genre .com, qui redirige des interruptions systeme (21h dans l'exemple, mais on peut imaginer facilement 13h dans notre cas) vers son propre code avant de lancer l'executable du jeu.
            En l'adaptant, ca permettrait d'intercepter les tentatives de lecture de secteurs caches et de renvoyer les valeurs attendues sans avoir a toucher a l'executable. Ca pourrait etre sympa d'avoir ce genre d'approche "non invasive" pour faire sauter les protections en question, non?
            Si ca interesse quelqu'un je veux bien tenter sur les deux jeux en question... pour commencer.
            Tu as en fait 2 possibilités : soit faire un résident indépendant que tu lances une fois avant et une fois après le jeu (parce que si tu détournes l'interruption 13h, il peut t'arriver de sacrées bêtises si tu ne remets pas tout en place), soit tu fais carrément un "loader" qui va charger le jeu et modifier son contenu en mémoire ...

            Personnellement, je préfère de loin la 2ème solution, surtout que là, il suffit juste de "raccourcir" ta fonction avec un "jmp" approprié de façon à ce qu'elle devienne un truc comme ça :
            Code:
            FUNCTION C_2835:BOOLEAN;
            VAR
                x86regs:RECORD CASE INTEGER OF
                    1:(AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags:INTEGER);
                    2:(AL,AH,BL,BH,CL,CH,DL,DH:BYTE);
                END;
                sectorBuff:ARRAY[0..$1ff] OF CHAR;
                sectorNum,i,driveNum:INTEGER;
                driveFlag:ARRAY[0..1] OF BOOLEAN;
                strBuff:STRING[10];
            BEGIN
                driveFlag[0] := TRUE;
                {return value}
                C_2835 := driveFlag[0];
            END;
            Comme tu peux le remarquer, il n'y aura plus d'accès au lecteur de disquette pour vérifier ta dernière piste ...

            D'un point de vue "pratique", le plus "simple" pour un "loader" est de détourner l'interruption vidéo (10h, fonction 00h) car elle n'est pratiquement utilisée qu'une seule fois dans tout le jeu pour définir le mode vidéo, et surtout, quand elle est appelé, le jeu est généralement déjà décompacté et est donc très "facile" à modifier ...

            Il faudrait que je remette la main sur mes disquette 3.5" (soit ce week-end;, soit dans 2 semaines), car je sais que j'ai un "modèle" que tu peux ensuite facilement adapter à n'importe quel jeu une fois que tu as compris le principe ... Je le posterai donc sur ce message si cela t'intéresse (et si ce n'est pas interdit par les modérateurs) ...

            Steph

            Commentaire

            • ergonomy_joe
              Swordsman


              • août 2010
              • 245

              #7
              Bon et bien finalement voici un exemple pour Bumpy.

              Code:
              cSize_p	EQU (OFFSET lastByte - OFFSET start + 100h + 0Fh)/10h
              ;########################################
              CODE	SEGMENT PUBLIC
              	ASSUME CS:CODE,DS:CODE
              	org 100h
              ;----------------------------------------
              start:	;-- set stack
              	MOV	SP,OFFSET lastByte
              	MOV	BX,cSize_p	;requested size in para
              	MOV	AH,4Ah	;setblock
              	INT	21h
              	;-- backup int 13h
              	MOV	AX,3513h
              	INT	21h
              	MOV	WORD PTR oldVector,BX
              	MOV	WORD PTR oldVector+2,ES
              	;-- set new int 13h
              	MOV	DX,OFFSET newRoutine
              	MOV	AX,2513h
              	INT	21h
              	;--
              	PUSH	CS
              	POP	ES
              	MOV	paramBlock+4,CS
              	MOV	paramBlock+8,CS
              	MOV	paramBlock+0Ch,CS
              	MOV	DX,OFFSET fileName
              	MOV	BX,OFFSET paramBlock
              	MOV	AX,4B00h	;load & execute program
              	INT	21h
              	;-- restore original int 13h
              	LDS	DX,CS:oldVector
              	MOV	AX,2513h
              	INT	21h
              	;-- terminate program
              	MOV	AX,4C00h
              	ADC	AL,0
              	INT	21h
              ;----------------------------------------
              newRoutine	PROC FAR
              	CMP	AH,2
              	JE	ok
              	JMP toOldVector
              ok:	;--
              	PUSHF
              	PUSH	AX
              	PUSH	BX
              	PUSH	CX
              	PUSH	DX
              	PUSH	SI
              	PUSH	DI
              	PUSH	DS
              	;--
              	MOV	AX,CS
              	MOV	DS,AX
              	;-- for bumpy
              	MOV	BYTE PTR ES:[BX+1feh],0
              	MOV	BYTE PTR ES:[BX+1ffh],4dh
              	;-- --
              	POP	DS
              	POP	DI
              	POP	SI
              	POP	DX
              	POP	CX
              	POP	BX
              	POP	AX
              	POPF
              	;-- --
              	MOV	AH,0
              	CLC
              	RETF2
              	;-- --
              toOldVector:	db 0EAh	;JMP xxxx:xxxx
              oldVector	dd 0
              	;-- --
              newRoutine	ENDP
              ;----------------------------------------
              fileName	db 'BUMPY.EXE',0
              paramBlock	dw 0		;ptr to environment segment
              	dw 80h,?	;ptr to command line tail
              	dw 5Ch,?	;ptr to fcb 1
              	dw 6Ch,?	;ptr to fcb 2
              ;----------------------------------------
              ;STACK
              ;----------------------------------------
              	db 6dh dup(?)
              lastByte	EQU THIS BYTE
              ;----------------------------------------
              CODE	ENDS
              ;########################################
              END	start
              Alors c'est pas forcement tres lisible comme code (je touche pas des masses en assembleur) mais en gros voila ce que ca fait:
              - redirection de l'interruption 13h (fonctions floppy du BIOS) vers une routine maison
              - lancement de l'executable du jeu vise

              Puis concernant la routine elle-meme, si elle est appelee avec une valeur du registre AH differente de 2 (c'est-a-dire "lecture de secteur(s)") on passe la main a la routine bios originale.
              Et donc enfin, si on est bien dans le cadre d'une lecture de secteur, comme la routine de BUMPY est assez simple, on ne cherche meme pas a verifier le numero de piste, ou de secteur, on ne fait qu'ecrire un 0 et un 0x4d aux offsets 0x1fe et 0x1ff du buffer passe en parametre.
              Evidemment, il faut retravailler cette routine dans le cas d'un autre jeu. Mais le fait est que ca marche, et que ca permet de jouer sans alterer le fichier original, puisque toute l'astuce se passe en "runtime".

              modif du 2010/12/28: oups, je viens de me rendre compte d'une erreur stupide au retour de l'INT 13h. J'utilisais IRET, mais en fait IRET va retablir le registre flag tel qu'il etait au moment de l'appel. Le CLC est donc rendu inutile.
              A la place, on utilise RETF 2 qui va tout simplement ignorer la valeur du registre flag empilee.
              Dernière modification par ergonomy_joe, 28 décembre 2010, 03h17.

              Commentaire

              • karamoon
                Barbarian


                • janvier 2006
                • 343

                #8
                Bonjour,

                je vais faire un peu de hors sujet, mais j'ai essayé de reconstruire le code source du Maitre des âmes il n'y a pas très longtemps sans succès. Pouvez-vous m'indiquer comment vous avez procédé, ça m'intéresserait beaucoup.

                Merci d'avance.

                Commentaire

                • ergonomy_joe
                  Swordsman


                  • août 2010
                  • 245

                  #9
                  salut karamoon,

                  En fait pour reconstruire le source, comme je n'ai pas trouve d'outil qui decompile automatiquement un binaire Turbo Pascal 3.xx, j'y suis alle "a la main".
                  .desassembler le binaire
                  .reperer les fonctions de la librairie pascal
                  .reperer les fonctions "utilisateurs"
                  .reperer la topographie du segment de donnees
                  .traduire en code pascal
                  .affiner

                  En regle general, les binaires TP3 sont assez facile a decompiler de cette maniere (enfin il faut un peu de temps quand meme) et ca ne doit pas etre trop dur de creer un outil qui le fasse automatiquement, mais la ca depasse mes competences.

                  Du coup j'ai un code source "reconstruit" du Maitre des Ames et de Zombi sur mon disque dur. Ca pourrait etre interessant de les poster quelquepart, mais ou ?

                  Commentaire

                  • karamoon
                    Barbarian


                    • janvier 2006
                    • 343

                    #10
                    Effectivement c'est plus compliqué que je le pensais et ça ne me surprend pas que je n'ai pas réussi.
                    Ceci-dit je suis curieux de voir le résultat, tu peux p-e poster ton travail sur Megaupload ou alors je te donne mon adresse en MP (si c'est possible).

                    Dans tous les cas merci de ta réponse.

                    Commentaire

                    • GT400
                      Manic Miner


                      • juin 2004
                      • 11522

                      #11
                      Hors sujet :

                      Ergonomy Joe (ou les autres), est-ce que tu t'y connais un peu en assembleur Z80 (sur CPC) ?
                      Il y a un truc planqué dans le code d'un de mes jeux cultes ("Sorcery+") auquel je n'ai toujours pas trouvé de réponse...

                      As the mist clears, the eerie image of a forest forms in front of you. To the east, a vast plain extends towards the horizon. Westward howewer, in the thick of the forest, a thousand pairs of eyes pierce the mist, glaring despondently back at you.

                      Commentaire

                      • stephh
                        General

                        • janvier 2009
                        • 1721

                        #12
                        Envoyé par ergonomy_joe Voir le message
                        Evidemment, il faut retravailler cette routine dans le cas d'un autre jeu. Mais le fait est que ca marche, et que ca permet de jouer sans alterer le fichier original, puisque toute l'astuce se passe en "runtime".
                        C'est à peu près le genre de "loader" dont je parlais (modification d'une interruption, lancement du jeu, puis restitution de l'interruption d'origine) et dont effectivement on peut se servir pour chaque jeu (en modifiant juste le code de l'interruption voire le numéro de l'interruption). En plus, on peut profiter de ce genre de "loader" pour installer un "trainer" (même si sur un jeu comme "Le maître des âmes", je ne vois pas trop quoi). Par contre, effectivement, la modification de l'interruption est très sommaire ici (on vérifie juste quelle fonction est appelée).


                        Envoyé par GT400 Voir le message
                        Hors sujet :

                        Ergonomy Joe (ou les autres), est-ce que tu t'y connais un peu en assembleur Z80 (sur CPC) ?
                        Il y a un truc planqué dans le code d'un de mes jeux cultes ("Sorcery+") auquel je n'ai toujours pas trouvé de réponse...
                        Hors sujet :

                        Peux-tu préciser quoi comme genre de truc ? Un "cheat code" à saisir ? Du texte caché ? Autre ?



                        Steph
                        Dernière modification par stephh, 13 janvier 2011, 00h21.

                        Commentaire

                        • GT400
                          Manic Miner


                          • juin 2004
                          • 11522

                          #13
                          Hors sujet :

                          Eh bien voilà : (désolé pour le HS, on fera un autre topic si ça s'éternise)

                          Etant un fan hardcore de ce jeu depuis sa sortie, j'ai fini par le fouiller avec un éditeur hexa/ascii il y a une dizaine d'années quand j'y ai pas mal rejoué sous émulateur avec mon précédent PC. J'ai découvert quelques petites choses cachées. J'ai découvert par exemple qu'en écrivant certains mots (quand on inscrit son nom au tableau des High Scores) on avait droit à une réponse en quelques mots (en écrivant par exemple "wank" (qui signifie "se branler") on obtenait en réponse "Do it yourself" ) et d'autres allusions/private jokes des programmeurs. Mais il y a eu un autre truc qu'on peut lire en ascii dans le code, un truc que je n'ai jamais lu dans le jeu : "Cheat!...but you won't get far". Ca doit à mon avis correspondre à ce qui s'affiche quand on tape un cheat code... mais ce dernier reste totalement inconnu. Et c'est en fait ça que j'aimerais savoir.
                          (Je connais le cheat code de la version 16bits (sortie 3 ans après) mais il n'a à mon avis rien à voir avec ce cheat code inconnu. (je l'ai testé sur la version CPC et ça n'a rien donné))
                          (le moyen le plus simple de voir de quoi je parle, pour ceux que ça intéresse, est de lancer le jeu sur Caprice (émulateur CPC), de faire un snapshot, et de l'éditer avec par exemple Hexworkshop)

                          As the mist clears, the eerie image of a forest forms in front of you. To the east, a vast plain extends towards the horizon. Westward howewer, in the thick of the forest, a thousand pairs of eyes pierce the mist, glaring despondently back at you.

                          Commentaire

                          • stephh
                            General

                            • janvier 2009
                            • 1721

                            #14
                            Envoyé par GT400 Voir le message
                            Hors sujet :

                            Eh bien voilà : (désolé pour le HS, on fera un autre topic si ça s'éternise)
                            Hors sujet :

                            Prépare-toi à créer un sujet, car ça va être un peu long (surtout si je dois mettre du code assembleur Z80 commenté) ... Et vu le peu de temps libre actuellement, compte une semaine pour au moins le début du détail ...

                            2 choses :

                            - Il ne s'agit pas de "Sorcery" mais de "Sorcery+".
                            - Comment fais-tu pour simuler le joystick au clavier sur CaPriCe32 ? J'en ai besoin pour démarrer une partie et jouer de quoi faire un score.



                            Steph

                            Commentaire

                            • GT400
                              Manic Miner


                              • juin 2004
                              • 11522

                              #15
                              Oui, il s'agit bien de Sorcery+. (Pour le joy sur Caprice, j'ai mis un lien dans l'autre topic que je viens de créer)

                              Ok. Je viens de faire un autre sujet. Merci de pouvoir jeter un oeil. (et aux autres qui pourront) Mais en tout cas prends ton temps, ce truc n'est pas très important. Ce jeu a maintenant 26 ans, donc un mois, six mois ou un an à attendre de plus pour percer le secret ne changera pour moi pas grand chose.

                              The new topic : http://www.abandonware-forums.org/sh...t-code-secret-...
                              Dernière modification par GT400, 14 janvier 2011, 13h29.
                              As the mist clears, the eerie image of a forest forms in front of you. To the east, a vast plain extends towards the horizon. Westward howewer, in the thick of the forest, a thousand pairs of eyes pierce the mist, glaring despondently back at you.

                              Commentaire

                              Chargement...