Никак не могу разобраться с механизмом обработки прерываний в NT. Руссинович утверждает, что адресс сопоставленный в IDT с конкретным прерыванием указывает на код диспетчирезации, копирующийся при создании объекта прерывания в буфер KINTERRUPT:ispatchCode из KiInterruptTemplate: Далее управление должно передаваться в KiInterruptDispatch или KiChainedDispatch, которые в свою очередь передают его конкретной ISR. Но эксперименты с трассировкой различных прерываний показали, что 1) Начало "кода диспетчирезации" у разных прерываний может быть одинаковым или разным 2) Ни в одном из случаев это не код из KiInterruptTemplate. Подскажите, чего я не понял, или понял не правильно в словах Руссиновичи и как со всем этим хозяйством разобраться.
UP Неужели никто не может сказать, где зарыта собака? Кстати, некоторые прерывания вообще не трассируются: после нажатия F8 на инструкции, к примеру int 11h(мышь), Syser просыпаетсся где-то в районе RtlExitUserThread
Sholar // Не силен в этой NT Вы как-то имхо странновато трассируите: зовете int (из User-mode?!) вместо честно поставленного bpx/bpm x (SoftIce) на элемент из idt и аппаратного прерывания (шевелите мышь если вам нужна мышь). User-mode int'ы с большой вероятностью будут проэмулированы/проскипаны на другом уровне.
Да, я просто писал int 3h/ int XXh и запускал это на выполнение. Сделал так, как вы говорите, если поставить бряк на обработчик мыши или клавиатуры, то это не срабатывает, а вот, к примеру, c int 2Eh работает. Но int 2Eh я мог и так трассировать старым способом. Возможно Syser не хочет трассировать аппаратные прерывания. Но трассировка обработчика в отладчике мне на самом деле ничего не дает(ибо вообще мало что там понимаю), интересует как и через какие обработчики проходит программа(ведь должен сохраняться трап-фрейм и т.д.?). Вот в книге Руссиновича, как я писал выше, говорится о том, что при любом прерывании сначала должен выполняться код диспетчирезации, скопированный из KiInterruptTemplate, но ни один из обработчиков не содержит ничего подобного.
PSR1257II Не выйдет при входе в прерывание все другие прерывания запрещаются. Единственный метод это трассировка int при условии, что отладчик умеет эмулировать int иначе опять таки прерывания будут запрещены. Так что дизассемблер в руки и вперёд изучать развилки. Sholar Отладчик вещь хорошая, но я человек ленивый и посмотрел бы в исходных кодах. Даже близко не мышь. Во-вторых явная путаница IRQ и INT.
На самом деле трассировать можно, просто это надо делать после того, как сформирован трап фрейм и разрешены прерывания.
Точно. Смотрю уже третьи сутки, изучил огромное количество кода, но до "того самого" докопаться не могу. В данный момент смотрю KeConnectInterrupt/KeDisconnectInterrupt в WRK. Подскажите где именно изучать, к примеру, как называется обработчик того же int 2Eh?
Sholar В WRK обработчики прерываний находятся в файле trap.asm (их два, для 32битного и 64битного режима). Например, для int 0x2E есть обработчик: IDTEntry _KiSystemService, D_INT332 ;2E: system service calls В общем, начать, думаю, стоит с этого файла.
Посмотрел этот обработчик, создается трап-фрейм и совершается прыжок в KiFastCallEntry, ранее изученную досконально. То есть никаких KiInterruptTemplate или KiInterruptDispatch. Пришла в голову мысль, что я жестко туплю и все написанное в #1 относится только к аппаратным прерываниям. Можно ли как-то узнать, за каким устройством закреплено конкретное прерывание? Отладчик эту инфу не показывает.
Отладчик все прекрасно показывает: Код (Text): kd> !idt Dumping IDT: 37: 806d1728 hal!PicSpuriousService37 3d: 806d2b70 hal!HalpApcInterrupt 41: 806d29cc hal!HalpDispatchInterrupt 50: 806d1800 hal!HalpApicRebootService 62: 81780404 atapi!IdePortInterrupt (KINTERRUPT 817803c8) 63: 815a2044 USBPORT!USBPORT_InterruptService (KINTERRUPT 815a2008) 73: 817aa664 SCSIPORT!ScsiPortInterrupt (KINTERRUPT 817aa628)
Чтоб трейсить IRQ нужно воспользоваться windbg. А Int в юзермодах, какой нить инвалидный(или на который прав не хватает), к примеру диспетчер IPI(0xE1) дёрнуть не получится. Это приведёт к срабатыванию защиты и будет вызвано системное исключение(#GP), далее вы попадается в системный диспетчер исключений(KiTrap0D() -> STATUS_ACCESS_VIOLATION).
Трассирую сисером прерывание 0xE1, в KiTrap0D не попадаю, управление передается на адресс указаный в IDT
Sholar И как вы его вызываете, в смысле прерывание ? Это не INT, а IRQ. Есть есчо тип векторов - исключения. IRQ хардварно вызываются, а не через INT из ядра. Хотя эмулировать вызов можно.
Код (Text): .code start: int 3h int 0E1h .end start Отладчик всплывает на int 0E1h, дальше жму F8 Хмм, то есть потрейсить код, который выполняется при хардверном прирывании у меня не получится?
Pavia Отладчегу должно быть пофигу на все остальные прерывания (если только его собственные - int 1/3 в случае bpx == int 3 или bpm X == int 1 не вырублены). При входе (например) в мышиное IRQ N запрещаются только все менее приоритетные, e.g. >N. Клава и таймер должны работать. Фактически ставя bmp/bpx на элемент idt вы просто ставите jmp Debugger. Если перехваченное прерывание используется отладчегом - тогда да, он повиснет но он всплывет. Sice работал у меня. Единственное что винда может перезагрузить idt и тогда вы не увидите никакого прерывания. Или если обработчик делает cli а вы поставили bpx после. Sholar By my humble opinion you should start your research from Processor architechture (e.g. idt, interrupts, etc) and only after some express study try some Windows-related features.
Sholar Попробуйте в олли это заюзать. Сиська это если и вызывает, то вызывает in silico. Защита не позволяет такое дёргать, у вас нет прав на это(CPL/IOPL). Там в дескрипторе указан !DPL, посему такие вектора не доступны в юзермоде.
Sholar Процессор при получении хардварного прерывания извлекает соответствующий ему элемент из таблицы idt и передает ему управление. Оформляется контекст нулевого уровня (стек - ядерный и так далее) и процессор работает в ring0. Все попытки вызывать прерывание программно не из нулевого кольца приводят к исключению защиты (примерно, нужно глянуть мануал) и обрабатываются соответствующим обработчиком системы а вовсе не соответствующим элементом из idt. int 2Eh (Windows) или int 80h (Linux) - специально оговоренный интерфейс ядра для связи с пользовательскими приложениями. Поэтому вы иногда (для некоторых прерываний) можете "программно" их "трассировать". Если хотите трассировать программно вызванное - пишите себе sys-драйвер и уже зовите из 0-кольца (или ищите соответствующий ядерный интерфейс как заметили выше).