Techniques anti-debugging et protection logicielle


<< Le faux désassemblage Protection par code checksum >>


III°) Les faux points d'arrêt (breakpoints)

Explication de la technique
   Cette technique s'appuie sur les différences d'éxécution entre un programme seul et un programme dans un débuggueur. Une différence essentielle est l'interprétation du caractères int 3, en hexadécimal, 0xCC. Ce caractère constitue les fameux breakpoints. Ces points d'arrêt sont associés au signal SIGTRAP. Quand un débuggueur lit un caractère 0xCC, il mets le programme en pause (ce qui permet de l'analyser à l'instant X). Quand un programme reçoit un SIGTRAP, il effectue l'action associée au signal (par défaut, il quitte). Le principe de cette méthode est simple : on modifie l'action effectuée par un SIGTRAP. Donc, un programme éxécuté normalement va suivre cette action, alors qu'un programme en cours de debug va se mettre en pause, puis continuer (et être piégé dans une partie du programme qui lui sera bien sûr réservée).

Illustration
   Voici un exemple d'utilisation des faux breakpoints. Le programme suivant est le même que celui de la partie ptrace, légèrement modifié :
    //auth.cpp : Exemple de l'utilisation d'un faux breakpoint

    #include <signal.h>

    #include <iostream>
      using std::cout;
      using std::cin;
      using std::endl;

    #include <string>
      using std::string;

    #define MDP "exemple_pass"

    void authentification(int signo) {
      string pass;

      cout << "Authentification requise\nMot de passe :\t";
      cin >> pass;   //Capture clavier

      if (pass == MDP)   //Si la chaîne rentrée au clavier est pareil que la chaîne MDP définie plus tôt
      cout << "Authentification réussie, bienvenue dans la suite du programme" << endl;

      else cout << "Echec de l'authentification\nAbandon..." << endl;   //Sinon

      exit(0);
    }

    int main() {

      signal(SIGTRAP, authentification);   //réception de SIGTRAP => authentification()
      __asm__("int3");   //On pose un breakpoint qui va envoyer un SIGTRAP

      return 1;   //On quitte en état d'erreur
    }
Le return 1; va juste nous permettre de prouver que le débugger a terminé dans cette partie du programme, contrairement à ce qui se passe en temps normal. En réalité, on utilise souvent ce genre de piège pour faire un faux clône de la suite réell du programme. Le cracker va essayer de la cracker sans comprendre pourquoi le vrai programme ne se soumet pas à ses ordres. Cette technique s'inscrit plutôt dans une optique de découragement du reverser. Voici un exemple d'utilisation du programme puis ce qui se passe en utilisant gdb :
    $ g++ auth.cpp -o auth && ./auth
    Authentification requise
    Mot de passe : testdepass
    Echec de l'authentification
    Abandon...
    $ ./auth
    Authentification requise
    Mot de passe : exemple_pass
    Authentification réussie, bienvenue dans la suite du programme
    $ gdb -q auth
    Using host libthread_db library "/lib/libthread_db.so.1".
    (gdb) r
    Starting program: /home/SeriousHack/auth
    Failed to read a valid object file image from memory.

    Program received signal SIGTRAP, Trace/breakpoint trap.
    0x0804894c in main ()
    (gdb) c
    Continuing.

    Program exited with code 01.
Comme prévu, bien que tout marche parfaitement en utilisation normale, le programme quitte tout de suite avec un code de sortie 01, ce qui correspond à ce que nous avons codé. Cette protection étant aisément contournable, on prend l'habitude de la protéger par faux désassemblage et par checksum, ce que nous nous proposons d'étudier maintenant.


<< Le faux désassemblage Protection par code checksum >>



3 Commentaires

Anonyme 18/10/13 16:18
Je....comprends...rien...

FrizN 07/11/12 07:41
A priori la majorité des assembleurs connaissent int3, c'est le cas de FASM que vous citez par exemple. Si jamais ce n'est pas le cas, int3 c'est l'opcode 0xcc pour x86. Il suffit donc de rajouter quelque chose du genre "db 0xcc".

Sebastien 01 06/11/12 22:30
Salut , juste une question :

Si dans le codage assembleur "pur" , le compilateur genre FASM , TASM MASM .. ne va pas prendre compte la syntax "int3"

Et dans les principes théoriques de la compilation C
à la ligne __asm__("int3")
comment le compilateur va t-il créer son code "natif" avec cela ?

Enfin en gros , ( j'ai pas encore testé ) , mais comment intégrer "int3" dans les compilateur asm ?




Commentaires désactivés.

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

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