n0name Адрес инструкции вызвавшей фолт передаётся через ядерный стек при возникновении фолта, также код ошибки и транзитный стек(если ловушка сработала в UM). ТС туда сам загрузил адрес label, не удивительно что отладчик получает уведамление
В общем, без отладчика система живет примерно минуту. Потом был BSoD. Почему я получаю уведомление в отладчике я пока не понял.
Mika0x65 ISR #PF вызывается не только для подкачки. Она выполняет множество задач. Например реализует механизм сторожевых страниц(PAGE_GUARD), обнаружение попыток нарушения защиты и развёртку исключений в UM. Если менеджер памяти не хэндлит фолт, тоесть он вызван изза не запланированного нарушния защиты, то фолт передаётся далее в зависимости от мода и пр. Например это нотификация системного отладчика или пользовательского. При этом отладчик должен откатать фолт, в противном случае он разворачивается как сех если это возможно, либо вызывается багчек. Если фолт не запланированный, то контекст будет изменён для передачи фолта далее в юзермод к примеру, тоесть ваш Ip в iret-фрейме будет затёрт.
Clerk Ты имеешь в виду сделать все, что делает обработчик, включая вызов _MmAccessFault@12, а потом и свои дела?
А какой смысл? По-моему, проще передрать его из IDA, посчитав смещения. Можно еще поменять код в памяти. Вариантов много.
Mika0x65 Ну я предложил тот, который на мой взгляд проще в реализации. Причём тут ида совсем не понятно.
Mika0x65 0. Я точно видел защиты где был перехват в драйвере PageFault и все работало более-менее стабильно. Не так глючно по крайней мере; 1. Попробуйте сделать не iret home, а оставьте лишь один iret - тот, который в оригинале, логика примерно такая: Handler_Entry: ... ; Some jobs before mov ss:[OriginalReturnCS],28h ; Selector, code32, Ring0 mov ss:[OriginalReturnEIP],offset Return ... ; blah-blah jmp cs:[Original] ; Там iretd Return: pushad pushfd ... popfd popad jmp cs:[OriginalCallerAddress] Возможно вы так и делаете, читал не очень внимательно. Sorry если че.
PSR1257 Проблема не в том, что я делаю iret, а в том, что мой код работает с разрешенными прерываниями. И запретить эти прерывания никак не получается. Единственное, в чем я сейчас не очень уверен, это в том, что стек общий. Еще не проверял, но, кажется, TSS имеет привязку к процессу или потоку (мне кажется, что я видел разные значения в сегменте, на который ссылается селектор 28). Кроме того, общий стек запрещает прерывать выполнение обработчика #PF, а я видел в обработчике #PF инструкцию 'sti'. А обработчик может обратиться к диску и дождаться прерывания от него, когда страница будет загружена в память. Вероятно, Windows использует какой-то более хитрый механизм. А перехватить #PF можно и модфикацией кода оригинального обработчика, например.
Mika0x65 Мне не верицца в это. Мне больше верица в то что двойной iret играет роль или какая-то мелочь типа использования селектора 23h. Можете выложить свой тестовый пример и как запускать? (если вы собирали DDK, то только sys). А про TSS - разве windows использует задачи? Я на 99% уверен что 98 не использовала. А если и использует - при подмене селектора на текущий (по идее это 28h) разве при iretd будет выполнено переключение задачи? По идее должно отработать просто как jump.
PSR1257 Изучайте матчасть. TSS используется при межкольцевых переключениях как источник транзитного стека, для хранения IOPM и пр. И нужна она не только для хардварного разруливания задач
Clerk То, что TSS используется как-то не по назначению - я видел исчо и в 98. Вопрос - используется ли она в NT для механизма вложенных задач? Если нет - остаются проблемы "общего стека" (гипотеза). Мне представляется что все это можно проверить на опыте. Сначала берем простейший случай - просто передача управление в оригинальный обработчик - тупо один jump, iret внутри него сразу на прерванную задачу. Работает? Если работает, то тут можно проверить две версии. Влияет sti и - якобы - нельзя работать внутри PageFault при разрешенных прерываниях так как якобы любое следующее прерывание затрет текущий стек (интересно как это PageFault подкачивает страницы без прерываний с диска - а это его основная функция). ok, усложняем - добавляем сразу перед jump в оригинальный обработчег sti. Работает? Добавляем еще цикл на 100-1000мкс после sti, но перед jump [OrigHandler]. Если все это также работает то можно проверять с другой стороны - минимум обработки после OrigHandler. Сначала меняем cs, eip и возможно EFLAGS в стеке и у нас просто jump cs:eip на прерванный процесс, только jump. Работает? Опять втыкаем loop и sti.
PSR1257 Можно работать при разрешённых прерываниях если трап-фрейм сформирован, скока можно повторять. Поток переходит в ядро из юзермода, тред меняет окружение на ядерное, предыдущее должно быть сохранено. Или к примеру на томже страничном нарушении пользовательского стека ось отвалится, да и вобще хз что может быть, так как смена окружения не произошла. Это не определённое состояние задачи. Ловушка это не просто вызов процедуры, где в стеке лежит адрес возврата. Там находится информация об фолте которая используется для обработки дальнейшей. Если вы загрузите ядерный селектор то соответственно сообщите менеджеру что фолт произошёл не в юзермоде, а в ядре. Загрузив туда пользовательский селектор - тред вернётся в юзермод, хотя скорее всего это приведёт к есчо одному фолту на Iret, так как транзитного стека нет.
Clerk Да, согласен - дефолтный обработчик скорее всего ориентируется на значения cs:eip в стеке и их замена приведет к неопределенности. Возможно конечно копировать весь обработчик к себе или патчить iretd в нем или прописать в юзермоде коде свой код (временно) чтобы опять получить управление ... получается пост-обработка практически невозможна (простыми методами).
PSR1257 Можно попробовать взвести TF, тогда при возврате сгенерится #DB и можно его откатать. Должно работать.