L'idée de cette technique et mes premiers codes ont maintenant 2 ans et j'ai longtemps hésité avant de publier ma technique, sinon mes outils ne sont pas encore complètement au point donc je ne les publierai pas pour le moment (mais logiquement ça devrait venir ...). Le principe de ma technique, l'émulation minimaliste du code, est le suivant :

  1. le code du debugger est injecté dans le processus cible
  2. le flot d'exécution du processus est détourné vers le code du debugger qui sauvegarde l'état des registres et des flags et créé un 'eip virtuel' qui correspond à l'eip du processus au moment où son flot d'exécution a été détourné.
  3. pour faire un step into, le debugger va désassembler l'instruction courante du processus cible à l'aide d'un LDE afin de récupérer sa taille
  4. le debugger fait un desassemblage minimaliste de l'instruction afin de déterminer si cette instruction permet de se déplacer dans le code (si c'est un jmp / loop / call / retn)
    • si l'instruction est une instruction permettant de se déplacer dans le code, elle est émulée et l'eip virtuel est mis à jour ainsi que la pile en cas de call ou de retn
    • sinon l'instruction est copiée dans un buffer exécutable, les registres et les flags sont restaurés et l'instruction est exécutée, on ré-enregistre alors les registres et les flags et la valeur de l'eip virtuel est mise à jour en ajoutant la taille de l'instruction
  5. on peut alors recommencer autant de fois que l'on veut ;)

Les problèmes liés a cette technique :

  • Si l'on rencontre un sysenter, il faut modifier la valeur pushée dans la pile pour pouvoir reprendre la main au moment du retour en r3
  • Il faut bien prendre en compte les préfixes superflu pour pouvoir reconnaître efficacement les sauts et les appels aux fonctions ou le saut sera exécuté dans le buffer et plantera le processus a coup sur
  • Il ne faut pas oublier de hooker ou de contrôler de quelque manière que ce soit les exceptions du processus pour que la valeur de eip contenue dans le context sauvegardé corresponde a la valeur de l'eip virtuel et pour pouvoir, au retour, reprendre l'exécution dans le debugger et non dans le code du programme
  • Plus tordu mais aussi important : j'avais eu l'idée d'un anti-tracing à base de rep movs / stos qui s'auto-patch, ce qui permettait en cas de step-over au dessus de l'instruction de sauter plus loin dans le code et de détecter le break point, ou lancer un anti-debugg, dans le cas de l'utilisation de cet anti trace avec le système de copie de l'instruction dans le buffer, l'instruction sera bien patchée mais ne sera pas exécutée (c'est assez compliqué a comprendre, je ferai un petit POC dans un mini crack me) et il en résultera une mauvaise exécution du code.
  • L'utilisation de la combinaison pushfd / or dword [esp] , 0x100 / popfd pose problème, en effet le trap flag engendrera une exception sur l'instruction suivant le popfd, or le popfd étant copié dans un buffer, l'exception se déclenchera dans le code du debugger, il est donc nécessaire de vérifier que le trap flag n'est pas armé avant d'exécuter un popfd, si il est armé il faut alors le désarmé et le réarmé juste avant l'exécution de l'instruction suivante
  • Enfin dans le cas des nanomites ou autres techniques similaires qui se basent sur eip et des exceptions qui sont catchées par un processus debuggant ou en ring 0, l'eip ne correspondant pas a celui qu'il devrait être, la protection ne fonctionnera pas et le programme plantera royalement.


Les premiers problèmes se règlent relativement simplement en étoffant le désassemblage minimaliste de l'instruction mais le dernier problème n'est pas simple a résoudre et impliquerai le développement de drivers ou autre afin de pouvoir modifier la valeur de eip dans le contexte enregistré et récupérer la valeur modifiée par la protection, ce qui est tout de suite beaucoup moin facile :P

Bref, je me rends compte que ce post est surement difficile à comprendre (non parce que la technique est compliquée mais parce que j'ai du mal à bien m'exprimer et j'ai la flemme de faire des zoulis schémas) mais j'espere que vous aurez saisis l'intérêt de cette technique.

Je compte fournir un jour un petit debugger se basant sur cette technique avec les sources etc. mais ça n'est pas pour tout de suite, coder une bonne interface avec les fonctionnalités de base d'un bon debugger est un travail fastidieux et plus que rébarbatif mais je ne désespère pas, mes premiers codes sur ce projet ont maintenant 2 ans mais ça avance tout doucement ;)

Voili voilou, si cette technique vous intéresse ou si vous souhaitez des précisions ou encore si vous voulez m'aider (<3), viendez me voir sur irc (#fat @ irc.epiknet.org) ou écrivez moi un petit mail (baboonlyuaorg)

Pour la détente : http://www.bashfr.org/?7967 <- votez pour moua :P

[EDIT] après avoir fait relire mon post par tbowan il s'est avéré que cette technique a déja ete décrite par un barbus :'( en plus l'article est très bien ecris : http://arsouyes.org/phrack/phrack63/phrack63_0x0d.html Le technique a .... 2ans, j'aurai du publier plus tôt :D