Переход по кольцу с использованием ворот вызова
Я пытаюсь выполнить переход от кольца 3 к кольцу 0, используя "Врата вызовов" вместо "SYSRET & SYSENTER", чтобы увидеть, как "Ворота вызовов" работают на процессорах IA-32e (64-разрядных).
Что я знаю, так это то, что Call Gates - это специальная структура, которую вы можете вставить в GDT, чтобы ее можно было использовать для перехода между разными кольцами.
Структура ворот вызова такая:
typedef struct CALL_GATE
{
unsigned __int32 offset0_15 : 16;
unsigned __int32 selector :16;
union {
struct {
unsigned __int16 ist : 3;
unsigned __int16 ignored : 5;
unsigned __int16 type : 5;
unsigned __int16 dpl : 2;
unsigned __int16 p : 1;
} part;
unsigned __int16 all;
} dummy;
unsigned __int64 offset16_63 : 48;
unsigned __int32 reserved : 32;
}CALL_GATE, *PCALL_GATE;
Я установил удаленный отладчик ядра Windows от windbg. Теперь позвольте мне сказать, что моя процедура отправки (место, куда я хочу перейти после того, как процессор перешел с кольца 3 на кольцо 0), расположено в 0xfffff8027f258bc0
поэтому я поставил аппаратную точку останова в этом месте:
ba e 1 fffff802`7f258bc0
Теперь я создал структуру шлюза вызова со следующей информацией:
- DPL: 0x3
- Селектор: 0x10 (KGDT64_R0_CODE)
- Тип: 0xc
- р (присутствует): 0x1
- и добавление offset0_15 & offset16_63: fffff8027f258bc0
Структура результата (в шестнадцатеричном формате) выглядит следующим образом:
00000000 fffff8027f25 ec00 0010 8bc0
Теперь, как ворота вызова (и все записи GDT) имеют 128 бит или 0x10 байт. Я выбираю 8-ую запись GDT, чтобы преобразовать ее в шлюз вызова, поэтому сначала найдите местоположение GDT с помощью GDTR, а затем измените его 8-ую запись (0x8-ая запись * 0x10 размер каждой записи).
kd> r gdtr
gdtr=fffff8028185afb0
kd> eb fffff8028185afb0+(0x8 * 0x10) 00 00 00 00 ff ff f8 02 7f 25 ec 00 00 10 8b c0
Пришло время использовать нашу запись, используя дальний вызов или дальний JMP. мое приложение пользовательского режима (которое хочет передать выполнение в кольцо 0) выполняет следующую инструкцию:
00000000`00d2114e ea000000000800 jmp 0008:00000000
Но проблема в том, что ничего не происходит, приложение пользовательского режима не аварийно завершает работу и не переводит выполнение в кольцо 0 (потому что моя аппаратная точка останова не сработала).
Теперь мой вопрос: что не так с моими предположениями, из-за которых возникают проблемы при переходе с кольца 3 на кольцо 0?
Обновление: я также проверяю 0x40 и 0x43 в качестве селектора для дальней JMP.