Números y operadores de MASM
En este tema se describe el uso de la sintaxis de expresiones de Microsoft Macro Assembler (MASM) con las herramientas de depuración de Windows.
El depurador acepta dos tipos diferentes de expresiones numéricas: expresiones de C++ y expresiones de MASM. Cada una de estas expresiones sigue sus propias reglas de sintaxis para la entrada y salida.
Para obtener más información sobre cuándo se usa cada tipo de sintaxis, consulte Evaluación de expresiones y ? (Evaluar expresión).
En este ejemplo, el comando ? muestra el valor del registro del puntero de instrucción mediante el evaluador de expresiones MASM.
0:000> ? @rip
Evaluate expression: 140709230544752 = 00007ff9`6bb40770
Definición del evaluador de expresiones en MASM
Use .expr (Elegir evaluador de expresiones) para ver cuál es el evaluador de expresiones predeterminado y cambiarlo a MASM.
0:000> .expr /s masm
Current expression evaluator: MASM - Microsoft Assembler expressions
Ahora que se ha cambiado el evaluador de expresiones predeterminado, se puede usar el comando ? (Evaluar expresión) para mostrar expresiones MASM. En este ejemplo se agrega el valor hexadecimal de 8 al registro rip.
0:000> ? @rip + 8
Evaluate expression: 140709230544760 = 00007ff9`6bb40778
La referencia de registro de @rip se describe con más detalle en Sintaxis de registro.
Números en expresiones MASM del depurador
Puede colocar números en expresiones MASM en base 16, 10, 8 o 2.
Use el comando n (Establecer número base) para establecer la base predeterminada en 16, 10 o 8. Todos los números sin prefijo se interpretan en esta base. Puede invalidar la base predeterminada especificando el prefijo 0x (hexadecimal), el prefijo 0n (decimal), el prefijo 0t (octal) o el prefijo 0y (binario).
También puede especificar números hexadecimales agregando una h después del número. Puede usar letras mayúsculas o minúsculas dentro de números. Por ejemplo, "0x4AB3", "0X4aB3", "4AB3h", "4ab3h" y "4aB3H" tienen el mismo significado.
Si no agrega un número después del prefijo en una expresión, el número se lee como 0. Por lo tanto, puede escribir 0 como 0, el prefijo seguido de 0 y solo el prefijo. Por ejemplo, en hexadecimal, "0", "0x0" y "0x" tienen el mismo significado.
Puede escribir valores hexadecimales de 64 bits con el formato xxxxxxxx'xxxxxxxx. También puede omitir el acento grave (`). Si incluye el acento grave, la extensión de signo automático está deshabilitada.
En este ejemplo se muestra cómo agregar un valor decimal, octal y binario para registrar 10.
? @r10 + 0x10 + 0t10 + 0y10
Evaluate expression: 26 = 00000000`0000001a
Símbolos en expresiones MASM del depurador
En las expresiones MASM, el valor numérico de cualquier símbolo es su dirección de memoria. Dependiendo de a lo que hace referencia el símbolo, esta dirección es la dirección de una variable global, variable local, función, segmento, módulo o cualquier otra etiqueta reconocida.
Para especificar a qué módulo está asociado la dirección, incluya el nombre del módulo y un signo de exclamación (!) antes del nombre del símbolo. Si el símbolo se puede interpretar como un número hexadecimal, incluya el nombre del módulo y un signo de exclamación, o simplemente un signo de exclamación, antes del nombre del símbolo. Para obtener más información sobre el reconocimiento de símbolos, consulte Sintaxis de símbolos y coincidencia de símbolos.
Use dos puntos (::) o dos caracteres de subrayado (__) para indicar los miembros de una clase.
Use un acento grave (`) o un apóstrofe (') en un nombre de símbolo solo si agrega un nombre de módulo y un signo de exclamación antes del símbolo.
Operadores numéricos en expresiones MASM
Puede modificar cualquier componente de una expresión mediante un operador unario. Puede combinar dos componentes mediante un operador binario. Los operadores unarios tienen prioridad sobre los operadores binarios. Cuando se usan varios operadores binarios, los operadores siguen las reglas de prioridad fijas que se describen en las tablas siguientes.
Siempre puede usar paréntesis para anular las reglas de prioridad.
Si parte de una expresión MASM está entre paréntesis y dos signos (@@) aparecen antes de la expresión, la expresión se interpreta según las reglas de expresión de C++. No se puede agregar un espacio entre los dos signos y el paréntesis de apertura. También puede especificar el evaluador de expresiones mediante @@c++( ... ) o @@masm( ... ).
Al realizar cálculos aritméticos, el evaluador de expresiones MASM trata todos los números y símbolos como tipos de ULONG64.
Los operadores de direcciones unarios asumen DS como el segmento predeterminado para las direcciones. Las expresiones se evalúan en orden de prioridad del operador. Si los operadores adyacentes tienen la misma prioridad, la expresión se evalúa de izquierda a derecha.
Puede usar los siguientes operadores unarios.
Operador | Significado |
---|---|
+ |
Suma unaria |
- |
Unario menos |
not |
Devuelve 1 si el argumento es cero. Devuelve cero para cualquier argumento distinto de cero. |
Hi (Hola) |
16 bits altos |
Bajo |
16 bits bajos |
by |
Byte de orden bajo de la dirección especificada. |
$pby |
Igual que by, salvo que toma una dirección física. Solo se puede leer la memoria física que usa el comportamiento de almacenamiento en caché predeterminado. |
wo |
Palabra de orden bajo de la dirección especificada. |
$pwo |
Igual que wo, salvo que toma una dirección física. Solo se puede leer la memoria física que usa el comportamiento de almacenamiento en caché predeterminado. |
dwo |
Palabra doble de la dirección especificada. |
$pdwo |
Igual que dwo, salvo que toma una dirección física. Solo se puede leer la memoria física que usa el comportamiento de almacenamiento en caché predeterminado. |
qwo |
Palabra cuádruple de la dirección especificada. |
$pqwo |
Igual que qwo, salvo que toma una dirección física. Solo se puede leer la memoria física que usa el comportamiento de almacenamiento en caché predeterminado. |
poi |
Datos de tamaño de puntero de la dirección especificada. El tamaño del puntero es de 32 bits o 64 bits. En la depuración del kernel, este tamaño se basa en el procesador del equipo de destino. Por lo tanto, poi es el mejor operador que se usará si desea datos de tamaño de puntero. |
$ppoi |
Igual que poi, salvo que toma una dirección física. Solo se puede leer la memoria física que usa el comportamiento de almacenamiento en caché predeterminado. |
Ejemplos
En el ejemplo siguiente se muestra cómo usar poi para desreferenciar un puntero para ver el valor almacenado en esa ubicación de memoria.
En primer lugar, determine la dirección de memoria de interés. Por ejemplo, podemos examinar la estructura del subproceso y decidir que queremos ver el valor 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 se encuentra 0x108 más allá del inicio del TEB.
0:000> ? @$teb + 0x108
Evaluate expression: 613867303176 = 0000008e`ed57b108
Use poi para desreferenciar esa dirección.
0:000> ? poi(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409
El valor devuelto de 409 coincide con el valor de CurrentLocale en la estructura TEB.
O use poi y paréntesis para desreferenciar la dirección calculada.
0:000> ? poi(@$teb + 0x108)
Evaluate expression: 1033 = 00000000`00000409
Use los operadores unarios by o wo para devolver un byte o una palabra de la dirección de destino.
0:000> ? by(0000008e`ed57b108)
Evaluate expression: 9 = 00000000`00000009
0:000> ? wo(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409
Operadores binarios
Puede usar los siguientes operadores binarios. Los operadores de cada celda tienen prioridad sobre los de las celdas inferiores. Los operadores de la misma celda tienen la misma prioridad y se analizan de izquierda a derecha.
Operador | Significado |
---|---|
* / mod (o %) |
Multiplicación División de enteros Módulo (resto) |
+ - |
Suma Resta |
<< >> >>> |
Desplazamiento a la izquierda Desplazamiento lógico a la derecha Desplazamiento aritmético a la derecha |
= (o ==) < > <= >= != |
Igual a Menor que Mayor que Menor o igual que Mayor o igual que No igual a |
and (o &) |
AND bit a bit |
xor (o ^) |
XOR (OR exclusivo) bit a bit |
or (o |) |
OR bit a bit |
Los operadores de comparación <, >, =, == y != se evalúan como 1 si la expresión es true o cero si la expresión es false. Un único signo de igual (=) es el mismo que un signo de igual doble (==). No se pueden usar efectos secundarios ni asignaciones dentro de una expresión MASM.
Una operación no válida (por ejemplo, la división por cero) da como resultado un "error de operando" en la ventana Comando del depurador.
Podemos comprobar que el valor devuelto coincide con 0x409 mediante el operador de comparación == .
0:000> ? poi(@$teb + 0x108)==0x409
Evaluate expression: 1 = 00000000`00000001
Operadores no numéricos en expresiones MASM
También puede usar los siguientes operadores adicionales en expresiones MASM.
Operador | Significado |
---|---|
$fnsucc(FnAddress, RetVal, Flag) |
Interpreta el valor RetVal como un valor devuelto para la función que se encuentra en la dirección FnAddress. Si este valor devuelto se califica como código correcto, $fnsucc devuelve TRUE. De lo contrario, $fnsucc devuelve FALSE. Si el tipo de valor devuelto es BOOL, bool, HANDLE, HRESULT o NTSTATUS, $fnsucc comprende correctamente si el valor devuelto especificado se califica como código correcto. Si el tipo de valor devuelto es un puntero, todos los valores distintos de NULL se califican como códigos correctos. Para cualquier otro tipo, correcto se define mediante el valor de Flag. Si Flag es 0, un valor distinto de cero de RetVal es correcto. Si Flag es 1, un valor de cero de RetVal es correcto. |
$iment (Address) |
Devuelve la dirección del punto de entrada de la imagen en la lista de módulos cargados. Address especifica la dirección base de la imagen portable ejecutable (PE). La entrada se encuentra buscando el punto de entrada de la imagen en el encabezado de imagen PE de la imagen que especifica Address. Puede usar esta función para ambos módulos que ya están en la lista de módulos y para establecer puntos de interrupción sin resolver mediante el comando bu. |
$scmp("String1", "String2") |
Se evalúa como -1, 0 o 1, como strcmp mediante la función de C strcmp . |
$sicmp("String1", "String2") |
Se evalúa como -1, 0 o 1, como la función stricmp de Microsoft Win32. |
$spat("String", "Pattern") |
Se evalúa como TRUE o FALSE en función de si String coincide con Pattern. La coincidencia distingue mayúsculas y minúsculas. Pattern puede contener una variedad de caracteres comodín y especificadores. Para obtener más información sobre la sintaxis, consulte Sintaxis de caracteres comodín de cadena. |
$vvalid(Address, Length) |
Determina si el intervalo de memoria que comienza en Address y se extiende Length bytes es válido. Si la memoria es válida, $vvalid se evalúa como 1. Si la memoria no es válida, $vvalid se evalúa como 0. |
Ejemplos
A continuación se muestra cómo usar el intervalo de memoria válida en torno a un módulo cargado.
En primer lugar, determine la dirección del área de interés, por ejemplo mediante el comando lm (Enumerar módulos cargados).
0:000> lm
start end module name
00007ff6`0f620000 00007ff6`0f658000 notepad (deferred)
00007ff9`591d0000 00007ff9`5946a000 COMCTL32 (deferred)
...
Use $vvalid para comprobar un intervalo de memoria.
0:000> ? $vvalid(0x00007ff60f620000, 0xFFFF)
Evaluate expression: 1 = 00000000`00000001
Use $vvalid para confirmar que este intervalo mayor es un intervalo de memoria no válido.
0:000> ? $vvalid(0x00007ff60f620000, 0xFFFFF)
Evaluate expression: 0 = 00000000`00000000
Esto también es un intervalo no válido.
0:000> ? $vvalid(0x0, 0xF)
Evaluate expression: 0 = 00000000`00000000
Use not para devolver cero cuando el intervalo de memoria sea válido.
0:000> ? not($vvalid(0x00007ff60f620000, 0xFFFF))
Evaluate expression: 0 = 00000000`00000000
Use $imnet para examinar el punto de entrada de COMCTL32 donde usamos anteriormente el comando lm para determinar la dirección. Comienza en 00007ff9`591d0000.
0:000> ? $iment(00007ff9`591d0000)
Evaluate expression: 140708919287424 = 00007ff9`59269e80
Desensamble la dirección devuelta para examinar el código de punto de entrada.
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 se muestra en la salida que confirma que este es el punto de entrada de este módulo.
Registros y pseudoregistros en expresiones MASM
Puede usar registros y pseudoregistros en expresiones MASM. Puede añadir una arroba (@) antes de todos los registros y pseudoregistros. El signo de arroba hace que el depurador acceda al valor más rápidamente. Este signo @ no es necesario para los registros basados en x86 más comunes. En el caso de otros registros y pseudoregistros, se recomienda agregar el signo de arroba, pero no es realmente necesario. Si omite el signo para los registros menos comunes, el depurador intenta analizar el texto como un número hexadecimal, como un símbolo y, por último, como registro.
También puede usar un punto (.) para indicar el puntero de instrucción actual. No debe agregar un signo de arroba @ antes de este punto y no puede usar un punto como primer parámetro del comando r. Este punto tiene el mismo significado que el pseudoregistro $ip.
Para obtener más información sobre los registros y los pseudoregistros, consulte Sintaxis de registro y Sintaxis de pseudoregistro.
Use el comando r register para ver que el valor del registro @rip es 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
Este mismo valor se puede mostrar utilizando el método abreviado de punto .
0:000> ? .
Evaluate expression: 140718141081456 = 00007ffb`7ed00770
Podemos confirmar que esos valores son equivalentes y devolver cero si lo son, usando esta expresión MASM.
0:000> ? NOT(($ip = .) AND ($ip = @rip) AND (@rip =. ))
Evaluate expression: 0 = 00000000`00000000
Números de línea de origen en expresiones MASM
Puede usar expresiones de número de línea y archivo de origen dentro de expresiones MASM. Debe incluir estas expresiones mediante acentos graves (`). Para obtener más información sobre la sintaxis, consulte Sintaxis de línea de origen.
Consulte también
Expresiones de MASM frente a expresiones de C++