Techniques anti-debugging et protection logicielle


<< Faux points d'arrêt


IV°) La protection par code checksum (vérification de la somme)

Explication de la technique
   En ouvrant un éxécutable avec un éditeur hexadécimal tel hexedit, on peut avoir le bytecode de notre programme. Autrement dit, le code complet en hexadécimal ou en décimal (ce qui donne les caractères que l'on peut voir en ouvrant un éxécutable avec un éditeur texte, qui est la correspondance ascii du bytecode). Le code complet n'étant qu'une succession de nombres (les opcodes), il nous est tout à fait possible d'en faire la somme. Le principe de la protection par code checksum est de vérifier que la somme de ces opcodes n'a pas été modifiée, autrement dit, que le programme tourne avec son code original. Pour ce, nous allons, à l'aide d'un programme simple en assembleur, tout d'abord vous montrer comment il est possible de contourner facilement des instructions de comparaison (cmp, cmpl) puis comment insérer un code de vérification de la somme des opcodes.

Exemple
   Nous allons étudier le programme suivant, toujours codé en assembleur AT&T pour Unix. Il n'est autre qu'un classique Hello, World, légèrement modifié pour illustrer notre point et également codé en version longue (d'une part pour compliquer un peu le code et décourager les crackers débutants, c'est une bonne habitude à prendre, et d'autre part car les instructions telles xor ou inc sont bien plus rapides que mov, mais ce sont des détails ;-) ) :
    .data   #declaration du segment des variables statiques initialisées

      bonjour: .string "Hello, World !\n"

      non_affiche: .string "Ce message ne peut pas être affiché\n"

    .text #declaration du segment code

      .global _start
       _start:

         xorl %eax,%eax   #Affichage de Hello, World !
         movb $4, %al
         xorl %ebx,%ebx
         inc %ebx
         movl $bonjour,%ecx
         xorl %edx,%edx
         mov $15,%edx
         int $0x80

         xorl %eax,%eax   #On mets eax à 0, puis on compare 1 et al, ce qui est donc toujours faux
         cmp $1,%al
         jne exit   #Ce Jump if Not Equal sera donc en théorie toujours réalisé

       naffiche:   #Affiche Ce message ne peut pas être affiché
         xorl %eax,%eax
         movb $4, %al
         xorl %ebx,%ebx
         inc %ebx
         movl $non_affiche,%ecx
         xorl %edx,%edx
         mov $36,%edx
         int $0x80

       exit:   #sortie
         xorl %eax,%eax
         xorl %ebx,%ebx
         inc %eax
         int $0x80
Pour ceux qui ne connaissent pas très bien l'assembleur, l'essentiel de ce code est expliqué dans la partie concernant le faux désassemblage. A noter que, comme indiqué, nous avons amplifié le code, par exemple, on aurait pu coder le label de sortie de façon plus simple :
       exit:   #sortie
         mov $1,%eax
         mov $0,%ebx
         int $0x80
Voici les sorties de ce programme en éxécution normale :
    $ gcc test.s -c -o test.o && ld test.o && ./a.out
    Hello, World !
    $
Comme prévu, le programme ne pouvant pas passer par le label naffiche (question de logique informatique), on a seulement un Hello, World ! classique qui s'affiche. Bien entendu, avec quelques connaissances légères en cracking, on sait facilement détourner le flux de ce programme. A l'aide d'un éditeur hexadécimal, on va donc modifier
    3C 01 (cmp $1,%al)
    75 15 (jne +15 <exit>)
en
    3C 00 (cmp $0,%al)
    75 15 (jne +15 <exit>)
ou
    3C 01 (cmp $1,%al)
    74 15 (je +15 <exit>)
Je pense que vous avez compris le but de la manoeuvre : soit on compare %al à 0, ce qui est toujours vrai et on n'utilise pas l'instruction Jump if Not Equal to exit, ou on compare %al à 1, ce qui est toujours faux et on n'utilise pas l'instruction Jump if Equal to exit). Vérifions le résultat de cette modification :
    $ hexedit a.out
    $./a.out
    Hello, World !
    Ce message ne peut pas être affiché
    $
Notre manipulation a donc parfaitement fonctionné et le cours du programme a été modifié, la présence d'un message qui n'aurait jamais pu être affiché en temps normal le prouve. Maintenant, nous allons protéger l'éxécutable par code checksum. En réalité, on le voit bien dans les deux modifications précédentes que la somme des opcodes sera décrémentée de 1 après l'édition de l'éxécutable. Voici le nouveau code protégé :
    .data   #declaration du segment des variables statiques initialisées

      bonjour: .string "Hello, World !\n"

      non_affiche: .string "Ce message ne peut pas être affiché\n"

      tentative_crack: .string "Tentative de crack !\nAbandon...\n"

    .text   #declaration du segment code

      .global _start
       _start:

         jmp checksum   #On commence par effectuer Checksum
         suite:   #on revient ici après le checksum s'il est positif

         xorl %eax,%eax
         movb $4, %al
         xorl %ebx,%ebx
         inc %ebx
         movl $bonjour,%ecx
         xorl %edx,%edx
         mov $15,%edx
         int $0x80

         xorl %eax,%eax
         cmp $1,%al
         jne exit

       naffiche:
         xorl %eax,%eax
         movb $4, %al
         xorl %ebx,%ebx
         inc %ebx
         movl $non_affiche,%ecx
         xorl %edx,%edx
         mov $36,%edx
         int $0x80

       exit:
         xorl %eax,%eax
         xorl %ebx,%ebx
         inc %eax
         int $0x80

       checksum:   #fonction checksum
         xorl %ebx,%ebx
         mov $checksum,%ecx
         sub $_start,%ecx
         mov $_start,%esi
       boucle:   #boucle d'addition des opcodes
         lodsb
         add %eax,%ebx
         loop boucle
         cmpl $5917,%ebx   #on a au préalable compté les opcodes et trouvé 5917
         jne crack   #Si le résultat de la boucle n'est pas 5917, on passe à <crack>
         jmp suite   #sinon on revient au début du programme

       crack:   #On avertit de la tentative de crack et on quitte
         xorl %eax,%eax
         movb $4, %al
         xorl %ebx,%ebx
         inc %ebx
         movl $tentative_crack,%ecx
         xorl %edx,%edx
         mov $32,%edx
         int $0x80
         jmp exit
Il ne nous reste plus qu'à vérifier que ce code checksum marche réellement :
    $ gcc checksum.s -c -o checksum.o && ld checksum.o -o checksum && ./checksum
    Hello, World !
    $ hexedit checksum
    $ ./checksum
    Tentative de crack !
    Abandon...
    $
Tout s'est bien déroulé, la protection n'entrave pas le fonctionnement du programme et empêche toute modification de la somme des opcodes. Cette technique est réellement puissante, surtout quand elle est combinée à d'autres techniques comme le faux désassemblage, ce qui rend très dur pour l'éventuel reverser ou cracker de modifier le programme à sa guise (puisque rien que le positionnement d'un breakpoint terminera l'éxécution du programme). Il doit alors, soit combler ses modifications par des instructions sans importance mais qui feront la même somme au final, ce qui n'est pas facile, soit réussir à déjouer le faux assemblage puis à détourner la fonction checksum, ce qui est aussi ardu. Par conséquent, cette protection est de loin la plus efficace que nous vous ayons exposé ici. A vrai dire, la seule protection qui est plus efficace est la protection par cryptage du code, que nous vous exposerons une fois la partie réseaux reconstruite.


<< Faux points d'arrêt



9 Commentaires
Afficher tous


Anonyme 19/02/14 10:44
Même si je comprends que c'est un site de hacking parler de cracking serait encore plus intéressant. Sinon super site.

onesimemoffo 29/11/12 23:47
Merci. C'est très gentil d'aider les autres.

FrizN 05/09/12 10:42
Rien ici n'est destiné à des personnes d'une certaine tranche d'âge. Des adolescents trouvent ça très facile et des adultes ne comprendront pas. Ca paraît logique que l'on ne puisse pas tout comprendre lorsqu'on débute dans un domaine. La persévérance est essentielle dans la sécurité, et cette section n'est pas la plus facile, c'est pour ça que je recommande *des bases en assembleur* dans la page introductive.

Anonyme 04/09/12 14:40
je vois que votre explication est un peu complexe a mon niveau et ça me donne le dégout d'y remettre les pieds. Une proposition : pourquoi ne pas céder les choses aussi pour les ado qui désirent tes explications ? merci




Commentaires désactivés.

Apprendre la base du hacking - Liens sécurité informatique/hacking - Contact

Copyright © Bases-Hacking 2007-2014. All rights reserved.