Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #35, ОКТЯБРЬ 2003 г.

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