Подтвердить что ты не робот

Как определить процесс создания/завершения процесса win32 в С++

Я знаю, что для получения уведомлений о создании или прекращении процесса Win32 мы могли бы использовать драйвер режима ядра NT с использованием API PsSetCreateProcessNotifyRoutine(), который предлагает возможность регистрировать функцию обратного вызова всей системы, которая вызывается ОС каждый раз, когда новый процесс запускается, завершается или завершается.

Возможно ли это, не создавая драйвер режима ядра NT, используя только функции Win32 API с использованием С++? Не использовать базовое решение бесконечного цикла, запрашивая список активного процесса, конечно.

Есть ли библиотека или win32 API, которые обеспечивают ту же функциональность (системный обратный вызов, асинхронные события)?

4b9b3361

Ответ 1

Единственное, о чем я мог подумать, это WMI, не уверен, что он обеспечивает обратный вызов для создания процесса, но он может быть интересен.

Ответ 2

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

VOID CALLBACK WaitOrTimerCallback(
    _In_  PVOID lpParameter,
    _In_  BOOLEAN TimerOrWaitFired
    )
{
    MessageBox(0, L"The process has exited.", L"INFO", MB_OK);
    return;
}

DWORD dwProcessID = 1234;
HANDLE hProcHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);

HANDLE hNewHandle;
RegisterWaitForSingleObject(&hNewHandle, hProcHandle , WaitOrTimerCallback, NULL, INFINITE, WT_EXECUTEONLYONCE);

Этот код вызовет WaitOrTimerCallback после завершения процесса.

Ответ 3

Вы можете отслеживать все процессы создания окна с помощью SetWindowsHookEx с CBTProc, однако что-то большее, чем это требует либо WMI, либо драйвер Windows, либо немного Black Magic

Ответ 4

Андерс прав, WMI прекрасно работает для этого. Поскольку мне это нужно для проекта, я могу поделиться кодом для обнаружения (произвольного) завершения процесса (учитывая его идентификатор):

ProcessTerminationNotification.h:

#ifndef __ProcessTerminationNotification_h__
#define __ProcessTerminationNotification_h__

#include <boost/function.hpp>

namespace ProcessTerminationNotification
{
    typedef boost::function< void(void) > TNotificationFunction;

    void registerTerminationCallback(TNotificationFunction callback, unsigned processId);
}
#endif // __ProcessTerminationNotification_h__

ProcessTerminationNotification.cpp:

#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#include <atlcomcli.h>

#pragma comment(lib, "wbemuuid.lib")

#include "ProcessTerminationNotification.h"

class EventSink : public IWbemObjectSink
{
    friend void ProcessTerminationNotification::registerTerminationCallback(TNotificationFunction callback, unsigned processId);

    CComPtr<IWbemServices> pSvc;
    CComPtr<IWbemObjectSink> pStubSink;

    LONG m_lRef;
    ProcessTerminationNotification::TNotificationFunction m_callback;

public:
    EventSink(ProcessTerminationNotification::TNotificationFunction callback)
        : m_lRef(0) 
        , m_callback(callback)
    {}
    ~EventSink()
    {}

    virtual ULONG STDMETHODCALLTYPE AddRef()
    {
        return InterlockedIncrement(&m_lRef);
    }
    virtual ULONG STDMETHODCALLTYPE Release()
    {
        LONG lRef = InterlockedDecrement(&m_lRef);
        if (lRef == 0)
            delete this;
        return lRef;
    }
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv)
    {
        if (riid == IID_IUnknown || riid == IID_IWbemObjectSink)
        {
            *ppv = (IWbemObjectSink *) this;
            AddRef();
            return WBEM_S_NO_ERROR;
        }
        else return E_NOINTERFACE;
    }

    virtual HRESULT STDMETHODCALLTYPE Indicate( 
        LONG lObjectCount,
        IWbemClassObject __RPC_FAR *__RPC_FAR *apObjArray
        )
    {
        m_callback();
        /* Unregister event sink since process is terminated */
        pSvc->CancelAsyncCall(pStubSink);
        return WBEM_S_NO_ERROR;
    }

    virtual HRESULT STDMETHODCALLTYPE SetStatus( 
        /* [in] */ LONG lFlags,
        /* [in] */ HRESULT hResult,
        /* [in] */ BSTR strParam,
        /* [in] */ IWbemClassObject __RPC_FAR *pObjParam
        )
    {
        return WBEM_S_NO_ERROR;
    } 

};


void ProcessTerminationNotification::registerTerminationCallback( TNotificationFunction callback, unsigned processId )
{
    CComPtr<IWbemLocator> pLoc;

    HRESULT hres = CoCreateInstance(
        CLSID_WbemLocator,             
        0, 
        CLSCTX_INPROC_SERVER, 
        IID_IWbemLocator,
        (LPVOID*)&pLoc);

    if (FAILED(hres))
    {
        cout << "Failed to create IWbemLocator object. "
            << "Err code = 0x"
            << hex << hres << endl;
        throw std::exception("ProcessTerminationNotificaiton initialization failed");
    }

    // Step 4: ---------------------------------------------------
    // Connect to WMI through the IWbemLocator::ConnectServer method

    CComPtr<EventSink> pSink(new EventSink(callback));

    // Connect to the local root\cimv2 namespace
    // and obtain pointer pSvc to make IWbemServices calls.
    hres = pLoc->ConnectServer(
        _bstr_t(L"ROOT\\CIMV2"), 
        NULL,
        NULL, 
        0, 
        NULL, 
        0, 
        0, 
        &pSink->pSvc
        );

    if (FAILED(hres))
    {
        cout << "Could not connect. Error code = 0x" 
            << hex << hres << endl;
        throw std::exception("ProcessTerminationNotificaiton initialization failed");
    }

    // Step 5: --------------------------------------------------
    // Set security levels on the proxy -------------------------

    hres = CoSetProxyBlanket(
        pSink->pSvc,                        // Indicates the proxy to set
        RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx 
        RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx 
        NULL,                        // Server principal name 
        RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
        RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
        NULL,                        // client identity
        EOAC_NONE                    // proxy capabilities 
        );

    if (FAILED(hres))
    {
        cout << "Could not set proxy blanket. Error code = 0x" 
            << hex << hres << endl;
        throw std::exception("ProcessTerminationNotificaiton initialization failed");
    }

    // Step 6: -------------------------------------------------
    // Receive event notifications -----------------------------

    // Use an unsecured apartment for security
    CComPtr<IUnsecuredApartment> pUnsecApp;

    hres = CoCreateInstance(CLSID_UnsecuredApartment, NULL, 
        CLSCTX_LOCAL_SERVER, IID_IUnsecuredApartment, 
        (void**)&pUnsecApp);

    CComPtr<IUnknown> pStubUnk; 
    pUnsecApp->CreateObjectStub(pSink, &pStubUnk);

    pStubUnk->QueryInterface(IID_IWbemObjectSink,
        (void **) &pSink->pStubSink);

    // The ExecNotificationQueryAsync method will call
    // The EventQuery::Indicate method when an event occurs
    char buffer[512];
    sprintf_s(buffer, "SELECT * " 
        "FROM __InstanceDeletionEvent WITHIN 1 "
        "WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.ProcessId=%u", processId);

    hres = pSink->pSvc->ExecNotificationQueryAsync(
        _bstr_t("WQL"), 
        _bstr_t(buffer), 
        WBEM_FLAG_SEND_STATUS, 
        NULL, 
        pSink->pStubSink);

    // Check for errors.
    if (FAILED(hres))
    {
        cout << "ExecNotificationQueryAsync failed "
            "with = 0x" << hex << hres << endl;
        throw std::exception("ProcessTerminationNotificaiton initialization failed");
    }
}

Обратите внимание, что код для инициализации безопасности COM и COM-процессов (CoInitializeEx и CoInitializeSecurity) здесь опущен, так как это должно быть сделано в инициализации приложения.

Используйте его с глобальными функциями или используйте boost:: bind для подключения к произвольному методу, пример последнего:

class MyClass
{
public:
    void myProcessTerminationCallback() { cout << "Wohoo!!" << endl; }
};


ProcessTerminationNotification::registerTerminationCallback(
    boost::bind(&MyClass::myProcessTerminationCallback, <pointer to MyClass instance>),
    1234); // Process ID = 1234

Ответ 5

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

Книга "Внутренние части Windows Часть 1" относится к механизму "Трассировка событий для Windows (ETW)", который является механизмом низкого уровня для событий операционной системы.

Следующее сообщение в блоге показывает, как ETW может использоваться в .NET для мониторинга процессов: http://blogs.msdn.com/b/vancem/archive/2013/03/09/using-traceevent-to-mine-information-in-os-registered-etw-providers.aspx

Ответ 6

Вы можете отслеживать создание процесса, подключая функцию CreateProcessInternalW. Подключив эту функцию, вы можете даже вставлять библиотеки DLL в новый процесс.

Ответ 7

Помимо WMI, или если вам нужно предотвратить запуск процесса или потока, или когда вам нужны синхронные уведомления, вы можете использовать подход драйвера режима ядра. Например, наш продукт CallbackProcess делает именно это.

Ответ 8

Запросы WMI могут стоить дорогостоящей производительности ЦП, если они не разработаны должным образом. Если внутреннее событие класса Win32_Process используется для отслеживания события создания процесса, это сильно влияет на производительность . Альтернативный подход заключается в использовании журналов аудита безопасности. Вы можете включить отслеживание процессов с использованием локальной политики безопасности или с помощью объекта групповой политики в случае нескольких машин. После запуска отслеживания процессов вы можете подписаться на журналы событий безопасности с помощью специального XML-запроса для отслеживания определенных процессов, представляющих интерес. Идентификатор события создания процесса - 4688. `

<QueryList>
 <Query Id="0" Path="Security">
   <Select Path="Security">
       *[EventData[Data[@Name='NewProcessName'] ='C:\Windows\explorer.exe']]
       and
       *[System[(EventID=4688)]]
   </Select>
 </Query>
</QueryList>

`

Ответ 9

Захват API должен быть правильным способом заполнить что-то подобное. Вы можете подключить createProcess (A/W/asUserA/W.... и т.д.) И NtTerminateProcess