Quel est le but de l'opcode nop?
Je passe par MSIL et je remarque qu'il y a beaucoup d'instructions nop. L'article MSDN dit qu'ils ne prennent aucune action et sont utilisés pour remplir l'espace si l'opcode est patché. Ils sont beaucoup plus utilisés dans les versions de débogage que dans les versions de publication. Je sais que ces types d'instructions sont utilisés dans les langages d'assemblage pour s'assurer qu'un opcode correspond à une limite de mot, mais pourquoi est-il nécessaire dans MSIL?
19 réponses
Les NOPs ont plusieurs objectifs:
- ils permettent au débogueur de placer un point d'arrêt sur une ligne même s'il est combiné avec d'autres dans le code généré.
- il permet au chargeur de corriger un saut avec un décalage cible de taille différente.
- il permet à un bloc de code d'être aligné à une limite particulière, ce qui peut être bon pour la mise en cache.
- il permet une liaison incrémentale pour écraser des morceaux de code avec un appel à une nouvelle section sans avoir à se soucier de la fonction globale changeant la taille.
Voici comment les nops sont utilisés par le débogage:
Les Nops sont utilisés par les compilateurs de langage (C#, VB, etc.) pour définir des points de séquence implicites. Ceux-ci indiquent au compilateur JIT où s'assurer que les instructions de la machine peuvent être mappées aux instructions IL.
L'entrée du blog de Rick Byer sur DebuggingModes.IgnoreSymbolStoreSequencePoints , explique quelques détails.
C # Place également Nops après les instructions d'appel de sorte que l'emplacement du site de retour dans la source soit plutôt l'appel que la ligne après l'appel.
Il fournit une opportunité pour les marqueurs basés sur la ligne (par exemple les points d'arrêt) dans le code où une version de release n'en émettrait aucune.
Il peut également rendre le code plus rapide, lors de l'optimisation pour des processeurs ou des architectures spécifiques:
Les processeurs utilisent depuis longtemps plusieurs pipelines qui fonctionnent à peu près en parallèle, de sorte que deux instructions indépendantes peuvent être dépassées en même temps. Sur un processeur simple avec deux pipelines, le premier peut prendre en charge toutes les instructions, tandis que le second ne prend en charge qu'un sous-ensemble. En outre, il y a des stands entre les pipelines quand on doit attendre le résultat d'une instruction précédente ce n'est pas encore terminée.
Dans ces circonstances, un NOP dédié peut forcer l'instruction suivante dans un pipeline spécifique (la première, ou non la première), et améliorer l'appariement des instructions suivantes de sorte que le coût du nop est plus qu'amorti.
Mec! No-op est génial! C'est une instruction qui ne fait que consommer du temps. Dans les âges sombres, vous l'utiliseriez pour faire des microadjustments dans le timing dans les boucles critiques ou plus important encore comme remplissage dans le code auto-modificateur.
Une utilisation classique pour eux est que votre débogueur puisse toujours associer une ligne de code source à une instruction IL.
Ils pourraient les utiliser à l'appui de modifier et continuer lors du débogage. Il fournit au débogueur de la place pour remplacer l'ancien code par un nouveau sans changer les décalages, etc.
Nop est essentiel dans la charge utile des exploits de débordement de tampon.
Comme l'a dit ddaa, les nops vous permettent de tenir compte de la variance dans la pile, de sorte que lorsque vous écrasez l'adresse de retour, elle saute au traîneau nop (beaucoup de nops d'affilée) et frappe le code exécutable correctement, plutôt que de sauter à un octet dans l'instruction qui n'est pas le début.
50 ans trop tard mais bon.
Les Nop sont utiles si vous tapez du code d'assemblage à la main. Si vous deviez supprimer du code, vous pourriez nop les anciens opcodes.
De même, vous pouvez insérer un nouveau code en écrasant un opcode et sauter ailleurs. Là, vous mettez les opcodes écrasés, et insérez votre nouveau code. Lorsque vous êtes prêt, vous sautez en arrière.
Parfois, il fallait utiliser les outils disponibles. Dans certains cas, c'était juste un éditeur de code machine très basique.
De nos jours, avec les compilateurs, les techniques n'ont plus aucun sens.
Dans la scène de fissuration logicielle, une méthode classique pour déverrouiller une application serait de patcher avec un NOP la ligne qui vérifie la clé ou l'enregistrement ou la période ou autres joyeusetés afin qu'elle ne fasse rien et continue simplement à démarrer l'application comme si elle était enregistrée.
J'ai aussi vu NOPs dans le code qui se modifie pour obscurcir ce qu'il fait en tant qu'espace réservé (veeery old copy protection).
Une utilisation un peu peu orthodoxe sont Nop-Slides , utilisé dans les exploits de débordement de tampon.
Dans un processeur pour lequel j'ai travaillé récemment (pendant quatre ans), NOP a été utilisé pour s'assurer que l'opération précédente s'est terminée avant le démarrage de l'opération suivante. Par exemple:
Valeur de charge à enregistrer (prend 8 cycles) nop 8 ajouter 1 à enregistrer
Cela s'est assuré que register avait la valeur correcte avant l'opération add.
Une autre utilisation était de remplir des unités d'exécution, telles que les vecteurs d'interruption qui devaient avoir une certaine taille (32 octets) car l'adresse pour vector0 était, disons 0, pour le vecteur 1 0x20 et ainsi de suite, le compilateur y met NOPs si nécessaire.
Ils permettent à l'éditeur de liens de remplacer une instruction plus longue (généralement saut en longueur) par une instruction plus courte (saut court). Le NOP prend l'espace supplémentaire - le code ne pouvait pas être déplacé car cela empêcherait les autres sauts de fonctionner. Cela se produit au moment du lien, de sorte que le compilateur ne peut pas savoir si un saut long ou court serait approprié.
Au moins, c'est l'une de leurs utilisations traditionnelles.
Ce n'est pas une réponse à votre question spécifique, mais dans l'ancien temps, vous pouviez utiliser un NOP pour remplir un slot de retard de branche , Si vous ne pouviez pas le remplir avec une instruction autrement utile.
Les compilateurs. net alignent-ils la sortie MSIL? J'imagine que cela pourrait être utile pour accélérer l'accès à L'IL... En outre, je crois comprendre qu'il est conçu pour être portable et que des accès alignés sont requis sur d'autres plates-formes matérielles.
Le premier assemblage que j'ai appris était SPARC donc je suis familier avec le slot de retard de branche, si vous ne pouvez pas le remplir avec une autre instruction, généralement l'instruction que vous alliez mettre au-dessus de l'instruction de branche ou incrémenter un compteur en boucles, vous utilisez un NOP.
Je ne suis pas familier avec la fissuration, mais je pense qu'il est courant d'écraser la pile en utilisant NOP, donc vous n'avez pas à calculer exactement où commence votre fonction malveillante.