2010-08-24 118 views
27

Win32進程創建/終止我知道,收到有關Win32進程創建或終止,我們可能會使用提供了註冊全系統的回調函數的能力的API PsSetCreateProcessNotifyRoutine()實現NT內核模式驅動程序通知其每當新進程啓動,退出或終止時由OS調用。如何檢測C++

這可能沒有創建一個NT內核模式驅動程序,只使用Win32 API函數使用c + +?不使用無限循環的基本解決方案查詢當然的活動進程列表。

是否有任何庫或win32 API提供相同的功能(系統範圍的回調,異步事件)?

回答

10

我能想到的唯一的事情是WMI,不知道,如果它提供了一個進程創建回調,但它可能是值得研究的。

+8

是的WMI可以提供我正在尋找(進程創建/終止回調)。 如果有人對如何看看http://msdn.microsoft.com/en-us/library/aa390425%28VS.85%29.aspx 感興趣,謝謝 – Nuno 2010-08-24 16:30:49

-1

API掛鉤應該是正確的方式來滿足這樣的事情。您可以掛鉤的CreateProcess(A/W/asUserA/W ....等)和NtTerminateProcess

+0

這不能實現系統範圍的監控除非你在內核和PatchGuard中執行,這是不可能的。 – 2017-09-27 12:38:11

6

您可以監控所有窗口使用SetWindowsHookExCBTProc創建進程,但是什麼比這更要求要麼WMI,Windows的驅動程序或一點點'​​'

+1

這隻跟蹤Windows的進程,但對於很多場景來說這是一個很好的答案。這也將組裝注入到所述過程中。 – 2015-08-27 21:07:12

+0

CBT掛鉤無法跟蹤進程創建/終止。這不是對這個問題的回答。 – IInspectable 2017-06-09 15:19:16

+0

@IInspectable:CBT鉤子可以跟蹤窗口進程;然而,我的答案的其餘部分回答了這個問題;就基於窗口的流程而言,CBT鉤子很簡單。 – Necrolis 2017-06-09 19:52:26

5

安德斯是正確的,WMI很好地爲此工作。因爲我需要此爲一個項目我可以共享代碼,用於檢測(任意的)進程終止(由於其ID):

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 ::綁定連接到後者的任意方法,例如:

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


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

有沒有人知道WMI如何在內部實現事件? – 2014-02-20 18:01:39

+0

根據「Windows Internals Part 1」一書,有一種名爲「Windows事件跟蹤(ETW)的機制」,它能夠跟蹤進程創建和終止。最終,WMI解決方案存在一個重大缺陷,因爲它不能實時(同步)提供事件。通過查看WMI WQL的WITHIN子句可以看出。 – 2014-02-20 21:49:28

+0

實時需要信息的情況很少,如果有的話。在99.999%的案例中,足以知道該過程已經死亡。 – Robert 2014-02-21 10:11:05

1

您可以通過掛鉤CreateProcessInternalW功能監視進程創建。通過掛鉤這個函數,你甚至可以將DLL注入到新進程中。

4

由於已經由以前的評論暗示,有使用WMI監視進程事​​件WMI未提供事件同步,.i.e一個缺點。耽擱很短。

書「Windows內部第1部分」指的是一個名爲「Windows事件跟蹤(ETW)」,這是操作系統事件的低級別機制機制。

下面的博客文章介紹如何ETW可以在淨用來監視進程: http://blogs.msdn.com/b/vancem/archive/2013/03/09/using-traceevent-to-mine-information-in-os-registered-etw-providers.aspx

+2

不幸的是,事實證明,ETW並沒有提供同步/實時事件。 ETW事件也受到緩衝。 – 2014-02-22 18:58:08

19

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一旦終止該進程。

+0

有沒有辦法使用您的解決方案檢測該進程的退出代碼? – 2014-10-31 23:26:10

+0

有沒有像這樣的方法,但跟蹤過程創建? – brunoqc 2014-11-07 15:41:06

+1

@brunoqc我在這個問題中發現了WMI的方式。 – 2014-11-07 19:09:16

0

除了WMI,或者如果您需要阻止進程或線程啓動,或者需要同步通知時,您可以使用內核模式驅動程序方法。例如,我們的CallbackProcess產品就是這樣做的。