如何在 C++ 中检测 win32 进程的创建/终止

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3556048/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:07:18  来源:igfitidea点击:

How to detect win32 process creation/termination in c++

c++winapiprocess

提问by Nuno

I know that to receive notifications about Win32 process creation or termination we might implement a NT kernel-mode driver using the APIs PsSetCreateProcessNotifyRoutine()that offers the ability to register system-wide callback function which is called by OS each time when a new process starts, exits or is terminated.

我知道要接收有关 Win32 进程创建或终止的通知,我们可能会使用 API 实现 NT 内核模式驱动程序,该驱动程序PsSetCreateProcessNotifyRoutine()提供注册系统范围回调函数的能力,每次新进程启动、退出或被终止。

Is this possible without creating a NT kernel-mode driver, only using Win32 API functions using c++? Not using the basic solution of a infinite cycle querying the list of active process of course.

这是否可能不创建 NT 内核模式驱动程序,仅使用使用 c++ 的 Win32 API 函数?当然不使用无限循环查询活动进程列表的基本解决方案。

Is there any library or win32 API that provides the same functionality (system wide callback, asynchronous events)?

是否有任何库或 win32 API 提供相同的功能(系统范围的回调、异步事件)?

采纳答案by Anders

The only thing I could think of is WMI, not sure if it provides a process creation callback, but it might be worth looking into.

我唯一能想到的是 WMI,不确定它是否提供进程创建回调,但可能值得研究。

回答by Anton K

WMI is great and it works with process names too. Although if you need to track process termination the more lightweight and easier way is the following:

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);

This code will call WaitOrTimerCallbackonce the process terminated.

WaitOrTimerCallback一旦进程终止,此代码将调用。

回答by Robert

Anders is correct, WMI works nicely for this. Since I needed this for a project I can share the code for detecting (arbitrary) process termination (given its ID):

安德斯是对的,WMI 可以很好地解决这个问题。由于我的项目需要这个,我可以共享用于检测(任意)进程终止的代码(给定它的 ID):

ProcessTerminationNotification.h:

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:

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");
    }
}

Note that the code to initialize COM and COM process security (CoInitializeEx and CoInitializeSecurity) is omitted here since it should be done in the application initialization.

请注意,这里省略了初始化 COM 和 COM 进程安全性(CoInitializeEx 和 CoInitializeSecurity)的代码,因为它应该在应用程序初始化中完成。

Use it with global functions or use boost::bind to connect to an arbitrary method, example of the latter:

将其与全局函数一起使用或使用 boost::bind 连接到任意方法,后者的示例:

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


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

回答by Necrolis

You can monitor all Window creating processes using SetWindowsHookExwith a CBTProc, however anything more than that requires either WMI, a windows driver or a little bit of 'Black Magic'

您可以使用SetWindowsHookExCBTProc来监视所有 Window 创建过程,但是除此之外的任何事情都需要 WMI、Windows 驱动程序或一点“黑魔法

回答by Christian K.

As already hinted by a previous comment, there's a drawback with using WMI to monitor process events as WMI is not providing events synchronously, .i.e. with a short delay.

正如之前的评论所暗示的那样,使用 WMI 来监视进程事​​件有一个缺点,因为 WMI 没有同步提供事件,即有很短的延迟。

The book "Windows Internals Part 1" is referring to a mechanism called "Event Tracing for Windows (ETW)" which is a low-level mechanism for operating system events.

“Windows Internals Part 1”一书指的是一种称为“Windows 事件跟踪 (ETW)”的机制,它是操作系统事件的低级机制。

The following blog post shows how ETW can be used within .Net to monitor processes: http://blogs.msdn.com/b/vancem/archive/2013/03/09/using-traceevent-to-mine-information-in-os-registered-etw-providers.aspx

以下博客文章展示了如何在 .Net 中使用 ETW 来监控进程:http: //blogs.msdn.com/b/vancem/archive/2013/03/09/using-traceevent-to-mine-information-in -os-registered-etw-providers.aspx

回答by zwclose7

You can monitor process creation by hooking CreateProcessInternalWfunction. By hooking this function, you can even inject DLLs into the new process.

您可以通过挂钩CreateProcessInternalW函数监视进程创建。通过挂钩此函数,您甚至可以将 DLL 注入新进程。

回答by Eugene Mayevski 'Callback

Besides WMI, or if you need to prevent the process or thread from being started, or when you need synchronous notifications, you can use a kernel-mode driver approach. Our CallbackProcessproduct, for example, does exactly this.

除了WMI,或者如果你需要阻止进程或线程被启动,或者当你需要同步通知时,你可以使用内核模式驱动程序方法。例如,我们的CallbackProcess产品就是这样做的。

回答by Red John

WMI queries can cost heavy CPU performance if not designed properly. If an intrinsic event from Win32_Process class is used to track process creation event, this impacts performance heavily. An alternate approach is to leverage Security Audit logs. You can enable Process Tracking using Local Security Policy or using a GPO in case of multiple machines. Once the process tracking starts, you can subscribe to security event logs with a custom XML query to monitor certain processes of your interest. The process creation event ID is 4688. `

如果设计不当,WMI 查询会消耗大量 CPU 性能。如果使用 Win32_Process 类的内部事件来跟踪进程创建事件,则会严重影响性能。另一种方法是利用安全审计日志。您可以使用本地安全策略或在多台机器的情况下使用 GPO 启用进程跟踪。流程跟踪开始后,您可以使用自定义 XML 查询订阅安全事件日志,以监控您感兴趣的某些流程。进程创建事件 ID 为 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>

`

`

回答by christian

API-hooking should be the right way to fullfill something like that. You can hook createProcess(A/W/asUserA/W.... etc) and NtTerminateProcess

API-hooking 应该是完成类似事情的正确方法。您可以挂钩 createProcess(A/W/asUserA/W.... etc) 和 NtTerminateProcess