Возникла проблема. В драйвере вызываю NtGetContextThread и происходит блокировка. Это выглядит так: В dispatch функции я создаю системный поток и останавливаюсь Code (Text): ::LARGE_INTEGER Timeout; Timeout.QuadPart = -10000 * 100 * 10000; status = ::KeWaitForSingleObject( SettingThread, ::Executive, ::UserMode, TRUE, &Timeout ); DbgPrint("%s\n", OsrNTStatusToString(status)); В потоке я вызываю NtGetContextThread, она вызывает PsGetContextThread, а та отправляет APC основному потоку и тоже останавливается на KeWaitForSingleObject - deadlock. Почему так происходит? Ведь я поставил wait функцию в основном потоке с параметрами WaitMode = UserMode и Alertable = TRUE. То есть APC должна приходить.
вы невнимательно прочитали вопрос. я сам не шлю APC. Я вызываю NtGetContextThread, она соответственно PsGetContextThread, а та KeInitializeApc, KeInsertQueueApc, KeWaitForSingleObject. это код, который работал в user mode. по некоторым причинам мне пришлось перенести его в kernel mode. где я допустил промах?
Ты пытаешься вызвать NtGetContextThread() для того потока, в контексте которого вызвана dispatch-функция, я правильно понимаю? Т.е. в dispatch-функции ты получаешь хендл потока-инициатора запроса, создаёшь ядерный поток, передавая ему хендл целевого потока, и ждёшь его завершения. В ядерном потоке вызываешь NtGetContextThread() для потока-инициатора IRP-запроса и убиваешься. Всё верно?
Поэтому и не работает, PsGetContextThread шлет ядерную apc, которая никакого отношения к alertable не имеет. Непонятно как это вобще работало.
работало, но соответственно в user mode я создавал user mode поток, вызывал там GetThreadContext, а в основном потоке ждал на WaitForSingleObject
А, ну тогда я действительно неверно понял. Вобщем при previous mode == UserMode при обработке ядерной апк ( той самой которая была послана из PsGetContextThread ) и если normal routine нулевая, то проверяется может ли быть доставлена юзермодному алертабле потоку, видимо поэтому и работало. При переносе в ядро prev mode изменился и соот-но работать перестало.
но мне нужен CONTEXT, я же не просто так жду может, вместо NtGetContextThread вызвать сразу PsGetContextThread с параметром UserMode?
Можно попробовать ( только поток зареференсить не забыть, а то он умереть может ненароком ). А вобще желательно целиком задачу описать, помоему все это както криво выглядит, а посоветовать как сделать нормально немогу, т.к. незнаю условий задачи.
надо получать и менять контекст потока приложения (т.е. вызывать GetThreadContext и SetThreadContext), причём надо обрабатывать случай пропатченной IAT. для меня наиболее удобно было бы сделать это в драйвере, но раз прямое перенесение кода в kernel мод вызывает столько сложностей, то, видимо, я перепишу эти GetThreadContext и SetThreadContext через sysenter
Во-первых, зачем вообще нужен отдельный ядерный поток, чтобы получить контекст текущего потока, - не понятно. Как насчёт вызвать NtGetContextThread() прямо в dispatch-функции, передав ей NtCurrentThread() в качестве хендла потока? Во-вторых, PsGetContextThread() шлёт ядерную APC, а ядерные APC никак не влияют на поведение функции KeWaitForSingleObject(), независимо от параметров. Т.е. если ты хотел таким образом добиться выхода из KeWaitForSingleObject(), то это была изначально нерабочая идея. В документации об этом сказано, кстати. И, в-третьих, если функция PsGetContextThread() повисла на ожидании, следовательно, её APC не была доставлена. В твоём случае, похоже, это связано с тем, что Previous Mode потока, который запросил информацию о контексте, == KernelMode.
Хороший вопрос. Это пришло из описания функции SetThreadContext То есть, я останавливаю поток и работаю с контекстом. Если запрашивается контекст текущего потока, то создаётся отдельный, основной останавливается, и оттуда запрашиватся контекст. Так было в user mode. В kernel mode я временно снял остановку потока, а сейчас думаю, что для текущего потока можно, наверное, не выполнять это условие. сам поток не сможет изменить контекст, а если его будет менять какой-то другой поток, то саспенд не поможет. ну разумеется, APC не была доставлена. выскажите пожалуйста ваши соображения, по поводу бессаспендного запроса контекста текущего потока
Т.е. задача свелась к suspend thread, get/set context, resume thread, для этого не нужны никакие системные потоки и apc, нужно просто вызвать эти апи. Что касается получения контекста без суспенда - получить его ( именно его, а не измененный другими контекст ) можно лишь в трап фрейме(и судя по всему это вобще здесь не нужно).
вы видимо не прочли про пропатченный IAT это расшифруйте пожалуйста. мне нужен консистентный контекст - то есть, чтобы не случилось так, что я начал считывать или устанавливать контекст, произошло переключение потоков и контекст изменился
sergegers А как IAT относится к контексту потока? Suspend Thread, потом установка контекста. После суспенда он в списке ожидания планировщика находится, ни о каком переключении речи тут идти не может.
вы предложили вызывать GetThreadContext & SetThreadContext, а они пропатчены. почему я и перелез в ядро так я и спрашиваю, можно ли сделать для текущего потока KeGetContextThread/KeSetContextThread без саспенда. видимо, тогда удастся обойтись без отдельного кернелмодного потока для запроса контекста, и тогда PreviousMode потока будет UserMode (хотя это тоже надо прояснить). по предположению x64 это позволит избежать зависания в PsGetContextThread
Ну, устанавливать контекст без остановки потока нельзя, это однозначно. А про получение см. ниже. Избежать-то, конечно, поможет, но какой в этом смысл для тебя? Контекст же уже не будет актуален к моменту возврата из PsGetContextThread(). Или тебе консистентность важнее, чем актуальность?