Интересная задача. Прибитие не завершение, втч добровольное. Один процесс прибивает другой TerminateProcess(). Потоки прибиваемого процесса должны успеть получить это событие, так как механизм завершения тяжелый во всех смыслах. Нужно для очистки ресурсов локально, тоесть нет второго серверного процесса, который может ожидать на портах(lpc etc). Если посмотреть базовые(те младших версий) реализации терминации, видны способы: - освобождение кс загрузчика, ntsetevent - освобождается юзер apc очередь, тоесть юзер потокам доставляется апк, но асинхронно. - спящие(suspend) треды выходят из сна ? Реально ли такое провернуть ?
Это кстати не так: она очищается, но без доставки - все оставшиеся APC в очереди отменяются, у них вызываются Rundown-рутины. Похоже, что после того, как потоку прилетит ядерная APC с PspExitSpecialApc+PspExitNormalApc, он больше в юзермод не выходит. Поймать NtSetEvent - наверно можно успеть в каком-то потоке, но вряд ли успеешь его обработать, прежде чем тебе тоже прилетит ядерная APC. В общем, "реально ли такое провернуть" - скорее нет, чем да.
GetExitCodeProcess --- Сообщение объединено, 16 янв 2025 --- или Мониторинг Handle Table и Rundown Protection --- Сообщение объединено, 16 янв 2025 --- второй получше код)
HoShiMin Часто приходилось видеть как ждущий поток выходит из ожидания при завершении процесса. А если ждать на обьектах, они просигналятся до завершения потоков ? Что будет если два потока будут ждать друг друга ? galenkane Спасибо, но в этих семплах просто циклы проверок, тоесть поток должен крутиться и проверять. Можно в несколько инструкций реализовать спин, ожидая изменение памяти.
Да, просигналят: там сначала отменяются все ожидания (IO, таймеры, етц), и только потом поток прибивается. Теоретически ты можешь успеть что-то поймать, но проблема в том, что никак не получится притормозить завершение, чтобы дать тебе его спокойно обработать. Это чистый рандом - или успеешь до APC, или нет. Если потоки будут ждать потоков - да, тоже просигналят, и кто-то может даже успеет ещё вернуться из ожидания в юзермод и выполнить пару сотен инструкций, но в любом случае, сложную логику так не выполнишь
А если приоритет накрутить ? Может способ есть как то время продлить потока, если ресурсы увеличить, память к примеру ? Помню была тема, да и факт - некоторые процессы не прибивались.
А вам надо именно что-то обработать? Может проще создать разделяемую память и запустить процесс, который будет её сохранять на диск или скидывать в сеть. Если получится за некоторое число инструкций записать в нее сообщение о завершении процесса, то и сохранить/передать информацию получится. Хотя тогда уже проще запустить исходный процесс под отладкой во втором и не придумывать велосипед. Вот, скорее всего, они как раз под отладкой в другом процессе и находились.
Приоритет - точно нет, поскольку поток завершает сам себя (а значит, просто будет делать это с бОльшим приоритетом). Единственное, что можно сделать - задержать потоки в ядре. Например, в тех APC’шках мы видим, что там есть цикл, атомарно декрементящий лоадерлок, если в момент завершения он был захвачен этим потоком. То есть, можно просто его захватить и пропатчить счётчик на максимальный (он же в юзермоде) - и всё, поток будет два часа его декрементить. Также потоки не смогут завершиться, пока у них есть незавершённые IRP - когда они запросили какую-нибудь файловую операцию, а ядро не сделало IoCompleteRequest. Но проблема в том, что всё это в ядре, а потоки завершаются независимо: они могут там повиснуть, процесс может стать неубиваемым, но делать полезную работу в юзермоде всё равно будет некому. Более того, ты не сможешь даже заспавнить новые потоки в таком процессе, т.к. он практически сразу запрещает ядру создавать их в себе. — Если говорить абстрактно, рассматривая вообще любые способы, включая ядерные хаки - то можно конечно: зайти в Guarded-регион или руками пропатчить в ETHREAD флажок, который говорит, что потоку запрещена доставка APC, и всё, потоку никто не сможет доставить APC - он станет неубиваемым. Но если делать без хаков - no way…