Получаю адрес IDT. По (например) седьмому вектору устанавливаю новый обработчик а старый сохраняю в памяти. Т.е в обработчике сохраняются все регистры и флаги, по окончании восстанавливаются регистры и флаги и передается управление на старый обработчик. Получения адреса IDT: VOID GetIDT(ULONG *ADDR) { UCHAR idtbase[6]; _asm { cli pushad mov eax,cr0 push eax pop esi and eax,0xFFFEFFFF mov cr0,eax sidt fword ptr [idtbase] mov eax,dword ptr [idtbase+2] mov edi,ADDR mov [edi],eax mov cr0,esi popad sti } } Сохрание и восстановление вектора прерывания: void SaveInterruptHandler(ULONG adr_IDT,ULONG InterruptNumber,UCHAR *DataInterrupt) { _asm { cli pushad mov eax,cr0 push eax pop esi and eax,0xFFFEFFFF mov cr0,eax mov ebx,adr_IDT mov eax,8 mov ecx,InterruptNumber imul ecx add ebx,eax mov edi,DataInterrupt mov edx,[ebx] mov [edi],edx mov edx,[ebx+4] mov [edi+4],edx mov cr0,esi popad sti } } void RestoreInterruptHandler(ULONG adr_IDT,ULONG InterruptNumber,UCHAR DataInterrupt) { _asm { cli pushad mov eax,cr0 push eax pop esi and eax,0xFFFEFFFF mov cr0,eax mov ebx,adr_IDT mov eax,8 mov ecx,InterruptNumber imul ecx add ebx,eax mov edi,DataInterrupt mov edx,[edi] mov [ebx],edx mov edx,[edi+4] mov [ebx+4],edx mov cr0,esi popad sti } } Установка нового вектора прерывания: .code old_handler dd 0 data_EXTENSION dd 0 // обработчик InterruptHandler proc pushfd cli pushad push es push ds push fs push gs mov eax,data_EXTENSION ;Вызов из ASM модуля функции InterruptRoutine cCall InterruptRoutine,<eax> pop gs pop fs pop ds pop es popad cmp old_handler,0 je m1 popfd jmp old_handler m1: popfd iretd InterruptHandler endp cProc SetInterruptHandler,12,<adr_IDT: dword,InterruptNumber: dword,adr_data: dword> cli pushad mov eax,cr0 push eax pop esi and eax,0FFFEFFFFh mov cr0,eax ;Сохраняется адрес DEVICE_EXTENSION mov eax,adr_data mov data_EXTENSION,eax mov ebx,adr_IDT mov eax,8 mov ecx,InterruptNumber imul ecx add ebx,eax mov edx,0 mov dx,word ptr [ebx+6] shl edx,10h mov dx,word ptr [ebx] ;Сохраняем в память старый обработчик mov old_handler,edx mov edx,offset InterruptHandler mov word ptr [ebx],dx shr edx,10h mov word ptr [ebx+6],dx mov byte ptr [ebx+5],8eh mov cr0,esi popad sti cRet SetInterruptHandler endProc SetInterruptHandler /* Эта функция предназначена для информирования приложения пользователя о произошедшем прерывании (Event) */ void InterruptRoutine(ULONG data) { PDEVICE_EXTENSION extension=(PDEVICE_EXTENSION)data; KIRQL oldIrql; KeAcquireSpinLock(&extension->Lock,&oldIrql); //Счетчик прерываний ++extension->ct; KeSetEvent(extension->Event,0,FALSE); // BSOD KeClearEvent(extension->Event); KeReleaseSpinLock(&extension->Lock,oldIrql); } Проблема – при вызове KeSetEvent(extension->Event,0,FALSE) происходит BSOD. Подскажите пожалуйста, что я делаю не так (и как надо
На SMP такое работать будет не всегда, нужно делать копию IDT, а не менять существующую (она используется и другими процессорами). По хорошему, нужно юзать IoConnectInterrupt(). Вот тут это неплохо расписано: http://www.codeproject.com/KB/system/soviet_direct_hooking.aspx А BSOD то какой?
Простите за долгое отсутствие. Great большое спасибо,все заработало. vshemm - спасибо за ссылку. BSOD был завязан с DRIVER_IRQL_LESS_OR_EQUAL.
Еще один вопрос.Не подскажете как заменить jmp old_handler на call old_handler в своем обработчике через IDT (первым нужно вызвать старый обработчик, а потом свой) под DOS WATCOM 32 - работает pushfd call fword ptr old_handler под DOS MICROSOFT 16 - работает pushf call dword ptr old_handler
Видимо, в новом обработчике должно быть нечто вроде: Код (Text): pushfd push cs push new_handler jmp far [old_handler]