PDA

Просмотр полной версии : Уязвимость DEP в подсистеме WoW64


Marylin
30.01.2026, 13:13
1. Вводная часть
2. Атрибуты вирт.страниц в записях РТЕ
3. Характеристики в заголовке РЕ-файла
4. Заключение

1. Вводная часть

Системный механизм безопасности DEP (Data Execution Prevention, предотвращение выполнения данных) в своё время наделал много шуму, и как оказалось он имеет некоторые нюансы. Всё сказанное ниже касается только 32-битных приложений Win, для запуска которых на системах х64 предусмотрена прослойка WoW64 (Windows on Windows).

Если проследить от куда у DEP ноги растут, то получаем следующую картину. На нижнем уровне имеем таблицу дескрипторов GDT, флаги в которой задают атрибуты целым сегментам памяти, например кода и данных в юзер-спейс (кольцо 3), кода/данных в пространстве ядра (кольцо 0), а так-же структуре РЕВ (см. селектор 50 ниже). На команду

dg

(dump gdt) отладчик WinDbg отзывается таким логом:

Код:



0: kd> dg 0 80
P Gr Pr Lo
Sel Base Limit Type l an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- --------
0000 00000000`00000000 00000000`00000000 0 By Np Nl 00000000
0008 00000000`00000000 00000000`00000000 0 By Np Nl 00000000
0010 00000000`00000000 00000000`00000000 Code RE Ac 0 By P Lo 0000029b
0018 00000000`00000000 00000000`ffffffff Data RW Ac 0 Pg P Nl 00000c93
0020 00000000`00000000 00000000`ffffffff Code RE Ac 3 Pg P Nl 00000cfb
0028 00000000`00000000 00000000`ffffffff Data RW Ac 3 Pg P Nl 00000cf3
0030 00000000`00000000 00000000`00000000 Code RE Ac 3 By P Lo 000002fb
0038 00000000`00000000 00000000`00000000 0 By Np Nl 00000000
0040 00000000`0379c000 00000000`00000067 TSS32 Busy 0 By P Nl 0000008b
0048 00000000`0000ffff 00000000`0000f800 0 By Np Nl 00000000
0050 ffffffff`fffde000 00000000`00003c00 Data RW Ac 3 By P Nl 000004f3
0058 00000000`00000000 00000000`00000000 0 By Np Nl 00000000
0060 00000000`00000000 00000000`ffffffff Code RE 0 Pg P Nl 00000c9a
0068 00000000`00000000 00000000`00000000 0 By Np Nl 00000000
0070 00000000`00000000 00000000`00000000 0 By Np Nl 00000000
0078 00000000`00000000 00000000`00000000 0 By Np Nl 00000000
0080 Unable to get descriptor
0: kd>
------------------------------------
Pl : Privilege (0=Kenel, 3=User)
Gran: Granularity (By=Byte, Pg=Page)
Pres: Present (Np=No, P=Yes)
Long: Size (Nl=32, Lo=64 bit)


Однако после перехода в РМ включается пейджинг (страничная организация памяти), и таблица GDT уходит уже на второй план, уступая место 4-уровневой таблице страниц "PageTable". То-есть большие сегменты вирт.памяти делятся на более мелкие страницы размером по 4 КБ. Записи "РТЕ" в этой таблице описывают атрибуты страниц и соответствие вирт.адреса физ.кадру памяти PFN (Page Frame Number). Так вот механизм DEP включается именно старшим битом(63) в РТЕ, который известен как "Бит XD" в библии Intel'a (eXecute Disable), или "NX" в доках AMD (No-eXecute).

2. Атрибуты вирт.страниц в записях РТЕ

Чтобы наглядно продемонстрировать эту фишку можно провести небольшой эксперимент, использовав в качестве кролика, например, процесс калькулятора. Значит запустим calc.exe, и получив адрес его структуры EPROCESS, запросим атрибуты записи PTE страницы, куда отображается неисполняемая структура РЕВ процесса:

Код:



0: kd> !process 0 0 calc.exe
PROCESS fffffa80115c7b00
SessionId: 1 Cid: 1198 Peb: 7fffffde000 ParentCid: 05d8
DirBase: 2996d2000 ObjectTable: fffff8a0051027a0 HandleCount: 98.
Image: calc.exe

0: kd> .process /p fffffa80115c7b00 !cmkd.ptelist -v 7fffffde000 dt _mmpte_hardware FFFFF683FFFFFEF0
nt!_MMPTE_HARDWARE
+0x000 Valid : 0y1
+0x000 Dirty1 : 0y1
+0x000 Owner : 0y1
+0x000 WriteThrough : 0y0
+0x000 CacheDisable : 0y0
+0x000 Accessed : 0y1
+0x000 Dirty : 0y1
+0x000 LargePage : 0y0
+0x000 Global : 0y1
+0x000 CopyOnWrite : 0y0
+0x000 Unused : 0y0
+0x000 Write : 0y1
+0x000 PageFrameNumber : 0y000000000000001000001101001010101011 (0x20d2ab)
+0x000 reserved1 : 0y0000
+0x000 SoftwareWsIndex : 0y00000110001 (0x31)
+0x000 NoExecute : 0y1

0: kd>


Активность DEP для процесса calc.exe подтверждает и системный "Диспетчер задач", или более продвинутый его форк "Process Hacker". А вот у страниц Total, AkelPad и WinWord бит DEP вместе с ASLR уже отключён:

https://forum.antichat.xyz/attachments/4950708/img_a7f5d56eaa.png
Но во-всей этой кухне интересно другое. Мы знаем, что страницы могут иметь три основных атрибута - это чтение(R), запись(W), и исполнение(Е). Эти атрибуты задаются в аргументах таких функций как

VirtualAlloc()

и

VirtualProtect()

. Но если посмотреть на биты структуры MMPTE_HARDWARE, то среди них имеется лишь бит "Write" (страница доступна для записи), а вот бита "Execute" как-раз таки нет! От сюда следует, что любые страницы вирт.памяти доступны для исполнения, пусть это будет хоть секция-данных, хоть стек. Другими словами, система и сам процессор могут только запретить исполнение битом NX в РТЕ, хотя в дефолте буквально все страницы исполняемые.

В качестве пруфа напишем простое 32-битное приложение с процедурой "HelloWorld", которую поместим для исполнения сначала в секцию данных, а потом скопируем её и в стек. Обратите внимание, что механизм DEP при этом в системе включён для всех (см. Win+Break --> Доп.параметры --> Быстродействие --> DEP).

https://forum.antichat.xyz/attachments/4950708/img_98ae42a29b.png

C-подобный:



format pe gui
include
'win32ax.inc'
entry start
;
//----------
.
data
szText1 db
'Launch code from data section'
,
0
szText2 db
'Launch code from STACK'
,
0
;
// Процедура для исполнения в секции-данных
align
4
startDep
:
invoke MessageBox
,
0
,
szText1
,
0
,
0
ret
align
4
endDep
:
;
//----------
section
'.code'
code readable executable
start
:
;
// Первый вызов из секции данных - ОК!
call startDep
;
// Теперь копируем процедуру в стек
push esp
mov ecx
,
endDep
-
startDep
;
// размер кода
sub esp
,
ecx
;
// выделяем фрейм в стеке
mov dword
[
startDep
+
5
]
,
szText2
;
// изменить текст мессаги
mov esi
,
startDep
;
// источник для копирования
mov edi
,
esp
;
// приёмник
cld
;
// прямой шаг
rep movsb
;
// скопировать ECX-байт..
call esp
;
// вызов процедуры из стека!
add esp
,
endDep
-
startDep
;
// восстановить стек,
pop esp
;
// ..и указатель на него
invoke ExitProcess
,
0
;
// на выход
;
//----------
section
'.idata'
import data readable
library user32
,
'user32.dll'
,
kernel32
,
'kernel32.dll'
include
'api\user32.inc'
include
'api\kernel32.inc'


Как видим, даже с активным DEP данные всё-равно доступны для исполнения (см.файл в скрепке)! Так в чём-же подвох? А дело в том, что мало иметь включённый DEP на уровне ЦП и системы, так ещё и само приложение должно быть скомпилированно с одноимённым ключом. У компоновщиков С++ и MASM этот ключ называется

/NXCOMPAT

, и он включён в дефолте так, что его можно только сбросить

/NXCOMPAT[:NO]

.

3. Характеристики в заголовке РЕ-файла

А вот компилятор FASM не может собирать исходники с ключами, поэтому нужно указать его явно в поле "DLL Characteristics" опционального заголовка уже скомпилированного РЕ-файла. Для манипуляций подобного рода как-нельзя лучше подходит крутая софтина CFF Explorer - этот процесс показан на скрине ниже. Родственная фишка рандомизации базы образа ASLR включается здесь битом "DLL can move" (в бинаре должна быть секция ".reloc"):

https://forum.antichat.xyz/attachments/4950708/img_43ddcfa0e9.png

Только теперь наше приложение будет иметь полноценную защиту от исполнения данных DEP, и если сейчас запустить его, то сразу-же получим крэш с ошибкой доступа

0xC0000005

. От сюда следует, что сбросив всего один бит в х32 исполняемом файле мы можем полностью анулировать этого сторожа, после чего без проблем внедрять свой шелл в любое место процесса-жертвы, для последующего запуска от туда через Wow64.

https://forum.antichat.xyz/attachments/4950708/img_bad97373eb.png

4. Заключение

DEP в WoW64 работает, но с ограничениями, т.к. это реализованный в либе Wow64.dll эмулятор, запускающий 32-бит приложения на 64-бит оси. Политика DEP может быть менее строгой или вовсе конфликтовать, если старые программы требуют выполнения кода из стека/кучи, что аппаратная защита ЦП в виде бита NX/XD блокирует. Для корректной работы 32-битных программ, DEP работает в режиме «Opt-Out» или принудительно отключается системой, чтобы избежать критических ошибок. Таким образом нельзя сказать, что DEP в WoW64 не работает полностью - просто он часто уходит в менее строгий режим, для совместимости с 32-битным софтом.