Поймать прибитие процесса.

Тема в разделе "WASM.WIN32", создана пользователем Indy_, 15 янв 2025.

  1. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    Интересная задача.

    Прибитие не завершение, втч добровольное. Один процесс прибивает другой TerminateProcess(). Потоки прибиваемого процесса должны успеть получить это событие, так как механизм завершения тяжелый во всех смыслах.

    Нужно для очистки ресурсов локально, тоесть нет второго серверного процесса, который может ожидать на портах(lpc etc).

    Если посмотреть базовые(те младших версий) реализации терминации, видны способы:

    - освобождение кс загрузчика, ntsetevent

    - освобождается юзер apc очередь, тоесть юзер потокам доставляется апк, но асинхронно.

    - спящие(suspend) треды выходят из сна ?

    Реально ли такое провернуть ?
     
  2. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.477
    Адрес:
    Россия, Нижний Новгород
    Это кстати не так: она очищается, но без доставки - все оставшиеся APC в очереди отменяются, у них вызываются Rundown-рутины.
    Похоже, что после того, как потоку прилетит ядерная APC с PspExitSpecialApc+PspExitNormalApc, он больше в юзермод не выходит.

    Поймать NtSetEvent - наверно можно успеть в каком-то потоке, но вряд ли успеешь его обработать, прежде чем тебе тоже прилетит ядерная APC.

    В общем, "реально ли такое провернуть" - скорее нет, чем да.
     
  3. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    311
    GetExitCodeProcess
    --- Сообщение объединено, 16 янв 2025 ---
    или Мониторинг Handle Table и Rundown Protection
    --- Сообщение объединено, 16 янв 2025 ---
    второй получше код)
     

    Вложения:

    • TermProcess.7z
      Размер файла:
      6,2 КБ
      Просмотров:
      98
    • TermProcess2.7z
      Размер файла:
      8,6 КБ
      Просмотров:
      96
    Indy_ нравится это.
  4. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    HoShiMin

    Часто приходилось видеть как ждущий поток выходит из ожидания при завершении процесса.

    А если ждать на обьектах, они просигналятся до завершения потоков ?

    Что будет если два потока будут ждать друг друга ?

    galenkane

    Спасибо, но в этих семплах просто циклы проверок, тоесть поток должен крутиться и проверять.

    Можно в несколько инструкций реализовать спин, ожидая изменение памяти.
     
  5. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.477
    Адрес:
    Россия, Нижний Новгород
    Да, просигналят: там сначала отменяются все ожидания (IO, таймеры, етц), и только потом поток прибивается.
    Теоретически ты можешь успеть что-то поймать, но проблема в том, что никак не получится притормозить завершение, чтобы дать тебе его спокойно обработать.
    Это чистый рандом - или успеешь до APC, или нет.

    Если потоки будут ждать потоков - да, тоже просигналят, и кто-то может даже успеет ещё вернуться из ожидания в юзермод и выполнить пару сотен инструкций, но в любом случае, сложную логику так не выполнишь
     
    Indy_ нравится это.
  6. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    А если приоритет накрутить ?

    Может способ есть как то время продлить потока, если ресурсы увеличить, память к примеру ?

    Помню была тема, да и факт - некоторые процессы не прибивались.
     
  7. MaKsIm

    MaKsIm Active Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    120
    А вам надо именно что-то обработать? Может проще создать разделяемую память и запустить процесс, который будет её сохранять на диск или скидывать в сеть. Если получится за некоторое число инструкций записать в нее сообщение о завершении процесса, то и сохранить/передать информацию получится.

    Хотя тогда уже проще запустить исходный процесс под отладкой во втором и не придумывать велосипед.
    Вот, скорее всего, они как раз под отладкой в другом процессе и находились.
     
  8. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.477
    Адрес:
    Россия, Нижний Новгород
    Приоритет - точно нет, поскольку поток завершает сам себя (а значит, просто будет делать это с бОльшим приоритетом).

    Единственное, что можно сделать - задержать потоки в ядре.
    Например, в тех APC’шках мы видим, что там есть цикл, атомарно декрементящий лоадерлок, если в момент завершения он был захвачен этим потоком.
    То есть, можно просто его захватить и пропатчить счётчик на максимальный (он же в юзермоде) - и всё, поток будет два часа его декрементить.
    Также потоки не смогут завершиться, пока у них есть незавершённые IRP - когда они запросили какую-нибудь файловую операцию, а ядро не сделало IoCompleteRequest.
    Но проблема в том, что всё это в ядре, а потоки завершаются независимо: они могут там повиснуть, процесс может стать неубиваемым, но делать полезную работу в юзермоде всё равно будет некому.

    Более того, ты не сможешь даже заспавнить новые потоки в таком процессе, т.к. он практически сразу запрещает ядру создавать их в себе.


    Если говорить абстрактно, рассматривая вообще любые способы, включая ядерные хаки - то можно конечно: зайти в Guarded-регион или руками пропатчить в ETHREAD флажок, который говорит, что потоку запрещена доставка APC, и всё, потоку никто не сможет доставить APC - он станет неубиваемым.
    Но если делать без хаков - no way…
     
    Indy_ нравится это.
  9. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    311
    там есть тредпул, что крутится
     
  10. M0rg0t

    M0rg0t Well-Known Member

    Публикаций:
    0
    Регистрация:
    18 окт 2010
    Сообщения:
    1.582
    HKLM\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\SilentProcessExit
    может это попробовать?
     
  11. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    Интересно найти возможность в базовой сборке wrk/w2k, что опенсорс. HoShiMin полагает что задача не решаема, нельзя тормознуть прибитие, кроме как блокирнуть загрузчик. Не верю просто в это, надо подумать, может найдется способ.

    А новые фичи не интересны.
     
  12. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.477
    Адрес:
    Россия, Нижний Новгород
    Ты писал, что это нужно для очистки ресурсов.
    Расскажи подробнее: почему нельзя заспавнить процесс-чистильщик, который будет ждать родителя?
    То, что ты пытаешься решить, явно должно решаться не так.
     
  13. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    HoShiMin

    Это был вопрос на кл., в твоих работах/реализациях ведь довольно просто находили уязвимости, это обсуждали.

    Эта тема интересна, можно поискать синхронные ошибки, проблема в том, что я не могу никакую статистику снять пока, те нет пэвм. Есть лишь знание, опыт и сурки :meeting:
     
  14. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.477
    Адрес:
    Россия, Нижний Новгород
    О, а это интересно. А что там находили?
     
  15. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    avanguard если по памяти. Какая в принципе разница, я например помню что ты ошибся с диапазоном ресурсов, неверно собрал, ошибку найдут.

    Может можно классику посмотреть, рейсконд атаку к примеру на область памяти или обьект, как будет вести себя при этом ос не известно. Это можно лишь измерить.

    Напомню что статистика или иной вероятностный путь решения не признается за метод.
     
  16. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.557
    Адрес:
    Russia
    А перехваты уже запрещены к использованию ? Перехватил TerminateProcess и освобождай .
     
  17. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.557
    Адрес:
    Russia
    есть еще такая штука как объкты Job
    AssignProcessToJobObject
    при уничтожении процесса ты точно получишь евент и сможешь освободить то, что не успелось освободиться.

    как пример

    Код (C++):
    1. #include <windows.h>
    2. #include <iostream>
    3.  
    4. int main() {
    5.     // Create a job object
    6.     HANDLE hJob = CreateJobObject(NULL, NULL);
    7.     if (hJob == NULL) {
    8.         std::cerr << "Error creating job object: " << GetLastError() << std::endl;
    9.         return 1;
    10.     }
    11.  
    12.     // Set up start info for the child process
    13.     STARTUPINFO si = { sizeof(si) };
    14.     PROCESS_INFORMATION pi;
    15.     ZeroMemory(&pi, sizeof(pi));
    16.  
    17.     // Create a child process (for example, notepad)
    18.     if (!CreateProcess(
    19.             "notepad.exe",
    20.             NULL,
    21.             NULL,
    22.             NULL,
    23.             FALSE,
    24.             CREATE_SUSPENDED, // Start in a suspended state
    25.             NULL,
    26.             NULL,
    27.             &si,
    28.             &pi)) {
    29.         std::cerr << "Error creating process: " << GetLastError() << std::endl;
    30.         CloseHandle(hJob);
    31.         return 1;
    32.     }
    33.  
    34.     // Assign the child process to the job
    35.     if (!AssignProcessToJobObject(hJob, pi.hProcess)) {
    36.         std::cerr << "Error assigning process to job: " << GetLastError() << std::endl;
    37.         TerminateProcess(pi.hProcess, 1);
    38.         CloseHandle(pi.hProcess);
    39.         CloseHandle(pi.hThread);
    40.         CloseHandle(hJob);
    41.         return 1;
    42.     }
    43.  
    44.     // Resume the child process to allow it to run
    45.     ResumeThread(pi.hThread);
    46.  
    47.     // Wait for the child process to exit
    48.     WaitForSingleObject(pi.hProcess, INFINITE);
    49.    
    50.     // There are no direct notifications here, but you know the process has ended
    51.     std::cout << "Child process has exited!" << std::endl;
    52.  
    53.     // Clean up handles
    54.     CloseHandle(pi.hProcess);
    55.     CloseHandle(pi.hThread);
    56.     CloseHandle(hJob);
    57.  
    58.     return 0;
    59. }
     
  18. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    TermoSINteZ,

    Суть в том, что исполняющийся поток завершается извне, более того снимается задача(процесс), тоесть обьекты память и прочие ядерные штуки. При этом событии поток должен проснуться и успеть пайлод отработать, пока как выше описал HoShiMin ядро не завершит все.
     
  19. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.557
    Адрес:
    Russia
    А, понял, то есть нужно чтоб поток как бы сам понял, что его киляют.
     
    Ahimov нравится это.
  20. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.557
    Адрес:
    Russia
    Пока мысль вращается вокруг отладки и события
    • DBG_TERMINATE_THREAD
    Значит наверняка можно, но с ходу не знаю, как застивить "отлаживать самого себя".