Números e operadores MASM
Este tópico descreve o uso da sintaxe de expressão Microsoft Macro Assembler (MASM) com as ferramentas de Depuração do Windows.
O depurador aceita dois tipos diferentes de expressões numéricas: expressões C++ e expressões MASM. Cada uma dessas expressões segue suas próprias regras de sintaxe para entrada e saída.
Para obter mais informações sobre quando cada tipo de sintaxe é usado, consulte Avaliando expressões e ? (Evaluate Expression).
Neste exemplo, o comando ? exibe o valor do registro do ponteiro de instrução usando o avaliador de expressão MASM.
0:000> ? @rip
Evaluate expression: 140709230544752 = 00007ff9`6bb40770
Definir o avaliador de expressão como MASM
Use o .expr (Choose Expression Evaluator) para ver qual é o avaliador de expressão padrão e altere-o para MASM.
0:000> .expr /s masm
Current expression evaluator: MASM - Microsoft Assembler expressions
Agora que o avaliador de expressão padrão foi alterado, o comando ? (Evaluate Expression) pode ser usado para exibir expressões MASM. Este exemplo adiciona o valor hexadecimal 8 ao registro rip.
0:000> ? @rip + 8
Evaluate expression: 140709230544760 = 00007ff9`6bb40778
A referência de registro de @rip é descrita em mais detalhes em Sintaxe de registro.
Números em expressões MASM do depurador
Você pode colocar números em expressões MASM na base 16, 10, 8 ou 2.
Use o comando n (Set Number Base) para definir o radix padrão como 16, 10 ou 8. Todos os números sem prefixo são interpretados nessa base. Você pode substituir o radix padrão especificando o prefixo 0x (hexadecimal), o prefixo 0n (decimal), o prefixo 0t (octal) ou o prefixo 0y (binário).
Você também pode especificar números hexadecimais adicionando um h depois do número. Você pode usar letras maiúsculas ou minúsculas dentro de números. Por exemplo, "0x4AB3", "0X4aB3", "4AB3h", "4ab3h" e "4aB3H" têm o mesmo significado.
Se você não adicionar um número depois do prefixo em uma expressão, o número será lido como 0. Portanto, você pode escrever 0 como 0, o prefixo seguido por 0 e somente o prefixo. Por exemplo, em hexadecimal, "0", "0x0" e "0x" têm o mesmo significado.
Você pode inserir valores hexadecimais de 64 bits no formato xxxxxxxx'xxxxxxxx. Você também pode omitir o acento grave ('). Se você incluir o acento grave, a extensão de sinal automático será desativada.
Este exemplo mostra como adicionar um valor decimal, octal e binário para registrar 10.
? @r10 + 0x10 + 0t10 + 0y10
Evaluate expression: 26 = 00000000`0000001a
Símbolos em expressões MASM do depurador
Em expressões MASM, o valor numérico de qualquer símbolo é seu endereço de memória. Dependendo ao que o símbolo se refere, esse endereço é o endereço de uma variável global, variável local, função, segmento, módulo ou qualquer outro rótulo reconhecido.
Para especificar a qual módulo o endereço está associado, inclua o nome do módulo e um ponto de exclamação (!) antes do nome do símbolo. Se o símbolo puder ser interpretado como um número hexadecimal, inclua o nome do módulo e um ponto de exclamação, ou apenas um ponto de exclamação, antes do nome do símbolo. Para obter mais informações sobre reconhecimento de símbolos, consulte Sintaxe e correspondência de símbolos.
Use dois pontos duas vezes (::) ou dois sublinhados (__) para indicar os membros de uma classe.
Use um acento grave (') ou um apóstrofo (') em um nome de símbolo somente se você adicionar um nome de módulo e ponto de exclamação antes do símbolo.
Operadores numéricos em expressões MASM
Você pode modificar qualquer componente de uma expressão usando um operador unário. Você pode combinar quaisquer dois componentes usando um operador binário. Os operadores unários têm precedência sobre os operadores binários. Quando você usa vários operadores binários, os operadores seguem as regras de precedência fixa descritas nas tabelas a seguir.
Você sempre pode usar parênteses para substituir regras de precedência.
Se parte de uma expressão MASM estiver entre parênteses e dois sinais de arroba (@@) aparecerem antes da expressão, a expressão será interpretada de acordo com as regras de expressão de C++. Não é possível adicionar um espaço entre os dois sinais de arroba e o parêntese de abertura. Você também pode especificar o avaliador de expressão usando @@c++( ... ) ou @@masm( ... ).
Quando você executa cálculos aritméticos, o avaliador de expressão MASM trata todos os números e símbolos como tipos ULONG64.
Os operadores de endereço unário assumem o DS como o segmento padrão para endereços. As expressões são avaliadas em ordem de precedência do operador. Se os operadores adjacentes tiverem precedência igual, a expressão será avaliada da esquerda para a direita.
Você pode usar os seguintes operadores unários.
Operador | Significado |
---|---|
+ |
Adição de unário |
- |
Menos unário |
not |
Retornará 1 se o argumento for zero. Retorna zero para qualquer argumento diferente de zero. |
oi |
16 bits altos |
low |
16 bits baixos |
by |
Byte de ordem baixa do endereço especificado. |
$pby |
O mesmo que by, mas leva um endereço físico. Somente a memória física que usa o comportamento de cache padrão pode ser lida. |
wo |
Palavra de ordem baixa do endereço especificado. |
$pwo |
O mesmo que wo, mas leva um endereço físico. Somente a memória física que usa o comportamento de cache padrão pode ser lida. |
dwo |
Palavra dupla do endereço especificado. |
$pdwo |
O mesmo que dwo, mas leva um endereço físico. Somente a memória física que usa o comportamento de cache padrão pode ser lida. |
qwo |
Palavra quádrupla do endereço especificado. |
$pqwo |
O mesmo que qwo, mas leva um endereço físico. Somente a memória física que usa o comportamento de cache padrão pode ser lida. |
poi |
Dados do tamanho de ponteiro do endereço especificado. O tamanho do ponteiro é de 32 bits ou 64 bits. Na depuração do kernel, esse tamanho é baseado no processador do computador de destino. Portanto, poi é o melhor operador a ser usado se você quiser dados do tamanho de um ponteiro. |
$ppoi |
O mesmo que poi, mas leva um endereço físico. Somente a memória física que usa o comportamento de cache padrão pode ser lida. |
Exemplos
O exemplo a seguir mostra como usar poi para cancelar a referência de um ponteiro para ver o valor armazenado nesse local de memória.
Primeiro, determine o endereço de memória de interesse. Por exemplo, podemos olhar para a estrutura do thread e decidir que queremos ver o 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 está localizado 0x108 além do início do TEB.
0:000> ? @$teb + 0x108
Evaluate expression: 613867303176 = 0000008e`ed57b108
Use poi para cancelar a referência desse endereço.
0:000> ? poi(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409
O valor retornado de 409 corresponde ao valor de CurrentLocale na estrutura TEB.
Ou use poi e parênteses para cancelar a referência do endereço calculado.
0:000> ? poi(@$teb + 0x108)
Evaluate expression: 1033 = 00000000`00000409
Use os operadores unários by ou wo para retornar um byte ou uma palavra do endereço de destino.
0:000> ? by(0000008e`ed57b108)
Evaluate expression: 9 = 00000000`00000009
0:000> ? wo(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409
Operadores binários
Você pode usar os seguintes operadores binários. Os operadores em cada célula têm precedência sobre aqueles em células inferiores. Os operadores na mesma célula têm a mesma precedência e são analisados da esquerda para a direita.
Operador | Significado |
---|---|
* / mod (or %) |
Multiplicação Divisão de inteiros Módulo (pendências) |
+ - |
Adição Subtração |
<< >> >>> |
Deslocamento à esquerda Deslocamento lógico para a direita Desvio aritmético para a direita |
= (ou ==) < > <= >= != |
Igual a Menor que Maior que Menor ou igual a Maior ou igual a Diferente de |
and (ou &) |
AND bit a bit |
xor (ou ^) |
XOR bit a bit (OR exclusivo) |
or (ou |) |
OR bit a bit |
Os operadores de comparação <, >, =, == e != serão avaliados como 1 se a expressão for verdadeira ou zero se a expressão for falsa. Um único sinal de igual (=) é o mesmo que um sinal de igual duplo (==). Não é possível usar efeitos colaterais ou atribuições em uma expressão MASM.
Uma operação inválida (como divisão por zero) resulta em um "Erro de operando" que é retornado para a janela Comando do depurador.
Podemos verificar se o valor retornado corresponde a 0x409 usando o operador de comparação ==.
0:000> ? poi(@$teb + 0x108)==0x409
Evaluate expression: 1 = 00000000`00000001
Operadores não numéricos em expressões MASM
Você também pode usar os seguintes operadores adicionais em expressões MASM.
Operador | Significado |
---|---|
$fnsucc(FnAddress, RetVal, Flag) |
Interpreta o valor RetVal como um valor de retorno para a função localizada no endereço FnAddress. Se esse valor de retorno se qualificar como um código de êxito, $fnsucc retornará TRUE. Caso contrário, $fnsucc retornará FALSE. Se o tipo de retorno for BOOL, bool, HANDLE, HRESULT ou NTSTATUS, $fnsucc entenderá corretamente se o valor de retorno especificado se qualifica como um código de êxito. Se o tipo de retorno for um ponteiro, todos os valores diferentes de NULL se qualificarão como códigos de êxito. Para qualquer outro tipo, o êxito é definido pelo valor de Flag. Se Flag for 0, um valor diferente de zero de RetVal será êxito. Se Flag for 1, um valor igual a zero de RetVal será êxito. |
$iment (Address) |
Retorna o endereço do ponto de entrada da imagem na lista de módulos carregados. Address especifica o endereço base da imagem PE (Portable Executable). A entrada é encontrada pesquisando o ponto de entrada da imagem no cabeçalho da imagem PE da imagem especificada por Address. Você pode usar essa função para os dois módulos que já estão na lista de módulos e para definir pontos de interrupção não resolvidos usando o comando bu. |
$scmp("String1", "String2") |
Avalia como -1, 0 ou 1, como o strcmp usando a função strcmp C. |
$sicmp("String1", "String2") |
Avalia como -1, 0 ou 1, como a função stricmp do Microsoft Win32. |
$spat("String", "Pattern") |
Avalia como TRUE ou FALSE dependendo se String corresponde a Pattern. A correspondência não diferencia maiúsculas de minúsculas. Pattern pode conter diversos caracteres curinga e especificadores. Para obter mais informações sobre a sintaxe, confira Sintaxe do curinga da cadeia de caracteres. |
$vvalid(Endereço, Comprimento) |
Determina se o intervalo de memória que começa em Address e se estende para bytes de Length é válido. Se a memória for válida, $vvalid avaliará como 1. Se a memória for inválida, $vvalid avaliará como 0. |
Exemplos
Veja a seguir como usar o intervalo de memória válida em torno de um módulo carregado
Primeiro, determine o endereço da área de interesse, por exemplo, usando o comando lm (List Loaded Modules).
0:000> lm
start end module name
00007ff6`0f620000 00007ff6`0f658000 notepad (deferred)
00007ff9`591d0000 00007ff9`5946a000 COMCTL32 (deferred)
...
Use $vvalid para verificar um intervalo de memória.
0:000> ? $vvalid(0x00007ff60f620000, 0xFFFF)
Evaluate expression: 1 = 00000000`00000001
Use $vvalid para confirmar que esse intervalo maior é um intervalo de memória inválido.
0:000> ? $vvalid(0x00007ff60f620000, 0xFFFFF)
Evaluate expression: 0 = 00000000`00000000
Este também é um intervalo inválido.
0:000> ? $vvalid(0x0, 0xF)
Evaluate expression: 0 = 00000000`00000000
Use not para retornar zero quando o intervalo de memória for válido.
0:000> ? not($vvalid(0x00007ff60f620000, 0xFFFF))
Evaluate expression: 0 = 00000000`00000000
Use $imnet para examinar o ponto de entrada de COMCTL32 no qual usamos anteriormente o comando lm para determinar o endereço. Começa em 00007ff9'591d0000.
0:000> ? $iment(00007ff9`591d0000)
Evaluate expression: 140708919287424 = 00007ff9`59269e80
Desmonte o endereço retornado para examinar o código do ponto 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 é exibido na saída confirmando que este é o ponto de entrada deste módulo.
Registros e pseudoregistros em expressões MASM
Você pode usar registros e pseudoregistros dentro de expressões MASM. Você pode adicionar um sinal de arroba (@) antes de todos os registros e pseudoregistros. O sinal de arroba faz com que o depurador acesse o valor mais rapidamente. Esse sinal @ é desnecessário para os registradores baseados em x86 mais comuns. Para outros registros e pseudoregistros, recomendamos que você adicione o sinal de arroba, mas ele não é necessário. Se você omitir o sinal de arroba para os registros menos comuns, o depurador tentará analisar o texto como um número hexadecimal, depois como um símbolo e, finalmente, como um registro.
Você também pode usar um ponto (.) para indicar o ponteiro de instrução atual. Você não deve adicionar um sinal @ antes desse ponto e não pode usar um ponto como o primeiro parâmetro do comando r. Esse ponto tem o mesmo significado do pseudoregistro $ip.
Para obter mais informações sobre registros e pseudoregistros, consulte Sintaxe de registro e Sintaxe de pseudoregistro.
Use o comando r register para ver que o valor do registro @rip é 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
Esse mesmo valor pode ser exibido usando o atalho de ponto.
0:000> ? .
Evaluate expression: 140718141081456 = 00007ffb`7ed00770
Podemos confirmar que todos esses valores são equivalentes e retornar zero se estiverem usando essa expressão MASM.
0:000> ? NOT(($ip = .) AND ($ip = @rip) AND (@rip =. ))
Evaluate expression: 0 = 00000000`00000000
Números de linha de origem em expressões MASM
Você pode usar o arquivo de origem e as expressões de número de linha dentro de expressões MASM. Você deve incluir essas expressões usando acentos graves ('). Para obter mais informações sobre a sintaxe, confira Sintaxe da linha de origem.