То зло. 1. Захват контекста без перехвата. Нужно искать PsSuspendProcess(). Далее из неё извлекаем PsGetNextProcessThread(). - Вызываем PsSuspendProcess(), все потоки останавливаются. - Выделяем память в процессе и записываем туда обработчик. - Перечисляем потоки посредством PsGetNextProcessThread(), получаем контекст посредством PsGetContextThread(есть в экспорте), извлекаем из контекста указатель на стек, сохраняем его в юзермодном стеке(выполнять на PASSIVE_LEVEL, если запись в сторожевую страницу стека он будет в этом случае расширен и не обработанное исключение не возникнет), сохраняем тамже Eip, EFlags, Ss, Cs(формируем фрейм для возврата инструкцией Iretd, после отработки нашего обработчика выполняем возврат на прерванный код посредством этой инструкции, разумеется без смены DPL). Затем сохраняем изменённый контекст посредством PsSetContextThread. - Выполняем PsResumeProcess. - Наш обработчик вызывается в контексте всех рабочих потоков. Атомарно проверяем флажёк, если он взведён выполняем возврат, иначе взводим его и выполняем дальгейшую обработку, тем самым отклонив остальные вызовы. 2. Захват контекстов используя сторожевые страницы. - Регистрируем диспетчер исключений. - Страница пямяти общая для всех потоков(например в секции кода нтдлл) помечается как сторожевая(GUARD). - Обрабатываем STATUS_GUARD_PAGE_VIOLATION. В контексте текущего потока изменяем Eip на наш код, формируем Iretd-фрейм в стеке для возврата. Выполняем возврат. - Исключение возникает однократно, после первого обращения к сторожевой странице атрибут PAGE_GUARD снимается автоматически.
Это anti-script kiddis protection. Если захочешь разобраться то разберешься, а если нужен готовый код то...
Да. Наш код выполняется в контексте полноценном. На счёт атомарных проверок: Код (Text): ;Все потоки перенаправлены на эту точку. ; - В стеке фрейм для возврата инструкцией Iretd. ; - Сохраняется все RGP. ; - Атомарный вызов обработчика. ; - Текущая страница доступна для записи. THREAD_ENTRY_LOCK macro InterceptDispatcher Local Dt_, ThreadEntryLock pushad Call Dt_ Dt_: mov ecx,1 pop edx xor eax,eax lock cmpxchg dword ptr [edx + (offset ThreadEntryLock - offset Dt_)],ecx .if Zero? Call InterceptDispatcher .endif popad iretd ThreadEntryLock BOOLEAN FALSE endm THREAD_ENTRY macro pushad Call InterceptDispatcher popad iretd endm ;THREAD_ENTRY_LOCK RemoteCallEntry ;RemoteCallEntry proc ; [...]
А расположенные фреймы для возврата в текущее положение потока будут как распологаться в памяти? в каком то порядке или как?
Нужно текущий юзермодный сохранить указатель на стек, флажки и Eip. Остальное обработчик сам в стеке сохранит - все RGP(pushad). А это мы из контекста извлекаем(для каждого потока вызывается PsGetContextThread).
Как найти PsSuspendProcess? NtSuspendProcess нашел через программку, попробывал запустить ничего не вышло
в принципе лучше бы вообще знать как их оттуда можно пользовать. А интересуют PsGetNextProcessThread().PsSuspendProcess(), PsGetNextProcessThread PsResumeProcess.
вы меня запутали). с чего должны быть ограничения на вызов функции при низком irql?) ограничения есть на некоторые функции при irql >= 2, но, поскольку у вас код в секции PAGE, то он (предполагается) будет вызван при irql < 2, а значит, что можно вызывать.