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


Преобразование виртуальных адресов в физические

Большинство команд отладчика используют виртуальные, а не физические адреса в качестве входных и выходных данных. Однако бывают случаи, когда физический адрес может быть полезен.

Существует два способа преобразования виртуального адреса в физический адрес: с помощью расширения !vtop и расширения !pte .

Общие сведения о виртуальных адресах в Windows см. в статье Виртуальные адресные пространства.

Преобразование адресов с помощью !vtop

Предположим, что выполняется отладка целевого компьютера, на котором выполняется процесс MyApp.exe, и вы хотите исследовать 0x0012F980 виртуального адреса. Ниже приведена процедура, используемая с расширением !vtop для определения соответствующего физического адреса.

Преобразование виртуального адреса в физический с помощью !vtop

  1. Убедитесь, что вы работаете в шестнадцатеричном формате. При необходимости задайте текущую базу с помощью команды N 16 .

  2. Определите байтовый индекс адреса. Это число равно наименьшим 12 битам виртуального адреса. Таким образом, 0x0012F980 виртуального адреса имеет байтовый индекс 0x980.

  3. Определите базу каталога адреса с помощью расширения !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
    
  4. Определите номер фрейма страницы базы каталога. Это просто база каталога без трех конечных шестнадцатеричных нулей. В этом примере база каталога является 0x098FD000, поэтому номер кадра страницы 0x098FD.

  5. Используйте расширение !vtop . Первым параметром этого расширения должен быть номер кадра страницы. Вторым параметром !vtop должен быть рассматриваемый виртуальный адрес:

    kd> !vtop 98fd 12f980
    Pdi 0 Pti 12f
    0012f980 09de9000 pfn(09de9)
    

    Второе число, отображаемое в последней строке, — это физический адрес начала физической страницы.

  6. Добавьте индекс байтов в адрес начала страницы: 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

  1. Убедитесь, что вы работаете в шестнадцатеричном формате. При необходимости задайте текущую базу с помощью команды N 16 .

  2. Определите байтовый индекс адреса. Это число равно наименьшим 12 битам виртуального адреса. Таким образом, 0x0012F980 виртуального адреса имеет байтовый индекс 0x980.

  3. Задайте для контекста процесса нужный процесс:

    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
    
  4. Используйте расширение !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
    
  5. Найдите последнюю строку правого столбца. Появится нотация "pfn 9de9". Номер 0x9DE9 является номером кадра страницы (PFN) этого PTE. Умножьте номер кадра страницы на 0x1000 (например, сместите его влево на 12 бит). Результатом, 0x09DE9000, является физический адрес начала страницы.

  6. Добавьте индекс байтов в адрес начала страницы: 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. Это тот же результат, который был получен предыдущими методами.