Поделиться через


Номера и операторы MASM

В этом разделе описывается использование синтаксиса выражения макросов Майкрософт (MASM) с инструментами отладки Windows.

Отладчик принимает два различных типа числовых выражений: выражения C++ и выражения MASM. Каждое из этих выражений соответствует собственным правилам синтаксиса входных и выходных данных.

Дополнительные сведения об использовании каждого типа синтаксиса см. в разделе "Оценка выражений " и ? (Вычислять выражение).

В этом примере используется ? Команда отображает значение регистра указателя инструкции с помощью вычислителя выражений MASM.

0:000> ? @rip
Evaluate expression: 140709230544752 = 00007ff9`6bb40770

Установка средства оценки выражений в MASM

Используйте expr (выбор вычислителя выражений), чтобы узнать, что такое средство оценки выражений по умолчанию, и измените его на MASM.

0:000> .expr /s masm
Current expression evaluator: MASM - Microsoft Assembler expressions

Теперь, когда средство оценки выражений по умолчанию было изменено, команду ? (Вычислять выражение) можно использовать для отображения выражений MASM. В этом примере в регистр rip добавляется шестнадцатеричное значение 8.

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

Ссылка на регистр @rip описана более подробно в описании синтаксиса регистра.

Числа в выражениях отладчика MASM

В выражения MASM можно поместить числа в любом из оснований 16, 10, 8 или 2.

Используйте команду n (Set Number Base), чтобы задать для радикса по умолчанию значение 16, 10 или 8. Затем все числа, не имеющие префикса, интерпретируются в этой базе. Можно переопределить радикс по умолчанию, указав префикс 0x (шестнадцатеричный), префикс 0n (десятичный), префикс 0t (восьмерично) или 0y префикс (двоичный).

Вы также можете указать шестнадцатеричные числа, добавив h после числа. В числах можно использовать прописные или строчные буквы. Например, "0x4AB3", "0X4aB3", "4AB3h", "4ab3h" и "4aB3H" имеют то же значение.

Если вы не добавляете число после префикса в выражении, число считывается как 0. Таким образом, можно написать значение 0 как 0, префикс, за которым следует 0, и только префикс. Например, в шестнадцатеричном, "0", "0x0" и "0x" имеют то же значение.

Шестнадцатеричные 64-разрядные значения можно ввести в формате xxxx'xxxx. Вы также можете опустить серьезный акцент ('). Если включить серьезный акцент, автоматическое расширение знака отключено.

В этом примере показано, как добавить десятичное, восьмеричное и двоичное значение для регистрации 10.

? @r10 + 0x10 + 0t10 + 0y10
Evaluate expression: 26 = 00000000`0000001a

Символы в выражениях MASM отладчика

В выражениях MASM числовое значение любого символа является его адресом памяти. В зависимости от того, к какому символу относится, этот адрес может быть адресом глобальной переменной, локальной переменной, функции, сегмента, модуля или любой другой распознанной метки.

Чтобы указать, с каким модулем связан адрес, добавьте имя модуля и восклицательный знак (!) перед именем символа. Если символ может быть интерпретирован как шестнадцатеричное число, добавьте имя модуля и восклицательный знак или просто восклицательный знак перед именем символа. Дополнительные сведения о распознавании символов см. в разделе "Синтаксис символов" и "Сопоставление символов".

Используйте две двоеточия (::) или два символа подчеркивания (__), чтобы указать члены класса.

Используйте серьезный акцент (') или апостроф (') в имени символа, только если добавить имя модуля и восклицательный знак перед символом.

Числовые операторы в выражениях MASM

Вы можете изменить любой компонент выражения с помощью унарного оператора. Можно объединить любые два компонента с помощью двоичного оператора. Унарные операторы имеют приоритет над двоичными операторами. При использовании нескольких двоичных операторов операторы следуют фиксированным правилам приоритета, описанным в следующих таблицах.

Для переопределения правил приоритета всегда можно использовать круглые скобки.

Если часть выражения MASM заключена в скобки и два знака (@@) отображаются перед выражением, выражение интерпретируется в соответствии с правилами выражений C++. Нельзя добавить пробел между двумя знаками @ и открывающей скобкой. Вы также можете указать средство оценки выражений с помощью @@c++( ... ) или @@masm( ... ).

При выполнении арифметических вычислений средство оценки выражений MASM обрабатывает все числа и символы как ULONG64 типы.

Унарные операторы адресов предполагают ds в качестве сегмента по умолчанию для адресов. Выражения оцениваются в порядке приоритета оператора. Если смежные операторы имеют равный приоритет, выражение вычисляется слева направо.

Вы можете использовать следующие унарные операторы.

Оператор Значение

+

Унарный плюс

-

Унарный минус

не

Возвращает значение 1, если аргумент равен нулю. Возвращает ноль для любого ненулевого аргумента.

Привет

Высокий 16 бит

низкий

Низкий 16 бит

от

Байт низкого порядка из указанного адреса.

$pby

То же самое, что и за исключением того, что он принимает физический адрес. Можно считывать только физическую память, использующую поведение кэширования по умолчанию.

wo

Слово с низким порядком из указанного адреса.

$pwo

То же самое, что wo , за исключением того, что он принимает физический адрес. Можно считывать только физическую память, использующую поведение кэширования по умолчанию.

dwo

Двойное слово из указанного адреса.

$pdwo

То же самое, что dwo , за исключением того, что он принимает физический адрес. Можно считывать только физическую память, использующую поведение кэширования по умолчанию.

qwo

Четыре слова из указанного адреса.

$pqwo

То же, что и qwo за исключением того, что она принимает физический адрес. Можно считывать только физическую память, использующую поведение кэширования по умолчанию.

poi

Данные размера указателя из указанного адреса. Размер указателя составляет 32 бита или 64 бита. В отладке ядра этот размер основан на процессоре целевого компьютера. Таким образом, poi является лучшим оператором для использования, если требуются данные размером с указатель.

$ppoi

То же, что poi, но с использованием физического адреса. Можно считывать только физическую память, использующую поведение кэширования по умолчанию.

Примеры

В следующем примере показано, как использовать poi для разыменования указателя, чтобы увидеть значение, хранящееся по этому адресу памяти.

Сначала определите адрес памяти, интересующий вас. Например, можно просмотреть структуру потока и решить, что нужно увидеть значение 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 находится 0x108 за пределами начала TEB.

0:000> ? @$teb + 0x108
Evaluate expression: 613867303176 = 0000008e`ed57b108

Используйте poi для разыменования этого адреса.

0:000> ? poi(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409

Возвращаемое значение 409 соответствует значению CurrentLocale в структуре TEB.

Или используйте poi и круглые скобки для расшифровки вычисляемого адреса.

0:000> ? poi(@$teb + 0x108)
Evaluate expression: 1033 = 00000000`00000409

Используйте унарные операторы by или wo, чтобы вернуть байт или слово из целевого адреса.

0:000> ? by(0000008e`ed57b108)
Evaluate expression: 9 = 00000000`00000009
0:000> ? wo(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409

Двоичные операторы

Вы можете использовать следующие двоичные операторы. Операторы в каждой ячейке имеют приоритет над операторами в нижних ячейках. Операторы в одной ячейке имеют одинаковый приоритет и анализируются слева направо.

Оператор Значение

*

/

mod (или %)

Умножение

Деление целых чисел

Модуль (оставшаяся часть)

+

-

Дополнение

Вычитание

<<

>>

>>>

Сдвиг влево

Логическая смена вправо

Арифметический сдвиг вправо

= (или ==)

<

>

<=

>=

!=

Равняется

Меньше

Больше чем

Меньше или равно

Больше или равно

Не равно

и (или &)

Битовое И

xor (или ^)

Побитовое XOR (исключающее ИЛИ)

или (|)

Битовое ИЛИ

Операторы <, >, =, ==, и != оцениваются как 1, если выражение истинно, или как 0, если выражение ложно. Единый знак равенства (=) совпадает с двойным знаком равенства (==). Побочные эффекты или назначения нельзя использовать в выражении MASM.

Недопустимая операция (например, деление по нулю) приводит к возврату ошибки Operand в окно команды отладчика.

Мы можем проверить, соответствует ли возвращаемое значение 0x409 с помощью оператора сравнения == .

0:000> ? poi(@$teb + 0x108)==0x409
Evaluate expression: 1 = 00000000`00000001

Нечисловые операторы в выражениях MASM

Кроме того, в выражениях MASM можно использовать следующие дополнительные операторы.

Оператор Значение

$fnsucc(FnAddress, RetVal, Flag)

Интерпретирует значение RetVal как возвращаемое значение для функции, расположенной по адресу FnAddress . Если это возвращаемое значение квалифициируется как код успешного выполнения, $fnsucc возвращает значение TRUE. В противном случае $fnsucc возвращает значение FALSE.

Если возвращаемый тип — BOOL, bool, HANDLE, HRESULT или NTSTATUS, $fnsucc правильно понимает, является ли указанное возвращаемое значение кодом успеха. Если возвращаемый тип является указателем, все значения, отличные от NULL , соответствуют кодам успешности. Для любого другого типа успех определяется значением Flag. Если Флаг равен 0, ненулевое значение RetVal означает успех. Если флаг равен 1, значение RetVal равно нулю — это успех.

$iment (адрес)

Возвращает адрес точки входа изображения в загруженном списке модулей. Адрес указывает базовый адрес переносимого исполняемого файла (PE). Запись найдена путем поиска точки входа изображения в заголовке изображения PE, указанного адресом .

Эту функцию можно использовать для обоих модулей, которые уже находятся в списке модулей, и для установки неразрешенных точек останова с помощью команды bu .

$scmp("String1", "String2")

Вычисляется в -1, 0 или 1, подобно функции strcmp с помощью C-функции strcmp.

$sicmp("String1", "String2")

Оценивается как -1, 0 или 1, так же, как и функция stricmp в Microsoft Win32.

$spat("String", "Pattern")

Вычисляется как TRUE или FALSE в зависимости от того, соответствует ли Строкашаблону. Регистр при сопоставлении не учитывается. Шаблон может содержать различные подстановочные знаки и спецификаторы. Дополнительные сведения о синтаксисе см. в разделе "Синтаксис подстановочных знаков строки".

$vvalid(адрес, длина)

Определяет, является ли диапазон памяти, начинающийся с адрес и протяженностью длиной байт, допустимым. Если память действительна, $vvalid принимает значение 1. Если память недействительна, $vvalid принимает значение 0.

Примеры

Ниже показано, как исследовать диапазон допустимой памяти вокруг загруженного модуля.

Сначала определите адрес интересующей области, например с помощью команды lm (команда List Loaded Modules ).


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

Используйте $vvalid для проверки диапазона памяти.

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

Используйте $vvalid для подтверждения того, что этот большой диапазон является недопустимым диапазоном памяти.

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

Это также недопустимый диапазон.

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

Используйте не для возврата нуля, если диапазон памяти действителен.

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

Используйте $imnet, чтобы просмотреть точку входа COMCTL32, адрес которой мы ранее определили с помощью команды lm. Она начинается с 0007ff9'591d00000.

0:000> ? $iment(00007ff9`591d0000)
Evaluate expression: 140708919287424 = 00007ff9`59269e80

Дизассемблируйте возвращенный адрес для проверки кода точки входа.

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 отображается в выходных данных, подтверждающих, что это точка входа для этого модуля.

Регистр и Pseudo-Registers в выражениях MASM

В выражениях MASM можно использовать регистры и псевдорегистрации. Вы можете добавить знак (@) перед всеми регистрами и псевдорегистрами. Знак @ позволяет отладчику быстрее получать доступ к значению. Этот знак @не требуется для наиболее распространенных регистров на основе x86. Для других регистров и псевдорегистрирующих регистров рекомендуется добавить знак при входе, но на самом деле это не обязательно. Если вы опустите знак @ для реже используемых регистров, отладчик пытается сначала проанализировать текст как шестнадцатеричное число, затем как символ, и, наконец, как регистр.

Можно также использовать точку (.) для указания текущего указателя команд. Не следует добавлять знак @до этого периода, и вы не можете использовать период в качестве первого параметра команды r. Этот период времени обозначает то же, что и $ip псевдорегистр.

Дополнительные сведения о регистрах и псевдорегистрах см. в Синтаксисе регистров и СинтаксисеPseudo-Register.

Используйте команду r register, чтобы узнать, что значение регистра @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

Это же значение можно отобразить с помощью . ярлык периода.

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

Мы можем подтвердить, что эти значения эквивалентны и возвращают ноль, если они есть, используя это выражение MASM.

0:000>  ? NOT(($ip = .) AND ($ip = @rip) AND (@rip =. ))
Evaluate expression: 0 = 00000000`00000000

Исходные номера строк в выражениях MASM

В выражениях MASM вы можете использовать выражения исходных файлов и номеров строк. Эти выражения необходимо заключить с помощью серьезных акцентов ('). Дополнительные сведения о синтаксисе см. в разделе "Синтаксис исходной строки".

См. также

Выражения MASM и выражения C++

Примеры смешанных выражений

Номера и операторы C++

Расширение знака

? (Оценить выражение)