Преобразование виртуальных адресов в физические
Большинство команд отладчика используют виртуальные, а не физические адреса в качестве входных и выходных данных. Однако бывают случаи, когда физический адрес может быть полезен.
Существует два способа преобразования виртуального адреса в физический адрес: с помощью расширения !vtop и расширения !pte .
Общие сведения о виртуальных адресах в Windows см. в статье Виртуальные адресные пространства.
Преобразование адресов с помощью !vtop
Предположим, что выполняется отладка целевого компьютера, на котором выполняется процесс MyApp.exe, и вы хотите исследовать 0x0012F980 виртуального адреса. Ниже приведена процедура, используемая с расширением !vtop для определения соответствующего физического адреса.
Преобразование виртуального адреса в физический с помощью !vtop
Убедитесь, что вы работаете в шестнадцатеричном формате. При необходимости задайте текущую базу с помощью команды N 16 .
Определите байтовый индекс адреса. Это число равно наименьшим 12 битам виртуального адреса. Таким образом, 0x0012F980 виртуального адреса имеет байтовый индекс 0x980.
Определите базу каталога адреса с помощью расширения !process :
kd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** .... PROCESS ff779190 SessionId: 0 Cid: 04fc Peb: 7ffdf000 ParentCid: 0394 DirBase: 098fd000 ObjectTable: e1646b30 TableSize: 8. Image: MyApp.exe
Определите номер фрейма страницы базы каталога. Это просто база каталога без трех конечных шестнадцатеричных нулей. В этом примере база каталога является 0x098FD000, поэтому номер кадра страницы 0x098FD.
Используйте расширение !vtop . Первым параметром этого расширения должен быть номер кадра страницы. Вторым параметром !vtop должен быть рассматриваемый виртуальный адрес:
kd> !vtop 98fd 12f980 Pdi 0 Pti 12f 0012f980 09de9000 pfn(09de9)
Второе число, отображаемое в последней строке, — это физический адрес начала физической страницы.
Добавьте индекс байтов в адрес начала страницы: 0x09DE9000 + 0x980 = 0x09DE9980. Это требуемый физический адрес.
Вы можете убедиться, что это вычисление выполнено правильно, отображая память по каждому адресу. Расширение !d\* отображает память по указанному физическому адресу:
kd> !dc 9de9980
# 9de9980 6d206e49 726f6d65 00120079 0012f9f4 In memory.......
# 9de9990 0012f9f8 77e57119 77e8e618 ffffffff .....q.w...w....
# 9de99a0 77e727e0 77f6f13e 77f747e0 ffffffff .'.w>..w.G.w....
# 9de99b0 .....
Команда d* (display Memory) использует виртуальный адрес в качестве аргумента:
kd> dc 12f980
0012f980 6d206e49 726f6d65 00120079 0012f9f4 In memory.......
0012f990 0012f9f8 77e57119 77e8e618 ffffffff .....q.w...w....
0012f9a0 77e727e0 77f6f13e 77f747e0 ffffffff .'.w>..w.G.w....
0012f9b0 .....
Поскольку результаты совпадают, это означает, что физический адрес 0x09DE9980 действительно соответствует 0x0012F980 виртуального адреса.
Преобразование адресов с помощью !pte
Опять же, предположим, что вы изучаете виртуальный адрес 0x0012F980, принадлежащий процессу MyApp.exe. Ниже приведена процедура, используемая с расширением !pte для определения соответствующего физического адреса:
Преобразование виртуального адреса в физический с помощью !pte
Убедитесь, что вы работаете в шестнадцатеричном формате. При необходимости задайте текущую базу с помощью команды N 16 .
Определите байтовый индекс адреса. Это число равно наименьшим 12 битам виртуального адреса. Таким образом, 0x0012F980 виртуального адреса имеет байтовый индекс 0x980.
Задайте для контекста процесса нужный процесс:
kd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** .... PROCESS ff779190 SessionId: 0 Cid: 04fc Peb: 7ffdf000 ParentCid: 0394 DirBase: 098fd000 ObjectTable: e1646b30 TableSize: 8. Image: MyApp.exe kd> .process /p ff779190 Implicit process is now ff779190 .cache forcedecodeuser done
Используйте расширение !pte с виртуальным адресом в качестве аргумента. При этом сведения отображаются в двух столбцах. В левом столбце описывается запись каталога страницы (PDE) для этого адреса; в правом столбце описывается запись таблицы страницы (PTE):
kd> !pte 12f980 VA 0012f980 PDE at C0300000 PTE at C00004BC contains 0BA58067 contains 09DE9067 pfn ba58 ---DA--UWV pfn 9de9 ---DA--UWV
Найдите последнюю строку правого столбца. Появится нотация "pfn 9de9". Номер 0x9DE9 является номером кадра страницы (PFN) этого PTE. Умножьте номер кадра страницы на 0x1000 (например, сместите его влево на 12 бит). Результатом, 0x09DE9000, является физический адрес начала страницы.
Добавьте индекс байтов в адрес начала страницы: 0x09DE9000 + 0x980 = 0x09DE9980. Это требуемый физический адрес.
Это тот же результат, что и при предыдущем методе.
Преобразование адресов вручную
Хотя расширения !ptov и pte предоставляют самый быстрый способ преобразования виртуальных адресов в физические, это преобразование также можно выполнить вручную. Описание этого процесса пролило свет на некоторые детали архитектуры виртуальной памяти.
Структуры памяти различаются по размеру в зависимости от процессора и конфигурации оборудования. Этот пример взят из системы x86, в которую не включено расширение физических адресов (PAE).
Используя 0x0012F980 снова в качестве виртуального адреса, сначала необходимо преобразовать его в двоичный файл вручную или с помощью команды .formats (Show Number Formats).
kd> .formats 12f980
Evaluate expression:
Hex: 0012f980
Decimal: 1243520
Octal: 00004574600
Binary: 00000000 00010010 11111001 10000000
Chars: ....
Time: Thu Jan 15 01:25:20 1970
Float: low 1.74254e-039 high 0
Double: 6.14381e-318
Этот виртуальный адрес представляет собой сочетание трех полей. Биты от 0 до 11 являются индексом байтов. Биты от 12 до 21 являются индексом таблицы страницы. Биты от 22 до 31 являются индексом каталога страницы. Разделив поля, вы:
0x0012F980 = 0y 00000000 00 010010 1111 1001 10000000
Это предоставляет три части виртуального адреса:
Индекс каталога страницы = 0y000000000 = 0x0
Индекс таблицы страницы = 0y0100101111 = 0x12F
Индекс байтов = 0y100110000000 = 0x980
Затем вам потребуется три дополнительных элемента информации для вашей системы.
Размер каждого PTE. Это 4 байта в системах x86, отличных от PAE.
Размер страницы. Это 0x1000 байт.
Виртуальный адрес PTE_BASE. В системе, отличной от PAE, это 0xC0000000.
С помощью этих данных можно вычислить адрес самого PTE:
PTE address = PTE_BASE
+ (page directory index) * PAGE_SIZE
+ (page table index) * sizeof(MMPTE)
= 0xc0000000
+ 0x0 * 0x1000
+ 0x12F * 4
= 0xC00004BC
Это адрес PTE. PTE — это 32-разрядное значение DWORD. Изучите его содержимое:
kd> dd 0xc00004bc L1
c00004bc 09de9067
Этот PTE имеет значение 0x09DE9067. Он состоит из двух полей:
Низкие 12 бит PTE являются флагами состояния. В этом случае эти флаги равны 0x067 или в двоичном формате 0y000001100111. Описание флагов состояния см. на странице справочника по !pte .
Высокие 20 бит PTE равны номеру кадра страницы (PFN) PTE. В этом случае PFN 0x09DE9.
Первый физический адрес на физической странице — это PFN, умноженное на 0x1000 (смещено влево на 12 бит). Индекс байтов — это смещение на этой странице. Таким образом, физический адрес, который вы ищете, 0x09DE9000 + 0x980 = 0x09DE9980. Это тот же результат, который был получен предыдущими методами.