Номера и операторы 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 в качестве сегмента по умолчанию для адресов. Выражения оцениваются в порядке приоритета оператора. Если смежные операторы имеют равный приоритет, выражение вычисляется слева направо.
Вы можете использовать следующие унарные операторы.
Оператор | Значение |
---|---|
+ |
Унарный плюс |
- |
Унарный минус |
not |
Возвращает значение 1, если аргумент равен нулю. Возвращает ноль для любого ненулевого аргумента. |
Привет |
Высокий 16 бит |
low |
Низкий 16 бит |
by |
Байт низкого порядка из указанного адреса. |
$pby |
То же самое, что и за исключением того, что он принимает физический адрес. Можно считывать только физическую память, использующую поведение кэширования по умолчанию. |
wo |
Слово с низким порядком из указанного адреса. |
$pwo |
То же самое, что wo , за исключением того, что он принимает физический адрес. Можно считывать только физическую память, использующую поведение кэширования по умолчанию. |
dwo |
Двойное слово из указанного адреса. |
$pdwo |
То же самое, что dwo , за исключением того, что он принимает физический адрес. Можно считывать только физическую память, использующую поведение кэширования по умолчанию. |
qwo |
Четыре слова из указанного адреса. |
$pqwo |
То же, что и qwo , за исключением того, что он принимает физический адрес. Можно считывать только физическую память, использующую поведение кэширования по умолчанию. |
пои |
Данные размера указателя из указанного адреса. Размер указателя составляет 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
Используйте унарные операторы, чтобы вернуть байт или слово из целевого адреса.
0:000> ? by(0000008e`ed57b108)
Evaluate expression: 9 = 00000000`00000009
0:000> ? wo(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409
Бинарные операторы
Вы можете использовать следующие двоичные операторы. Операторы в каждой ячейке имеют приоритет над операторами в нижних ячейках. Операторы в одной ячейке имеют одинаковый приоритет и анализируются слева направо.
Оператор | Значение |
---|---|
* / mod (или %) |
Умножение Деление целых чисел Модуль (оставшаяся часть) |
+ - |
Дополнение Вычитание |
<< >> >>> |
Сдвиг влево Логическая смена вправо Арифметический сдвиг вправо |
= (или ==) < > <= >= != |
Равно Меньше Больше Меньше или равно Больше или равно Не равно |
и (или &) |
Побитовое И |
xor (или ^) |
Побитовое XOR (эксклюзивное ИЛИ) |
или (или |) |
Побитовое ИЛИ |
Операторы <сравнения , >=, ==, и != оцениваются в 1, если выражение имеет значение true или ноль, если выражение равно false. Единый знак равенства (=) совпадает с двойным знаком равенства (==). Побочные эффекты или назначения нельзя использовать в выражении 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 с помощью функции strcmp C. |
$sicmp("String1", "String2") |
Оценивается как -1, 0 или 1, например функция 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 отображается в выходных данных, подтверждающих, что это точка входа для этого модуля.
Регистры и псевдорегистрации в выражениях MASM
В выражениях MASM можно использовать регистры и псевдорегистрации. Вы можете добавить по знаку (@) перед всеми регистрами и псевдорегистрами. При входе отладчик быстрее обращается к значению. Этот знак @не требуется для наиболее распространенных регистров на основе x86. Для других регистров и псевдорегистрирующих регистров рекомендуется добавить знак при входе, но на самом деле это не обязательно. Если вы опустите знак для менее распространенных регистров, отладчик пытается проанализировать текст как шестнадцатеричное число, а затем в качестве символа и, наконец, как регистр.
Можно также использовать точку (.) для указания текущего указателя инструкции. Не следует добавлять знак @до этого периода, и вы не можете использовать период в качестве первого параметра команды r. Этот период имеет то же значение, что и $ip псевдорегистрировать.
Дополнительные сведения о регистрах и псевдорегистрирующих регистрах см. в разделе "Регистр синтаксис " и "Псевдорегистрирующий синтаксис".
Используйте команду 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. Эти выражения необходимо заключить с помощью серьезных акцентов ('). Дополнительные сведения о синтаксисе см. в разделе "Синтаксис исходной строки".