Pourquoi ce code me permet-il de détecter un débogueur?

Pourquoi le code assembleur suivant est-il un outil anti-débogage?

l1: call l3 l2: ;some code l3: mov al, 0c3h mov edi, offset l3 or ecx, -1 rep stosb 

Je sais que C3h est RETN et je sais que stobs écrit la valeur dans al comme opcode en fonction du décalage dans edi et cela est fait pour ecx fois à cause de rep .

Je suis également conscient du fait que les stobs et stosw fonctionneront s’ils ont été pré-récupérés sur l’architecture intel comme leur format original.

Si nous exécutons le programme en mode débogué, la pré-extraction n’est pas pertinente et l’étiquette l2 s’exécutera (car elle est en une seule étape), sinon, s’il n’y a pas de débogueur, il sera ping entre l1 et l3.

    Lorsque le programme est débogué (c.-à-d. Une seule étape), la queue de prélecture est vidée à chaque étape (en cas d’interruption). Cependant, lorsqu’il est exécuté normalement, cela n’arrivera pas à rep stosb . Les processeurs plus anciens ne l’ont pas purgé même en cas d’écriture en mémoire dans la zone mise en cache, afin de prendre en charge le code auto-modifiable qui a été modifié à l’exception des rep movs et rep stosb . (IIRC a finalement été corrigé dans les processeurs i7.)

    C’est pourquoi, s’il y a un débogueur (simple étape), le code s’exécutera correctement et lorsque rep stosb sera remplacé par ret l2 sera exécuté. Lorsqu’il n’y a pas de débogueur, rep stosb continuera, puisque ecx est le plus grand possible, il finira par écrire quelque part qu’il n’est pas censé écrire et qu’une exception se produira.

    Cette technique anti-débogage est décrite dans cet article .

    La seule chose qu’un débogueur fait ici est un délai supplémentaire. Cela peut être la clé de la façon dont cela fonctionne. Le manuel d’Intel (et je suppose que AMD) indique explicitement que le code auto-modifiable n’est pas garanti “à fonctionner” à moins que le programme ne signale à la CPU que la ligne de cache contenant l’instruction modifiée a changé. Ceci permet de rendre la logique de lecture anticipée peu coûteuse; les concepteurs de puces ne veulent pas avoir de matériel qui teste continuellement que chaque octet d’une cachette d’instructions est toujours valide.

    Donc, je suppose que ce qui se passe avec les débogueurs est l1 appels l3, qui stocke un retour après le repstosb, et le retour est exécuté en raison des longs retards induits par le débogueur en pas à pas, forçant le cache après avoir modifié l3.

    Sans le débogueur, je devine l’instruction (non représentée) après l’exécution du stosb. Si c’était un saut vers “sans débogueur”, le succès du saut démontrerait qu’aucun débogueur pas à pas n’était utilisé.

    Si je trouvais ce code dans une application, je refuserais de l’exécuter.