Share via


Números e operadores MASM

Este tópico descreve o uso da sintaxe de expressão MASM (Microsoft Macro Assembler) 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 ? (Avaliar expressão).

Neste exemplo, o ? 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 (Escolher Avaliador de Expressão) para ver qual é o avaliador de expressão padrão e alterá-lo 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 ? (Avaliar expressão) O comando pode ser usado para exibir expressões MASM. Este exemplo adiciona o valor hex de 8 ao registro de rip.

0:000> ? @rip + 8
Evaluate expression: 140709230544760 = 00007ff9`6bb40778

A referência de registro de @rip é descrita mais detalhadamente 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 (Definir Base numérica) para definir o radix padrão como 16, 10 ou 8. Todos os números não prefixados são interpretados nessa base. Você pode substituir o radix padrão especificando o prefixo 0x (hexadecimal), o prefixo de 0n (decimal), o prefixo 0t (octal) ou o prefixo 0y (binário).

Você também pode especificar números hexadecimal adicionando um h após o número. Você pode usar letras maiúsculas ou minúsculas em números. Por exemplo, "0x4AB3", "0X4aB3", "4AB3h", "4ab3h" e "4aB3H" têm o mesmo significado.

Se você não adicionar um número após o prefixo em uma expressão, o número será lido como 0. Portanto, você pode gravar 0 como 0, o prefixo seguido por 0 e apenas o prefixo. Por exemplo, em hexadecimal, "0", "0x0" e "0x" têm o mesmo significado.

Você pode inserir valores hexadecimal 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á desabilitada.

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 do 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 o reconhecimento de símbolos, consulte Sintaxe de símbolo e correspondência de símbolos.

Use dois dois dois pontos (::) 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 dois componentes usando um operador binário. Operadores unários têm precedência sobre operadores binários. Quando você usa vários operadores binários, os operadores seguem as regras de precedência fixas 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 em sinais (@@) aparecerem antes da expressão, a expressão será interpretada de acordo com as regras de expressão do C++. Não é possível adicionar um espaço entre os dois em sinais 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.

Operadores de endereço unário assumem ds como o segmento padrão para endereços. As expressões são avaliadas em ordem de precedência do operador. Se operadores adjacentes tiverem precedência igual, a expressão será avaliada da esquerda para a direita.

Você pode usar os operadores unários a seguir.

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 baixa ordem do endereço especificado.

$pby

O mesmo que por, exceto que ele usa 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 baixa ordem do endereço especificado.

$pwo

O mesmo que wo , exceto que ele usa 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 , exceto que ele usa 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 , exceto que ele usa 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 do 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 do ponteiro.

$ppoi

O mesmo que poi , exceto que ele usa 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 desreferenciar 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 examinar 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 desreferenciar esse 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 desreferenciar o 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 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 operadores binários a seguir. 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 (ou %)

Multiplicação

Divisão de inteiros

Módulo (resto)

+

-

Adição

Subtração

<<

>>

>>>

Shift esquerda

Deslocamento lógico para a direita

Deslocamento aritmético para a direita

= (ou ==)

<

>

<=

>=

!=

Igual a

Menor que

Maior que

Menor que ou igual a

Maior que ou igual a

É diferente de

e (ou &)

AND bit a bit

xor (ou ^)

XOR bit a bit (OR exclusivo)

ou (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 (==). Você não pode usar efeitos colaterais ou atribuições dentro de uma expressão MASM.

Uma operação inválida (como divisão por zero) resulta em um "erro operando" é retornado para a janela Comando do Depurador.

Podemos marcar que o valor retornado corresponde 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 operadores adicionais a seguir em expressões MASM.

Operador Significado

$fnsucc(FnAddress, RetVal, Flag)

Interpreta o valor RetVal como um valor retornado para a função localizada no endereço FnAddress . Se esse valor retornado se qualificar como um código de êxito, $fnsucc retornará TRUE. Caso contrário, $fnsuccretornará FALSE.

Se o tipo de retorno for BOOL, bool, HANDLE, HRESULT ou NTSTATUS, $fnsucc entenderá corretamente se o valor retornado 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 Sinalizador. Se Sinalizador for 0, um valor diferente de zero de RetVal será êxito. Se Sinalizador for 1, um valor zero de RetVal será bem-sucedido.

$iment (Endereço)

Retorna o endereço do ponto de entrada da imagem na lista de módulos carregados. O endereço especifica o endereço base da imagem PE (Portable Executable). A entrada é encontrada pesquisando o ponto de entrada da imagem no cabeçalho de imagem PE da imagem especificada por Address .

Você pode usar essa função para ambos os 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")

É avaliado como -1, 0 ou 1, como o strcmp usando a função strcmp C.

$sicmp("String1", "String2")

É avaliado como -1, 0 ou 1, como a função stricmp 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. O padrão pode conter uma variedade de caracteres curinga e especificadores. Para obter mais informações sobre a sintaxe, consulte Sintaxe curinga de cadeia de caracteres.

$vvalid(Address,Length)

Determina se o intervalo de memória que começa em Endereço e se estende para Bytes de comprimento é válido. Se a memória for válida, $vvalid será avaliada como 1. Se a memória for inválida, $vvalid será avaliada como 0.

Exemplos

O exemplo a seguir mostra como usar a investigação do 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 (Listar Módulos Carregados ).


0:000> lm
start             end                 module name
00007ff6`0f620000 00007ff6`0f658000   notepad    (deferred)
00007ff9`591d0000 00007ff9`5946a000   COMCTL32   (deferred)        
...

Use $vvalid para marcar um intervalo de memória.

0:000> ? $vvalid(0x00007ff60f620000, 0xFFFF)
Evaluate expression: 1 = 00000000`00000001

Use $vvalid para confirmar se esse intervalo maior é um intervalo de memória inválido.

0:000> ? $vvalid(0x00007ff60f620000, 0xFFFFF)
Evaluate expression: 0 = 00000000`00000000

Esse também é um intervalo inválido.

0:000> ? $vvalid(0x0, 0xF)
Evaluate expression: 0 = 00000000`00000000

Use para não 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 que 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 esse é o ponto de entrada para este módulo.

Registros e Pseudo-Registers em expressões MASM

Você pode usar registros e pseudo-registros em expressões MASM. Você pode adicionar um sinal de at (@) antes de todos os registros e pseudo-registros. O sinal em faz com que o depurador acesse o valor mais rapidamente. Esse sinal @ é desnecessário para os registros mais comuns baseados em x86. Para outros registros e pseudo-registros, recomendamos que você adicione o sinal de at, mas ele não é realmente necessário. Se você omitir o sinal em para os registros menos comuns, o depurador tentará analisar o texto como um número hexadecimal, depois como um símbolo e, por fim, 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 período e não pode usar um ponto como o primeiro parâmetro do comando r. Esse período tem o mesmo significado que o pseudo-registro $ip .

Para obter mais informações sobre registros e pseudo-registros, consulte Sintaxe de registro e sintaxe pseudo-registro.

Use o comando r register para ver se o valor do @rip registro é 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 período.

0:000> ? .
Evaluate expression: 140718141081456 = 00007ffb`7ed00770

Podemos confirmar se esses valores são todos equivalentes e retornar zero se forem, 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 expressões de número de linha e arquivo de origem em expressões MASM. Você deve colocar essas expressões usando acentos graves ('). Para obter mais informações sobre a sintaxe, consulte Sintaxe de linha de origem.

Confira também

Expressões MASM versus expressões C++

Exemplos de expressões mistas

Números e operadores C++

Assinar Extensão

? (Avaliar expressão)