Изменение nx-бита непосредственно из структур уровня подкачки

Я изучаю трансляцию виртуальных адресов в Windows 10 x64. Я также читал о PML4, PDP, PDE и PTE, и теперь я пытаюсь изменить nx-бит стека, чтобы выполнить код в стеке, изменив структуры подкачки.

Я видел следующее изображение, которое описывает nx-бит в PML4E, PDPE, PDE и PTE:

Структура подкачки

Давайте предположим, что мы создали Windbg для отладки ядра с помощью VMWare, а на гостевой машине мы отлаживаем простое приложение с помощью xdbg64.

После присоединения к целевому процессу с помощью xdbg64 теперь rsp указывает на 00000089F06FF848. Я меняю поток программы и выполняю jmp rsp, и теперь rip указывает на rsp, но дает access_violation exception из-за DEP, поэтому я не могу выполнить какой-либо код в стеке. (ранее я изменил стек на что-то вроде xor rax,rax, чтобы там был правильный ассемблерный код).

Теперь я приостанавливаю гостевую машину с помощью Windbg с хоста и, чтобы сделать правильный перевод, меняю явный процесс на целевой процесс, используя .process /f /i ffffa9841d9952c0, и после нажатия g теперь наш cr3 действителен для перевода.

Затем я использую следующую команду, чтобы получить физический адрес PML4E, PDPE, PDE, PTE:

kd> !vtop 0 00000089F06FF848
Amd64VtoP: Virt 00000089`f06ff848, pagedir 34848000
Amd64VtoP: PML4E 34848008
Amd64VtoP: PDPE 3316e138
Amd64VtoP: PDE 340efc18
Amd64VtoP: PTE 31de77f8
Amd64VtoP: Mapped phys 68a6b848
Virtual address 89f06ff848 translates to physical address 68a6b848.

Из картинки выше 63-й бит предназначен для NX-Bit, тогда я получаю все записи(PML4E, PDPE, PDE, PTE), чтобы увидеть, что там есть.

В случае PML4E это:

kd> !db 34848008
#34848008 67 e8 16 33 00 00 00 0a-00 00 00 00 00 00 00 00 g..3............
#34848018 67 88 77 55 00 00 00 0a-00 00 00 00 00 00 00 00 g.wU............
#34848028 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#34848038 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#34848048 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#34848058 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#34848068 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#34848078 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

Преобразование 67 e8 16 33 00 00 00 0a (01100111 11101000 00010110 00110011 00000000 00000000 00000000 00001010)

to

67 e8 16 33 00 00 00 0b (01100111 11101000 00010110 00110011 00000000 00000000 00000000 00001011)

(Обратите внимание на жирный бит.)

ПДПЭ это:

kd> !db 3316e138
#3316e138 67 f8 0e 34 00 00 00 0a-00 00 00 00 00 00 00 00 g..4............
#3316e148 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#3316e158 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#3316e168 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#3316e178 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#3316e188 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#3316e198 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#3316e1a8 00 00 00 00 00 00 00 00-67 f8 0e 34 00 00 00 0a00 00 00 00 00 00 00 00 ................

Преобразование 67 f8 0e 34 00 00 00 0a (01100111 11111000 00001110 00110100 00000000 00000000 00000000 00001010)

to

67 f8 0e 34 00 00 00 0b (01100111 11111000 00001110 00110100 00000000 00000000 00000000 00001011)

ПДЭ это:

kd> !db 340efc18
#340efc18 67 78 de 31 00 00 00 0a-00 00 00 00 00 00 00 00 gx.1............
#340efc28 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#340efc38 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#340efc48 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#340efc58 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#340efc68 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#340efc78 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#340efc88 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

Преобразование 67 78 de 31 00 00 00 0a (01100111 01111000 11011110 00110001 00000000 00000000 00000000 00001010)

to

67 78 de 31 00 00 00 0b (01100111 01111000 11011110 00110001 00000000 00000000 00000000 00001011)

А ПТЭ это:

kd> !db 31de77f8
#31de77f8 67 b8 a6 68 00 00 00 81-00 00 00 00 00 00 00 00 g..h............
#31de7808 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#31de7818 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#31de7828 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#31de7838 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#31de7848 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#31de7858 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#31de7868 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

И в этом случае я ничего не менял, потому что 67 b8 a6 68 00 00 00 81 равно 01100111 10111000 10100110 01101000 00000000 00000000 00000000 10000001, так как его последний бит равен 1.

На последнем шаге я снова запускаю !vtop, чтобы убедиться, что он по-прежнему транслируется на тот же физический адрес, и вижу, что это правильно (указывает на то же место).

Затем я нажимаю g, чтобы проверить, может ли он выполнить содержимое стека или нет, но я вижу, что он по-прежнему выдает ту же ошибку (access_violation) и не может выполнить этот адрес (rsp).

Итак, у меня есть следующие вопросы:

  1. Что не так с моей модификацией, которая не имеет никакого эффекта?

  2. Я слышал, что у GDT также есть что-то вроде NX-Bit, которое предотвращает выполнение стека. В чем разница между предотвращением выполнения GDT и NX-Bit на уровне подкачки?

  3. Почему существуют 4 уровня, определяющие nx-бит? Влияет ли изменение только одной из вышеуказанных записей, например pml4e, на все остальные записи?


person Migo Lopak    schedule 15.03.2018    source источник


Ответы (1)


Что не так с моей модификацией, которая не имеет никакого эффекта?

Вы должны были исправить бит NX PTE (который является самым значащим битом).

Я только что пропатчил некоторый код в notepad.exe, установил точку входа для выполнения этого кода (nops, за которым следует RET):

Блокнот с кодом

Найдите блокнот:

kd> !process 0 0 notepad.exe PROCESS ffffe000852c5840
    SessionId: 1  Cid: 0108    Peb: 7ff689a4e000  ParentCid: 0d74 FreezeCount 1
    DirBase: 1b1b9000  ObjectTable: ffffc000a6b08280  HandleCount: <Data Not Accessible>
    Image: notepad.exe

Переключите контекст на него:

kd> .process /p /i ffffe000852c5840
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
kd> g
Break instruction exception - code 80000003 (first chance)
nt!DbgBreakPointWithStatus:
fffff803`f63d1300 cc              int     3

Это содержимое RSP (0x64a9b5fdd8), просто чтобы быть уверенным:

kd> db 64a9b5fdd8 L10
00000064`a9b5fdd8  90 90 90 90 90 90 90 90-c3 c3 c3 c3 c3 c3 c3 c3  ................

Проверить виртуальный на физический:

kd> !vtop 0 00000064a9b5fdd8
Amd64VtoP: Virt 00000064a9b5fdd8, pagedir 000000001b1b9000
Amd64VtoP: PML4E 000000001b1b9000
Amd64VtoP: PDPE 0000000019bbdc90
Amd64VtoP: PDE 00000000416bea68
Amd64VtoP: PTE 00000000501bfaf8
Amd64VtoP: Mapped phys 0000000039fcfdd8
Virtual address 64a9b5fdd8 translates to physical address 39fcfdd8.

Двойная проверка физического адреса:

kd> !db 0000000039fcfdd8 L10
#39fcfdd8 90 90 90 90 90 90 90 90-c3 c3 c3 c3 c3 c3 c3 c3 ................

Теперь проверяем PTE:

kd> !dq 00000000501bfaf8 L1
#501bfaf8 82b00000`39fcf867 

Преобразование PTE в двоичный файл:

kd> .formats 82b00000`39fcf867
Evaluate expression:
  Hex:     82b00000`39fcf867
  Decimal: -9029717251904964505
  Octal:   1012600000007177174147
  Binary:  10000010 10110000 00000000 00000000 00111001 11111100 11111000 01100111
  Chars:   ....9..g
  Time:    ***** Invalid FILETIME
  Float:   low 0.000482503 high -2.58609e-037
  Double:  -9.78598e-296

Установлен старший бит, что означает, что бит NX установлен, поэтому мы не можем выполнить в стеке.

Мы просто хотим удалить этот бит, поэтому технически просто удалим старшую часть полубайта (вместо 0x82 у нас будет 0x02):

kd> .formats 02b00000`39fcf867
Evaluate expression:
  Hex:     02b00000`39fcf867
  Decimal: 193654784949811303
  Octal:   0012600000007177174147
  Binary:  00000010 10110000 00000000 00000000 00111001 11111100 11111000 01100111
  Chars:   ....9..g
  Time:    Fri Sep  2 12:34:54.981 2214 (UTC + 1:00)
  Float:   low 0.000482503 high 2.58609e-037
  Double:  9.78598e-296

Перепишите ПТЭ:

kd> !eb 501bfaf8+7 02

Переписанный PTE:

kd> !db 501bfaf8
#501bfaf8 67 f8 fc 39 00 00 b0 02-

kd> !dq 501bfaf8 L1
#501bfaf8 02b00000`39fcf867

Выполнять:

kd> g

Тогда нет проблем с выполнением стека в пользовательской области :)

введите здесь описание изображения

Я слышал, что у GDT также есть что-то вроде NX-Bit, которое предотвращает выполнение стека. В чем разница между предотвращением выполнения GDT и NX-Bit на уровне подкачки?

Хм, нет, таких вещей, как бит NX в GDT... Более того, у вас нет дескрипторов сегментов для CS, DS, SS, ES в x64 (только GS и FS).

Почему существуют 4 уровня, определяющие nx-бит? Влияет ли изменение только одной из вышеуказанных записей, например pml4e, на все остальные записи?

Точно :) Это может иметь забавные побочные эффекты, например, изменение бита U/S в PML4E с S (руководитель) на U (пользователь) дает пользователю доступ ко всем страницам, на которые ссылается эта запись...

person Neitsa    schedule 16.03.2018
comment
Спасибо за ваш ответ, это работает! Пожалуйста, также взгляните на stackoverflow.com/questions/49474945/ - тот же вопрос. - person Migo Lopak; 25.03.2018