Question:
Quel est le but de «mov edi, edi»?
Mellowcandle
2013-03-25 14:56:00 UTC
view on stackexchange narkive permalink

Je vois cette instruction au début de plusieurs programmes Windows. Elle copie un registre sur lui-même, donc fondamentalement, cela agit comme un nop . À quoi sert cette instruction?

L'essence: C'est un NOP à deux octets. Vous pouvez donc patcher deux octets de manière atomique sans que le processeur ne charge une instruction incomplète / incorrecte lorsqu'il tente d'exécuter cette partie du code pendant que vous la modifiez.
Dans x86-64 `mov edi, edi` n'est pas un NOP. Dans x86-64, il met à zéro les 32 premiers bits de `rdi`. Dans le code 32 bits «mov edi, edi» peut être utilisé comme NOP.
Trois réponses:
#1
+68
QAZ
2013-03-25 15:03:13 UTC
view on stackexchange narkive permalink

Raymond Chen (Microsoft) a publié un article sur ce blog en détail:

https://devblogs.microsoft.com/oldnewthing/20110921-00/?p=9583

En bref, il s'agit d'un ajout au moment de la compilation appliqué afin de prendre en charge les correctifs à chaud au moment de l'exécution, de sorte que la fonction peut avoir les deux premiers octets écrasés par une instruction JMP pour rediriger l'exécution vers un autre morceau de code.

Vous devriez probablement ajouter une note sur les 5 octets vides précédant l'instruction `mov edi, edi`.
Pourquoi pas un vrai NOP 2 octets comme «66 90»? Ce serait plus efficace: aucun uop back-end nécessaire, aucune latence supplémentaire pour l'EDI (au cas où cela compte), aucun registre physique nécessaire pour renommer la sortie. Peut-être est-ce censé être une «signature» que les outils peuvent reconnaître comme n'étant pas naturelle, sauf dans le code hotpatch?
@PeterCordes: Raymond Chen explique que https://devblogs.microsoft.com/oldnewthing/20130102-00/?p=5663 "la décision d'utiliser MOV EDI, EDI comme instruction NOP à deux octets est venue après consultation des fabricants de processeurs pour leur recommandations pour le meilleur NOP à deux octets "
@BenSchwehn: Huh, probablement cette décision remonte aux jours P5 Pentium, où un préfixe «66» faisait que l'instruction prenait un cycle supplémentaire pour décoder. C'est malheureux pour les processeurs ultérieurs à partir de P6 et au-delà. Il est également regrettable que ce soit un NOP, plutôt que d'être éventuellement une instruction utile comme un encodage à 2 octets de `push ebp` pour les fonctions qui utilisent un pointeur de trame. (Utiliser la forme `push r / m32` avec un octet modrm, pas la forme courte 1 octet.) Mais c'est un peu moins simple à gérer, et a besoin d'une alternative pour ne pas pessimiser les fonctions qui ne veulent rien pousser.
#2
+19
peter ferrie
2013-03-30 03:59:49 UTC
view on stackexchange narkive permalink

Il est prévu de sauter à un emplacement spécifique , 5 octets avant l'instruction mov. De là, vous avez 5 octets qui sont destinés à être modifiés en un saut en longueur vers un autre endroit dans l'espace mémoire 32 bits. Notez que lors du patch à chaud, ce saut de 5 octets doit être placé en premier, puis le mov peut être remplacé. Dans l'autre sens, vous risquez que le mov-jmp remplacé s'exécute en premier, et saute aux 5 octets de tout ce qui se trouve là (tout est nops par défaut, mais on ne sait jamais).

[l'addition suit ]

En ce qui concerne l'écriture du saut de 5 octets - il y a aussi le problème qu'il n'y a qu'une seule instruction qui vous permettra d'écrire plus de 4 octets de manière atomique - cmpxchg8b, et ce n'est pas une instruction idéale à cet effet. Si vous écrivez d'abord 0xe9, puis un dword, vous avez une condition de concurrence si 0xe9 est exécuté avant de placer le dword. Encore une autre raison d'écrire d'abord le saut en longueur.

Il s'agit généralement de NOP ou INT3.
Oui, mais dans le cas des INT3, vous ne voulez certainement pas exécuter cela par accident.
Et dans le cas où la fonction est * déjà * détournée, écrire d'abord l'adresse de la cible de saut de 4 octets remplacera atomiquement tout ce que `rel32` avait le` jmp` précédent. (En supposant que le dword est aligné sur 4 octets, ce qu'il sera si les fonctions sont alignées sur 8 ou 16 octets. Il se termine au début d'une fonction.)
#3
+8
rebel87
2015-10-03 12:54:27 UTC
view on stackexchange narkive permalink

Courtsey Présentation de Hotpatching and the Rise of Third-Party Patches à BlackHat USA 2006 par Alexander Sotirov

Qu'est-ce que le Hotpatching? Hotpatching est une méthode pour modifier le comportement d'une application en modifiant son code binaire à l'exécution. C'est une technique courante avec de nombreuses utilisations:

• débogage (points d'arrêt logiciel)

• instrumentation d'exécution

• accrocher les fonctions de l'API Windows

• modification de l'exécution ou ajout de nouvelles fonctionnalités aux applications source fermées

• déploiement des mises à jour logicielles sans redémarrage

• correction des vulnérabilités de sécurité

Hotpatches sont générés par un outil automatisé qui compare les binaires d'origine et corrigés. Les fonctions qui ont changé sont incluses dans un fichier avec une extension .hp.dll.Lorsque la DLL du correctif est chargée dans un processus en cours, la première instruction de la fonction vulnérable est remplacée par un saut vers le correctif.

Le L'option du compilateur / hotpatch garantit que la première instruction de chaque fonction est une instruction mov edi, edi qui peut être écrasée en toute sécurité par le hotpatch. Les anciennes versions de Windows ne sont pas compilées avec cette option et ne peuvent pas être corrigées à chaud.



Ce Q&R a été automatiquement traduit de la langue anglaise.Le contenu original est disponible sur stackexchange, que nous remercions pour la licence cc by-sa 3.0 sous laquelle il est distribué.
Loading...