Ответ 1
Единственное, о чем я мог подумать, это WMI, не уверен, что он обеспечивает обратный вызов для создания процесса, но он может быть интересен.
Я знаю, что для получения уведомлений о создании или прекращении процесса Win32 мы могли бы использовать драйвер режима ядра NT с использованием API PsSetCreateProcessNotifyRoutine()
, который предлагает возможность регистрировать функцию обратного вызова всей системы, которая вызывается ОС каждый раз, когда новый процесс запускается, завершается или завершается.
Возможно ли это, не создавая драйвер режима ядра NT, используя только функции Win32 API с использованием С++? Не использовать базовое решение бесконечного цикла, запрашивая список активного процесса, конечно.
Есть ли библиотека или win32 API, которые обеспечивают ту же функциональность (системный обратный вызов, асинхронные события)?
Единственное, о чем я мог подумать, это WMI, не уверен, что он обеспечивает обратный вызов для создания процесса, но он может быть интересен.
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
после завершения процесса.
Вы можете отслеживать все процессы создания окна с помощью SetWindowsHookEx с CBTProc, однако что-то большее, чем это требует либо WMI, либо драйвер Windows, либо немного Black Magic
Андерс прав, 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
Как уже намечено предыдущим комментарием, существует недостаток в использовании 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
Вы можете отслеживать создание процесса, подключая функцию CreateProcessInternalW
. Подключив эту функцию, вы можете даже вставлять библиотеки DLL в новый процесс.
Помимо WMI, или если вам нужно предотвратить запуск процесса или потока, или когда вам нужны синхронные уведомления, вы можете использовать подход драйвера режима ядра. Например, наш продукт CallbackProcess делает именно это.
Запросы 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>
`
Захват API должен быть правильным способом заполнить что-то подобное. Вы можете подключить createProcess (A/W/asUserA/W.... и т.д.) И NtTerminateProcess