Информация об изменениях

Сообщение Re: Поймать TerminateProcess для своего приложения от 22.02.2019 10:32

Изменено 22.02.2019 12:13 EreTIk

Re: Поймать TerminateProcess для своего приложения
Здравствуйте, _agg, Вы писали:

_>привет всем, понадобилось в момент когда из диспетчера задач вызывают снять задачу записать в лог сообщение об этом, пытался вот так:

  Скрытый текст
_>
_>void __cdecl thr_wait_terminate_process(LPVOID ptr) {
_>    DWORD dwPID = GetCurrentProcessId();
_>    HANDLE hProcess = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, TRUE, dwPID);
_>    do {
_>        if (!hProcess) {
_>            t2f::T2F(err::GetErrMsg());
_>            break;
_>        }
_>    } while (false);
_>    DWORD dwErr = WaitForSingleObject(hProcess, INFINITE);
_>    CString str; str.Format(L"Close process:%lu", dwErr);
_>    t2f::T2F(str);
_>}
_>

_>t2f::T2F — пишет лог
_>err::GetErrMsg() — вызывает GetLastError и форматирует сообщение из полученной ошибки

_>Это поточная функция, которая как мне казалось должна поймать TerminateProcess вызываемый для моего процесса диспетчером задач, но увы и поэтому прошу помощи у знающих людей как же правильно это сделать?

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

Почему этот код должен срабатывать только при уничтожении процесса из диспетчером задач? Как это будет отличаться от других случаев:
  • не диспетчером задач, а другой внешний процесс, например — антивирус, завершает процесс?
  • свой же процесс внутри системного или библиотечного кода (по зависимостям) вызывает одну из функций, завершающей процесс?
  • необработанное исключение внутри процесса приводит к завершению процесса?
  • процесс сам завершился "штатно"? Если важно отделить только это событие и сейчас в этой точке завершается нить с приведенным кодом, то тогда может пойти от обратного: в месте завершения нити залогировать "штатный" выход, а если нет такой записи в логе, то считать что произошла непредусмотренная ситуация уничтожения процесса?

Если интересует именно вызов TerminateProcess, то в Windows 10 (а скорее всего и и на более старых версиях) в отдельном процессе можно следить за ETW-событиями, которые логируют вызов TerminateProcess одного процесса для другого:
  PspLogAuditTerminateRemoteProcessEvent
PAGE:007BC54A ; __stdcall PspLogAuditTerminateRemoteProcessEvent(x, x)
PAGE:007BC54A _PspLogAuditTerminateRemoteProcessEvent@8 proc near
PAGE:007BC54A                                         ; CODE XREF: NtTerminateProcess(x,x)+172p
PAGE:007BC54A
PAGE:007BC54A var_2C          = dword ptr -2Ch
PAGE:007BC54A var_28          = dword ptr -28h
PAGE:007BC54A var_24          = dword ptr -24h
PAGE:007BC54A var_20          = dword ptr -20h
PAGE:007BC54A var_1C          = dword ptr -1Ch
PAGE:007BC54A var_18          = dword ptr -18h
PAGE:007BC54A var_14          = dword ptr -14h
PAGE:007BC54A var_10          = dword ptr -10h
PAGE:007BC54A var_C           = dword ptr -0Ch
PAGE:007BC54A var_8           = dword ptr -8
PAGE:007BC54A var_4           = dword ptr -4
PAGE:007BC54A
PAGE:007BC54A                 mov     edi, edi
PAGE:007BC54C                 push    ebp
PAGE:007BC54D                 mov     ebp, esp
PAGE:007BC54F                 sub     esp, 2Ch
PAGE:007BC552                 mov     eax, ___security_cookie
PAGE:007BC557                 xor     eax, ebp
PAGE:007BC559                 mov     [ebp+var_4], eax
PAGE:007BC55C                 push    4
PAGE:007BC55E                 lea     eax, [ebp+var_28]
PAGE:007BC561                 mov     [ebp+var_28], ecx
PAGE:007BC564                 pop     ecx
PAGE:007BC565                 mov     [ebp+var_24], eax
PAGE:007BC568                 lea     eax, [ebp+var_2C]
PAGE:007BC56B                 mov     [ebp+var_14], eax
PAGE:007BC56E                 lea     eax, [ebp+var_24]
PAGE:007BC571                 push    eax
PAGE:007BC572                 push    2
PAGE:007BC574                 mov     [ebp+var_2C], edx
PAGE:007BC577                 xor     edx, edx
PAGE:007BC579                 push    edx
PAGE:007BC57A                 push    offset _KERNEL_AUDIT_API_TERMINATEPROCESS
PAGE:007BC57F                 push    dword_67AC8C
PAGE:007BC585                 mov     [ebp+var_20], edx
PAGE:007BC588                 push    _EtwApiCallsProvRegHandle
PAGE:007BC58E                 mov     [ebp+var_1C], ecx
PAGE:007BC591                 mov     [ebp+var_18], edx
PAGE:007BC594                 mov     [ebp+var_10], edx
PAGE:007BC597                 mov     [ebp+var_C], ecx
PAGE:007BC59A                 mov     [ebp+var_8], edx
PAGE:007BC59D                 call    _EtwWrite@24    ; EtwWrite(x,x,x,x,x,x)
PAGE:007BC5A2                 mov     ecx, [ebp+var_4]
PAGE:007BC5A5                 xor     ecx, ebp
PAGE:007BC5A7                 call    @__security_check_cookie@4 ; __security_check_cookie(x)
PAGE:007BC5AC                 mov     esp, ebp
PAGE:007BC5AE                 pop     ebp
PAGE:007BC5AF                 retn
PAGE:007BC5AF _PspLogAuditTerminateRemoteProcessEvent@8 endp


Но сразу надо учесть, что:
  • taskmgr, помимо TerminateProcess, вызывает EndTask, что приведет к RPC-вызову csrss, который уже и будет непосредственным инициатором вызова TerminateProcess.
  • не TerminateProcess'ом единым можно заставить процесс умереть: 12 ways to terminate a process.

P.S. Зачем вокруг логирования ошибки открытия процесса городить while (false)? В боевом коде после if (!hProcess) есть еще код, который не попал в приведенный пример?
Re: Поймать TerminateProcess для своего приложения
Здравствуйте, _agg, Вы писали:

_>привет всем, понадобилось в момент когда из диспетчера задач вызывают снять задачу записать в лог сообщение об этом, пытался вот так:

  Скрытый текст
_>
_>void __cdecl thr_wait_terminate_process(LPVOID ptr) {
_>    DWORD dwPID = GetCurrentProcessId();
_>    HANDLE hProcess = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, TRUE, dwPID);
_>    do {
_>        if (!hProcess) {
_>            t2f::T2F(err::GetErrMsg());
_>            break;
_>        }
_>    } while (false);
_>    DWORD dwErr = WaitForSingleObject(hProcess, INFINITE);
_>    CString str; str.Format(L"Close process:%lu", dwErr);
_>    t2f::T2F(str);
_>}
_>

_>t2f::T2F — пишет лог
_>err::GetErrMsg() — вызывает GetLastError и форматирует сообщение из полученной ошибки

_>Это поточная функция, которая как мне казалось должна поймать TerminateProcess вызываемый для моего процесса диспетчером задач, но увы и поэтому прошу помощи у знающих людей как же правильно это сделать?

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

Почему этот код должен срабатывать только при уничтожении процесса из диспетчером задач? Как это будет отличаться от других случаев:
  • не диспетчером задач, а другой внешний процесс, например — антивирус, завершает процесс?
  • свой же процесс внутри системного или библиотечного кода (по зависимостям) вызывает одну из функций, которая завершает текущий процесс?
  • необработанное исключение внутри процесса приводит к завершению процесса?
  • процесс сам завершился "штатно"? Если важно отделить только это событие и сейчас в этой точке завершается нить с приведенным кодом, то тогда может пойти от обратного: в месте завершения нити залогировать "штатный" выход, а если нет такой записи в логе, то считать что произошла непредусмотренная ситуация уничтожения процесса?

Если интересует именно вызов TerminateProcess, то в Windows 10 (а скорее всего и и на более старых версиях) в отдельном процессе можно следить за ETW-событиями, которые логируют вызов TerminateProcess одного процесса для другого:
  PspLogAuditTerminateRemoteProcessEvent
PAGE:007BC54A ; __stdcall PspLogAuditTerminateRemoteProcessEvent(x, x)
PAGE:007BC54A _PspLogAuditTerminateRemoteProcessEvent@8 proc near
PAGE:007BC54A                                         ; CODE XREF: NtTerminateProcess(x,x)+172p
PAGE:007BC54A
PAGE:007BC54A var_2C          = dword ptr -2Ch
PAGE:007BC54A var_28          = dword ptr -28h
PAGE:007BC54A var_24          = dword ptr -24h
PAGE:007BC54A var_20          = dword ptr -20h
PAGE:007BC54A var_1C          = dword ptr -1Ch
PAGE:007BC54A var_18          = dword ptr -18h
PAGE:007BC54A var_14          = dword ptr -14h
PAGE:007BC54A var_10          = dword ptr -10h
PAGE:007BC54A var_C           = dword ptr -0Ch
PAGE:007BC54A var_8           = dword ptr -8
PAGE:007BC54A var_4           = dword ptr -4
PAGE:007BC54A
PAGE:007BC54A                 mov     edi, edi
PAGE:007BC54C                 push    ebp
PAGE:007BC54D                 mov     ebp, esp
PAGE:007BC54F                 sub     esp, 2Ch
PAGE:007BC552                 mov     eax, ___security_cookie
PAGE:007BC557                 xor     eax, ebp
PAGE:007BC559                 mov     [ebp+var_4], eax
PAGE:007BC55C                 push    4
PAGE:007BC55E                 lea     eax, [ebp+var_28]
PAGE:007BC561                 mov     [ebp+var_28], ecx
PAGE:007BC564                 pop     ecx
PAGE:007BC565                 mov     [ebp+var_24], eax
PAGE:007BC568                 lea     eax, [ebp+var_2C]
PAGE:007BC56B                 mov     [ebp+var_14], eax
PAGE:007BC56E                 lea     eax, [ebp+var_24]
PAGE:007BC571                 push    eax
PAGE:007BC572                 push    2
PAGE:007BC574                 mov     [ebp+var_2C], edx
PAGE:007BC577                 xor     edx, edx
PAGE:007BC579                 push    edx
PAGE:007BC57A                 push    offset _KERNEL_AUDIT_API_TERMINATEPROCESS
PAGE:007BC57F                 push    dword_67AC8C
PAGE:007BC585                 mov     [ebp+var_20], edx
PAGE:007BC588                 push    _EtwApiCallsProvRegHandle
PAGE:007BC58E                 mov     [ebp+var_1C], ecx
PAGE:007BC591                 mov     [ebp+var_18], edx
PAGE:007BC594                 mov     [ebp+var_10], edx
PAGE:007BC597                 mov     [ebp+var_C], ecx
PAGE:007BC59A                 mov     [ebp+var_8], edx
PAGE:007BC59D                 call    _EtwWrite@24    ; EtwWrite(x,x,x,x,x,x)
PAGE:007BC5A2                 mov     ecx, [ebp+var_4]
PAGE:007BC5A5                 xor     ecx, ebp
PAGE:007BC5A7                 call    @__security_check_cookie@4 ; __security_check_cookie(x)
PAGE:007BC5AC                 mov     esp, ebp
PAGE:007BC5AE                 pop     ebp
PAGE:007BC5AF                 retn
PAGE:007BC5AF _PspLogAuditTerminateRemoteProcessEvent@8 endp


Но сразу надо учесть, что:
  • taskmgr, помимо TerminateProcess, вызывает EndTask, что приведет к RPC-вызову csrss, который уже и будет непосредственным инициатором вызова TerminateProcess.
  • не TerminateProcess'ом единым можно заставить процесс умереть: 12 ways to terminate a process.

P.S. Зачем вокруг логирования ошибки открытия процесса городить while (false)? В боевом коде после if (!hProcess) есть еще код, который не попал в приведенный пример?