Как обнаружить создание / завершение процесса win32 в c ++ - PullRequest
33 голосов
/ 24 августа 2010

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

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

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

Ответы [ 9 ]

25 голосов
/ 15 марта 2014

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 после завершения процесса.

11 голосов
/ 24 августа 2010

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

6 голосов
/ 24 августа 2010

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

5 голосов
/ 28 декабря 2012

Андерс прав, 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
4 голосов
/ 21 февраля 2014

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

Книга "Внутренние компоненты 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

1 голос
/ 01 апреля 2013

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

0 голосов
/ 13 мая 2018

Запросы 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>

`

0 голосов
/ 15 февраля 2016

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

0 голосов
/ 24 августа 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...