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


Синтаксис адресов и диапазона адресов

В отладчике можно указать адреса несколькими способами.

Адреса обычно являются виртуальными, за исключением случаев, когда документация специально указывает другой тип адреса. В пользовательском режиме отладчик интерпретирует виртуальные адреса в соответствии с каталогом страниц текущего процесса. В режиме ядра отладчик интерпретирует виртуальные адреса в соответствии с каталогом страницы процесса, который указывает контекст процесса . Вы также можете напрямую задать контекст адреса в пользовательском режиме. Дополнительные сведения о контексте адреса в пользовательском режиме см. в разделе .context (Set User-Mode Address Context).

В выражениях MASM можно использовать оператор poi для расшифровки любого указателя. Например, если указатель на адрес 0x0000008e'ed57b108 указывает на расположение адреса 0x805287637256, следующие две команды эквивалентны.

0:000> dd 805287637256
0:000> dd poi(000000bb`7ee23108)

Пример отображения адреса памяти

Чтобы просмотреть пример использования poi, определите смещение для CurrentLocale блока среды потока (TEB). Используйте команду dx для отображения @$teb, который является примером псевдорегистров, которые содержат общие адреса, такие как текущее расположение счетчика программ.

0:000> dx @$teb
@$teb                 : 0x1483181000 [Type: _TEB *]

...

    [+0x108] CurrentLocale    : 0x409 [Type: unsigned long]

CurrentLocale — +0x108 с начала TEB. Затем определите адрес памяти этого местоположения.

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

Используйте poi для разыменования этого адреса, чтобы увидеть, что он содержит значение CurrentLocale, равное 0x409.

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

В выражениях отладчика C++ указатели ведут себя как указатели в C++. Однако числа интерпретируются как целые числа. Если вы хотите разыменовать числовое значение, может потребоваться сначала привести его к нужному типу, как показано в следующем примере.

Чтобы попробовать это, используйте .expr , чтобы задать средство оценки выражений на C++.

0:000> .expr /s C++
Current expression evaluator: C++ - C++ source expressions

Устанавливая средство оценки выражений на C++, мы можем использовать приведение к типу long.

0:000> d *((long*)0x00000014`83181108 ) 
00000000`00000409  ???????? ???????? ???????? ????????

Дополнительные сведения о приведении числовых значений см. в разделе C++ Numbers and Operators.

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

0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions

0:000> ? @@masm(poi(00000078`267d7108))
Evaluate expression: 1033 = 00000000`00000409

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

Можно также указать адрес в приложении, указав исходное имя исходного файла и номер строки. Дополнительные сведения об указании этой информации см. в разделе "Синтаксис исходной строки".

Диапазоны адресов

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

Чтобы указать диапазон по паре адресов, укажите начальный адрес и конечный адрес. Например, в следующем примере представлен диапазон 8 байт, начиная с адреса 0x00001000.

0x00001000  0x00001007

Чтобы указать диапазон адресов по количеству адресов и объектов, укажите аргумент адреса, букву L (верхний или нижний регистр) и аргумент значения. Адрес указывает начальный адрес. Значение указывает количество объектов для проверки или отображения. Размер объекта зависит от команды. Например, если размер объекта равен 1 байту, следующий пример — это диапазон 8 байтов, начиная с адреса 0x00001000.

0x00001000  L8

Однако если размер объекта является двойным словом (32 бита или 4 байта), следующие два диапазона дают диапазон 8-байтов.

0x00001000  0x00001007
0x00001000  L2

Указатель диапазона размеров L

Существуют два других способа указать значение (LSize диапазон спецификатора):

  • L?Размер (с вопросительным знаком) означает то же, что и LРазмер, за исключением того, что L?Размер снимает автоматическое ограничение диапазона отладчика. Как правило, существует ограничение диапазона в 256 МБ, так как большие диапазоны являются типографическими ошибками. Если вы хотите указать диапазон, размер которого превышает 256 МБ, необходимо использовать L?Синтаксис размера .

  • L-SizeРазмер (с дефисом) задает диапазон длины размера, который заканчивается на заданном адресе. Например, 8000000 L20 указывает диапазон от 0x80000000 до 0x8000001F, а 80000000 L-20 указывает диапазон от 0x7FFFFFE0 до 0x7FFFFFFF.

Некоторые команды, запрашивающие диапазоны адресов, принимают один адрес в качестве аргумента. В этой ситуации команда использует некоторое число объектов по умолчанию для вычисления размера диапазона. Как правило, команды, для которых диапазон адресов является окончательным параметром, разрешают этот синтаксис. Точный синтаксис и размер диапазона по умолчанию для каждой команды см. в справочных разделах для каждой команды.

Пример диапазона памяти поиска

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

0:000> ? @rip 
Evaluate expression: 140720561719153 = 00007ffc`0f180771

Затем мы будем искать начиная с 00007ffc'0f180771, для 100000 с помощью команды s (Search Memory). Мы указываем диапазон для поиска с помощью L100000.

0:000> s -a 00007ffc`0f180771 L100000 "ntdll"  
00007ffc`0f1d48fa  6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00  ntdll\ldrinit.c.
00007ffc`0f1d49c2  6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00  ntdll\ldrmap.c..
00007ffc`0f1d4ab2  6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63  ntdll\ldrredirec
00007ffc`0f1d4ad2  6e 74 64 6c 6c 5c 6c 64-72 73 6e 61 70 2e 63 00  ntdll\ldrsnap.c.
...

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

0:000> s -a 0x00007ffc`0f180771 0x00007ffc`0f280771 "ntdll"  
00007ffc`0f1d48fa  6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00  ntdll\ldrinit.c.
00007ffc`0f1d49c2  6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00  ntdll\ldrmap.c..
00007ffc`0f1d4ab2  6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63  ntdll\ldrredirec
00007ffc`0f1d4ad2  6e 74 64 6c 6c 5c 6c 64-72 73 6e 61 70 2e 63 00  ntdll\ldrsnap.c.
...

Наконец, мы можем искать назад в диапазоне памяти с помощью параметра L-length.

0:000> s -a 00007ffc`0f1d4ad2 L-100000 "ntdll"  
00007ffc`0f1d48fa  6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00  ntdll\ldrinit.c.
00007ffc`0f1d49c2  6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00  ntdll\ldrmap.c..
00007ffc`0f1d4ab2  6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63  ntdll\ldrredirec

Пример разборки памяти

В этом примере используется команда u (unassemble) и параметр L для дизассемблирования трех байтов кода.

0:000> u 00007ffc`0f1d48fa L3
ntdll!`string'+0xa:
00007ffc`0f1d48fa 6e              outs    dx,byte ptr [rsi]
00007ffc`0f1d48fb 7464            je      ntdll!`string'+0x21 (00007ffc`0f1d4961)
00007ffc`0f1d48fd 6c              ins     byte ptr [rdi],dx

Или укажите три байта памяти, чтобы их дизассемблировать.

0:000> u 00007ffc`0f1d48fa 00007ffc`0f1d48fd
ntdll!`string'+0xa:
00007ffc`0f1d48fa 6e              outs    dx,byte ptr [rsi]
00007ffc`0f1d48fb 7464            je      ntdll!`string'+0x21 (00007ffc`0f1d4961)
00007ffc`0f1d48fd 6c              ins     byte ptr [rdi],dx

Режимы адресации и поддержка сегментов

На платформах x86 CDB и KD поддерживают следующие режимы адресации. Эти режимы отличаются их префиксами.

Приставка Имя Типы адресов
% плоский 32-разрядные адреса (также 16-разрядные селекторы, указывающие на 32-разрядные сегменты) и 64-разрядные адреса в 64-разрядных системах.
& virtual 86 Адреса реального режима. Только на основе x86.
# простой Адреса в режиме реального режима. Только на основе x86.

Разница между режимами обычного и виртуального 86 заключается в том, что обычный 16-разрядный адрес использует значение сегмента в качестве селектора и ищет дескриптор сегмента. Но виртуальный 86-адрес не использует селекторы и вместо этого проецируется непосредственно в нижние 1 МБ.

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

Обсудить аргументы

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

Синтаксис Значение

смещение

Абсолютный адрес в пространстве виртуальной памяти с типом, соответствующим текущему режиму выполнения. Например, если текущий режим выполнения равен 16 биту, смещение равно 16 биту. Если режим выполнения сегментирован в 32-разрядном режиме, смещение равно 32-разрядному сегменту.

&[[ сегмент:]] смещение

Реальный адрес. основанные на x86 и x64.

%segment:[[смещение]]

Сегментированные 32-разрядные или 64-разрядные адреса. на основе x86 и на основе x64.

%[[смещение]]

Абсолютный адрес (32-разрядная или 64-разрядная) в пространстве виртуальной памяти. на основе x86 и на основе x64.

name[[ +|- ]] смещение

Линейный 32-разрядный или 64-разрядный адрес. имя может быть любым символом. смещение задаёт величину смещения. Это смещение может быть любым режимом адреса, который указывает префикс. Префикс не указывает адрес режима по умолчанию. Смещение можно указать как положительное (+) или отрицательное значение (-).

Используйте команду dg (селектор отображения) для просмотра сведений о дескрипторе сегмента.

См. также

Чтобы отобразить сведения о памяти, используйте команду !address .

Для поиска памяти используйте команду s (Search Memory).

Чтобы отобразить содержимое памяти, используйте команду d, da, db, dc, dd, dD, df, dp, dq, du, dw (display Memory).

Сведения о том, как можно просматривать и изменять память с помощью окна памяти, см. в разделе "Использование окна памяти".