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


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

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

Существует два способа преобразования виртуального адреса в физический адрес: с помощью расширения !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 снова в качестве виртуального адреса, сначала необходимо преобразовать его в двоичный вид, вручную либо с помощью команды .форматов (показать форматы чисел):

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 - или в двоичном формате 0y00000110011. Для объяснения флагов состояния см. на справочной странице !pte.

  • Высокие 20 битов PTE соответствуют номеру кадра страницы (PFN) PTE. В этом случае PFN — 0x09DE9.

Первый физический адрес на физической странице — это PFN, умноженный на 0x1000 (смещенный влево 12 бит). Индекс байтов — это смещение на этой странице. Таким образом, физический адрес, который вы ищете, 0x09DE9000 + 0x980 = 0x09DE9980. Это тот же результат, полученный предыдущими методами.