Nombres et opérateurs MASM
Cette rubrique décrit l'utilisation de la syntaxe des expressions Microsoft Macro Assembler (MASM) avec les outils de débogage Windows.
Le débogueur accepte deux types différents d'expressions numériques : les expressions C++ et les expressions MASM. Chacune de ces expressions suit ses propres règles de syntaxe pour l'entrée et la sortie.
Pour plus d'informations sur le moment où chaque type de syntaxe est utilisé, veuillez consulter Évaluation des expressions et ? (Évaluer l'expression).
Dans cet exemple, la commande ? affiche la valeur du registre du pointeur d'instruction en utilisant l'évaluateur d'expressions MASM.
0:000> ? @rip
Evaluate expression: 140709230544752 = 00007ff9`6bb40770
Définir l'évaluateur d'expressions sur MASM
Utilisez .expr (Choisir l'évaluateur d'expressions) pour voir quel est l'évaluateur d'expressions par défaut et le changer pour MASM.
0:000> .expr /s masm
Current expression evaluator: MASM - Microsoft Assembler expressions
Maintenant que l'évaluateur d'expressions par défaut a été changé, la commande ? (Évaluer l'expression) peut être utilisée pour afficher les expressions MASM. Cet exemple ajoute la valeur hexadécimale de 8 au registre rip.
0:000> ? @rip + 8
Evaluate expression: 140709230544760 = 00007ff9`6bb40778
La référence du registre de @rip est décrite plus en détail dans Syntaxe des registres.
Nombres dans les expressions MASM du débogueur
Vous pouvez utiliser des nombres dans les expressions MASM en base 16, 10, 8 ou 2.
Utilisez la commande n (Définir la base numérique) pour définir la base par défaut sur 16, 10 ou 8. Tous les nombres sans préfixe sont alors interprétés dans cette base. Vous pouvez remplacer la base par défaut en spécifiant le préfixe 0x (hexadécimal), le préfixe 0n (décimal), le préfixe 0t (octal) ou le préfixe 0y (binaire).
Vous pouvez également spécifier des nombres hexadécimaux en ajoutant un h après le nombre. Vous pouvez utiliser des lettres majuscules ou minuscules dans les nombres. Par exemple, « 0x4AB3 », « 0X4aB3 », « 4AB3h », « 4ab3h » et « 4aB3H » ont la même signification.
Si vous n'ajoutez pas de nombre après le préfixe dans une expression, le nombre est lu comme 0. Par conséquent, vous pouvez écrire 0 comme 0, le préfixe suivi de 0 et seulement le préfixe. Par exemple, en hexadécimal, « 0 », « 0x0 » et « 0x » ont la même signification.
Vous pouvez entrer des valeurs hexadécimales 64 bits au format xxxxxxxx`xxxxxxxx. Vous pouvez également omettre l'accent grave (`). Si vous incluez l'accent grave, l'extension de signe automatique est désactivée.
Cet exemple montre comment ajouter une valeur décimale, octale et binaire au registre 10.
? @r10 + 0x10 + 0t10 + 0y10
Evaluate expression: 26 = 00000000`0000001a
Symboles dans les expressions MASM du débogueur
Dans les expressions MASM, la valeur numérique de tout symbole est son adresse mémoire. Selon ce à quoi se réfère le symbole, cette adresse est l'adresse d'une variable globale, d'une variable locale, d'une fonction, d'un segment, d'un module ou de tout autre label reconnu.
Pour spécifier à quel module l'adresse est associée, incluez le nom du module et un point d'exclamation (!) avant le nom du symbole. Si le symbole pouvait être interprété comme un nombre hexadécimal, incluez le nom du module et un point d'exclamation, ou juste un point d'exclamation, avant le nom du symbole. Pour plus d'informations sur la reconnaissance des symboles, veuillez consulter Syntaxe des symboles et correspondance des symboles.
Utilisez deux points (::) ou deux traits de soulignement (__) pour indiquer les membres d'une classe.
Utilisez un accent grave (`) ou une apostrophe (') dans un nom de symbole uniquement si vous ajoutez un nom de module et un point d'exclamation avant le symbole.
Opérateurs numériques dans les expressions MASM
Vous pouvez modifier tout composant d'une expression en utilisant un opérateur unaire. Vous pouvez combiner deux composants en utilisant un opérateur binaire. Les opérateurs unaires ont priorité sur les opérateurs binaires. Lorsque vous utilisez plusieurs opérateurs binaires, les opérateurs suivent les règles de priorité fixe décrites dans les tableaux suivants.
Vous pouvez toujours utiliser des parenthèses pour outrepasser les règles de priorité.
Si une partie d'une expression MASM est entre parenthèses et que deux signes arobase (@@) apparaissent avant l'expression, l'expression est interprétée selon les règles d'expression C++. Vous ne pouvez pas ajouter d'espace entre les deux signes arobase et la parenthèse ouvrante. Vous pouvez également spécifier l'évaluateur d'expressions en utilisant @@c++( ... ) ou @@masm( ... ).
Lorsque vous effectuez des calculs arithmétiques, l'évaluateur d'expressions MASM traite tous les nombres et symboles comme des types ULONG64.
Les opérateurs d'adresse unaires supposent que DS est le segment par défaut pour les adresses. Les expressions sont évaluées selon l'ordre de priorité des opérateurs. Si les opérateurs adjacents ont la même priorité, l'expression est évaluée de gauche à droite.
Vous pouvez utiliser les opérateurs unaires suivants.
Opérateur | Signification |
---|---|
+ |
Plus unaire |
- |
Moins unaire |
not |
Renvoie 1 si l'argument est zéro. Renvoie zéro pour tout argument non nul. |
salut |
16 bits de poids fort |
Faible |
16 bits de poids faible |
by |
Octet de faible ordre de l'adresse spécifiée. |
$pby |
Identique à by sauf qu'il prend une adresse physique. Seule la mémoire physique utilisant le comportement de mise en cache par défaut peut être lue. |
wo |
Mot de faible ordre de l'adresse spécifiée. |
$pwo |
Identique à wo sauf qu'il prend une adresse physique. Seule la mémoire physique utilisant le comportement de mise en cache par défaut peut être lue. |
dwo |
Double-mot de l'adresse spécifiée. |
$pdwo |
Identique à dwo sauf qu'il prend une adresse physique. Seule la mémoire physique utilisant le comportement de mise en cache par défaut peut être lue. |
qwo |
Quadruple-mot de l'adresse spécifiée. |
$pqwo |
Identique à qwo sauf qu'il prend une adresse physique. Seule la mémoire physique utilisant le comportement de mise en cache par défaut peut être lue. |
poi |
Données de taille de pointeur de l'adresse spécifiée. La taille du pointeur est de 32 bits ou 64 bits. En débogage kernel, cette taille est basée sur le processeur de l'ordinateur cible. Par conséquent, poi est le meilleur opérateur à utiliser si vous voulez des données de taille de pointeur. |
$ppoi |
Identique à poi sauf qu'il prend une adresse physique. Seule la mémoire physique utilisant le comportement de mise en cache par défaut peut être lue. |
Exemples
L'exemple suivant montre comment utiliser poi pour déréférencer un pointeur afin de voir la valeur stockée à cet emplacement mémoire.
Déterminez d'abord l'adresse mémoire d'intérêt. Par exemple, nous pouvons examiner la structure du thread et décider que nous voulons voir la valeur de CurrentLocale.
0:000> dx @$teb
@$teb : 0x8eed57b000 [Type: _TEB *]
[+0x000] NtTib [Type: _NT_TIB]
[+0x038] EnvironmentPointer : 0x0 [Type: void *]
[+0x040] ClientId [Type: _CLIENT_ID]
[+0x050] ActiveRpcHandle : 0x0 [Type: void *]
[+0x058] ThreadLocalStoragePointer : 0x1f8f9d634a0 [Type: void *]
[+0x060] ProcessEnvironmentBlock : 0x8eed57a000 [Type: _PEB *]
[+0x068] LastErrorValue : 0x0 [Type: unsigned long]
[+0x06c] CountOfOwnedCriticalSections : 0x0 [Type: unsigned long]
[+0x070] CsrClientThread : 0x0 [Type: void *]
[+0x078] Win32ThreadInfo : 0x0 [Type: void *]
[+0x080] User32Reserved [Type: unsigned long [26]]
[+0x0e8] UserReserved [Type: unsigned long [5]]
[+0x100] WOW32Reserved : 0x0 [Type: void *]
[+0x108] CurrentLocale : 0x409 [Type: unsigned long]
CurrentLocale est situé à 0x108 au-delà du début du TEB.
0:000> ? @$teb + 0x108
Evaluate expression: 613867303176 = 0000008e`ed57b108
Utilisez poi pour déréférencer cette adresse.
0:000> ? poi(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409
La valeur retournée de 409 correspond à la valeur de CurrentLocale dans la structure TEB.
Ou utilisez poi et des parenthèses pour déréférencer l'adresse calculée.
0:000> ? poi(@$teb + 0x108)
Evaluate expression: 1033 = 00000000`00000409
Utilisez les opérateurs unaires by ou wo pour retourner un octet ou un mot de l'adresse cible.
0:000> ? by(0000008e`ed57b108)
Evaluate expression: 9 = 00000000`00000009
0:000> ? wo(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409
Opérateurs binaires
Vous pouvez utiliser les opérateurs binaires suivants. Les opérateurs dans chaque cellule ont priorité sur ceux dans les cellules inférieures. Les opérateurs dans la même cellule ont la même priorité et sont analysés de gauche à droite.
Opérateur | Signification |
---|---|
* / mod (ou %) |
Multiplication Division d'entier Modulus (reste) |
+ - |
Ajout Soustraction |
<< >> >>> |
Décalage vers la gauche Décalage logique à droite Décalage arithmétique à droite |
= (ou ==) < > <= >= != |
Égal à Inférieur à Supérieur à Inférieur ou égal à Supérieur ou égal à Non égal à |
and (ou &) |
ET au niveau du bit |
xor (ou ^) |
XOR bit à bit (OU exclusif) |
or (ou |) |
Opération de bits OR |
Les opérateurs de comparaison <, >, =, == et != évaluent à 1 si l'expression est vraie ou à zéro si l'expression est fausse. Un seul signe égal (=) est identique à un double signe égal (==). Vous ne pouvez pas utiliser des effets de bord ou des affectations dans une expression MASM.
Une opération invalide (comme la division par zéro) entraîne une « Erreur d'opérande » renvoyée à la fenêtre de commande du débogueur.
Nous pouvons vérifier que la valeur retournée correspond à 0x409 en utilisant l'opérateur de comparaison ==.
0:000> ? poi(@$teb + 0x108)==0x409
Evaluate expression: 1 = 00000000`00000001
Opérateurs non numériques dans les expressions MASM
Vous pouvez également utiliser les opérateurs supplémentaires suivants dans les expressions MASM.
Opérateur | Signification |
---|---|
$fnsucc(FnAddress, RetVal, Flag) |
Interprète la valeur RetVal comme une valeur de retour pour la fonction située à l'adresse FnAddress. Si cette valeur de retour est qualifiée de code de succès, $fnsucc renvoie TRUE. Sinon, $fnsucc renvoie FALSE. Si le type de retour est BOOL, bool, HANDLE, HRESULT ou NTSTATUS, $fnsucc comprend correctement si la valeur de retour spécifiée est qualifiée de code de succès. Si le type de retour est un pointeur, toutes les valeurs autres que NULL sont qualifiées de codes de succès. Pour tout autre type, le succès est défini par la valeur de Flag. Si Flag est 0, une valeur non nulle de RetVal est un succès. Si Flag est 1, une valeur nulle de RetVal est un succès. |
$iment (Address) |
Renvoie l'adresse du point d'entrée de l'image dans la liste des modules chargés. Address spécifie l'adresse de base de l'image Portable Executable (PE). L'entrée est trouvée en recherchant le point d'entrée de l'image dans l'en-tête de l'image PE de l'image que Address spécifie. Vous pouvez utiliser cette fonction pour les modules qui sont déjà dans la liste des modules et pour définir des points d'arrêt non résolus en utilisant la commande bu. |
$scmp("String1", "String2") |
Évalue à -1, 0 ou 1, comme la fonction strcmp en utilisant la fonction C strcmp . |
$sicmp("String1", "String2") |
Évalue à -1, 0 ou 1, comme la fonction Microsoft Win32 stricmp. |
$spat("String", "Pattern") |
Évalue à TRUE ou FALSE selon que String correspond à Pattern ou non. La correspondance n'est pas sensible à la casse. Pattern peut contenir une variété de caractères génériques et de spécificateurs. Pour plus d’informations sur la syntaxe, consultez la section syntaxe des caractères génériques de chaîne. |
$vvalid(Adresse, Longueur) |
Détermine si la plage de mémoire qui commence à Address et s'étend sur Length octets est valide. Si la mémoire est valide, $vvalid évalue à 1. Si la mémoire est invalide, $vvalid évalue à 0. |
Exemples
L'exemple suivant montre comment utiliser $vvalid pour vérifier la plage de mémoire valide autour d'un module chargé.
Déterminez d'abord l'adresse de la zone d'intérêt, par exemple en utilisant la commande lm (Liste des modules chargés.
0:000> lm
start end module name
00007ff6`0f620000 00007ff6`0f658000 notepad (deferred)
00007ff9`591d0000 00007ff9`5946a000 COMCTL32 (deferred)
...
Utilisez $vvalid pour vérifier une plage de mémoire.
0:000> ? $vvalid(0x00007ff60f620000, 0xFFFF)
Evaluate expression: 1 = 00000000`00000001
Utilisez $vvalid pour confirmer que cette plage plus grande est une plage de mémoire invalide.
0:000> ? $vvalid(0x00007ff60f620000, 0xFFFFF)
Evaluate expression: 0 = 00000000`00000000
C'est aussi une plage invalide.
0:000> ? $vvalid(0x0, 0xF)
Evaluate expression: 0 = 00000000`00000000
Utilisez not pour renvoyer zéro lorsque la plage de mémoire est valide.
0:000> ? not($vvalid(0x00007ff60f620000, 0xFFFF))
Evaluate expression: 0 = 00000000`00000000
Utilisez $imnet pour examiner le point d'entrée de COMCTL32 que nous avons précédemment utilisé la commande lm pour déterminer l'adresse. Il commence à 00007ff9`591d0000.
0:000> ? $iment(00007ff9`591d0000)
Evaluate expression: 140708919287424 = 00007ff9`59269e80
Désassemblez l'adresse retournée pour examiner le code du point d'entrée.
0:000> u 00007ff9`59269e80
COMCTL32!DllMainCRTStartup:
00007ff9`59269e80 48895c2408 mov qword ptr [rsp+8],rbx
00007ff9`59269e85 4889742410 mov qword ptr [rsp+10h],rsi
00007ff9`59269e8a 57 push rdi
COMCTL32 est affiché dans la sortie confirmant qu'il s'agit du point d'entrée de ce module.
Registres et pseudo-registres dans les expressions MASM
Vous pouvez utiliser des registres et des pseudo-registres dans les expressions MASM. Vous pouvez ajouter un signe arobase (@) avant tous les registres et pseudo-registres. Le signe arobase permet au débogueur d'accéder plus rapidement à la valeur. Ce signe @ n'est pas nécessaire pour les registres les plus courants basés sur x86. Pour les autres registres et pseudo-registres, nous recommandons d'ajouter le signe arobase, mais il n'est pas réellement requis. Si vous omettez le signe arobase pour les registres moins courants, le débogueur essaie d'analyser le texte comme un nombre hexadécimal, puis comme un symbole et enfin comme un registre.
Vous pouvez également utiliser un point (.) pour indiquer le pointeur d'instruction actuel. Vous ne devez pas ajouter de signe @ avant ce point, et vous ne pouvez pas utiliser un point comme premier paramètre de la commande r. Ce point a la même signification que le pseudo-registre $ip.
Pour plus d'informations sur les registres et pseudo-registres, veuillez consulter Syntaxe des registres et Syntaxe des pseudo-registres.
Utilisez la commande r pour voir que la valeur du registre @rip est 00007ffb`7ed00770.
0:000> r
rax=0000000000000000 rbx=0000000000000010 rcx=00007ffb7eccd2c4
rdx=0000000000000000 rsi=00007ffb7ed61a80 rdi=00000027eb6a7000
rip=00007ffb7ed00770 rsp=00000027eb87f320 rbp=0000000000000000
r8=00000027eb87f318 r9=0000000000000000 r10=0000000000000000
r11=0000000000000246 r12=0000000000000040 r13=0000000000000000
r14=00007ffb7ed548f0 r15=00000210ea090000
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ntdll!LdrpDoDebuggerBreak+0x30:
00007ffb`7ed00770 cc int 3
Cette même valeur peut être affichée en utilisant le raccourci point.
0:000> ? .
Evaluate expression: 140718141081456 = 00007ffb`7ed00770
Nous pouvons confirmer que ces valeurs sont toutes équivalentes et renvoyer zéro si elles le sont en utilisant cette expression MASM.
0:000> ? NOT(($ip = .) AND ($ip = @rip) AND (@rip =. ))
Evaluate expression: 0 = 00000000`00000000
Numéros de ligne de code source dans les expressions MASM
Vous pouvez utiliser des expressions de fichier source et de numéro de ligne dans les expressions MASM. Vous devez inclure ces expressions en utilisant des accents graves (`). Pour plus d'informations sur la syntaxe, veuillez consulter Syntaxe des lignes de code source.