|

Ring0
Shen (_shen_@mail.ru)
Спецвыпуск Xakep, номер #035, стр. 035-062-4
Код
Примерная последовательность действий:
1. Сохранить адрес старого обработчика.
2. Модифицировать IDT, подменив адрес обработчика на адрес нашей процедуры.
3. Вызвать перехваченное прерывание.
4. Посидеть в Ring0 :).
5. Восстановить адрес старого обработчика.
Весь наш план основан на манипуляциях с IDT. Но мы ведь даже не знаем, где находится эта IDT, у нее нет фиксированного положения в памяти. Для этого в процессоре существует группа регистров, связанных с таблицами дескрипторов: GDTR, LDTR и IDTR. Нас, естественно, интересует последний. В нем хранится размер таблицы (правильнее, предел) и адрес ее начала. IDTR – регистр формата fword (word:dword), т.е. 6-байтный. Первые 16 разрядов занимает предел, все остальное – адрес. Нам потребуется только адрес, он находится в IDTR по смещению +2.
К содержимому регистра нельзя обращаться напрямую, для этого существует привилегированная команда sidt (Save IDTr):
idtr df 0
…
sidt fword ptr [idtr]
Теперь мы можем получить адрес начала IDT:
idtr df 0
…
sidt fword ptr [idtr]
mov ebx,dword ptr [idtr+2]
Пришло время разобраться с форматом дескрипторов прерываний.
Всего 8 байт. Селектор сегмента и параметры мы трогать не будем, нас интересует только адрес, так и запомним: младшее слово адреса обработчика находится по смещению +0 от начала дескриптора, старшее - по +6.
Как найти в IDT нужный дескриптор? У нас уже есть адрес начала таблицы, и мы знаем размер каждого дескриптора – что еще нужно?
intnum equ 04h ; лучше перехватывать малоиспользуемые прерывания
idtr df 0 ; сюда мы сохраним IDTR
…
sidt fword ptr [idtr] ; сохраняем IDTR в переменную idtr
mov ebx,dword ptr [idtr+2] ; нам нужен адрес начала, а не предел
add ebx,intnum*8 ; переходим на начало нужного дескриптора
Все, теперь в ebx адрес дескриптора прерывания с номером 04h. Сохраним адрес оригинального обработчика:
saved dd 0 ; сюда мы сохраним адрес старого обработчика
…
mov ax,word ptr [ebx+6] ; кладем в ax старшее слово адреса обработчика
shl eax,16 ; сдвигаем его в старшее слово eax
mov ax,word ptr [ebx] ; кладем в ax младшее слово адреса обработчика
mov dword ptr [saved],eax ; сохраняем
Заменим в дескрипторе адрес обработчика на адрес нашей процедуры:
mov eax, offset ring0code ; кладем в ax смещение процедуры
mov word ptr [ebx],ax ; заменяем младшее слово адреса
shr eax,16 ; сдвигаем старшее слово eax в младшее
mov word ptr [ebx+6],ax ; заменяем старшее слово адреса
…
ring0code: ; где-то здесь наша процедура
Все! Торжественный момент – можно генерить прерывание!
int intnum
Мы в Ring0!
ring0code:
; здесь мы можем делать что угодно,
; ведь мы уже в нулевом кольце!
iret ; возвращаемся в обыденность
Теперь пришла пора горьких разочарований. Попробуй вызвать из Ring0 функцию MessageBox. Попробуй и любуйся синим экраном с белыми надписями :). Дело в том, что Win32API, к которым относится MessageBox, доступны лишь на третьем, пользовательском, уровне. Ring0 предоставляет другие методы работы – VxD-сервисы. И, если вдуматься, то никаких разочарований быть не может – эти сервисы дают кодеру такие возможности, что ты уже никогда не сможешь заставить себя пользоваться API :). Чего стоит только установка обработчика файловой системы!
Назад на стр. 035-062-3 Содержание Вперед на стр. 035-062-5
|