函數原型:
NTSTATUS PsSetCreateProcessNotifyRoutine( _In_ PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine, _In_ BOOLEAN Remove );
原文的解釋為:The PsSetCreateProcessNotifyRoutine routine adds a driver-supplied callback routine to, or removes it from, a list of routines to be called whenever a process is created or deleted.
簡單的翻譯一下:PsSetCreateProcessNotifyRoutine 例程增加一個"驅動供應"回調例程,在進程創建或消亡的時候回調函數會被調用。
NotifyRoutine為回調指針:
定義為:
VOID (*PCREATE_PROCESS_NOTIFY_ROUTINE) ( IN HANDLE ParentId, IN HANDLE ProcessId, IN BOOLEAN Create );
- NotifyRoutine [in]
-
Specifies the entry point of a caller-supplied process-creation callback routine.
- Remove [in]
-
Indicates whether the routine specified by NotifyRoutine should be added to or removed from the system's list of notification routines. If FALSE, the specified routine is added to the list. If TRUE, the specified routine is removed from the list.
- 如果為FALSE 表示在系統通知例程列表中增加此例程,如果為TRUE標志從系統通知例程列表中刪除該例程,
- 驅動卸載時應該時此參數應該為TRUE;
-
廢話不說了直接上代碼框架: #include <ntddk.h> VOID UnloadDriver(PDRIVER_OBJECT pDriver); VOID CreateProcessRoutineSpy( IN HANDLE ParentId, IN HANDLE ProcessId, IN BOOLEAN Create ); NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING Registry) { NTSTATUS status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(pDriver); UNREFERENCED_PARAMETER(Registry); KdPrint(("[SysTest] DriverEntry Loading.\n")); status = PsSetCreateProcessNotifyRoutine(CreateProcessRoutineSpy, FALSE); if (!NT_SUCCESS(status)) { KdPrint(("[SysTest] PsSetCreateProcessNotifyRoutine failed status:(%x).\n", status)); return status; } pDriver->DriverUnload = UnloadDriver; return status; } VOID CreateProcessRoutineSpy( IN HANDLE ParentId, IN HANDLE ProcessId, IN BOOLEAN Create ) { if (Create) { KdPrint(("[SysTest] Process Created. ParentId:(%d) ProcessId:(%d).\n", ParentId, ProcessId)); } else { KdPrint(("[SysTest] Process Terminated ProcessId:(%d).ParentId:(%d) .\n", ProcessId, ParentId)); } return; } VOID UnloadDriver(PDRIVER_OBJECT pDriver) { UNREFERENCED_PARAMETER(pDriver); NTSTATUS status; status = PsSetCreateProcessNotifyRoutine(CreateProcessRoutineSpy, TRUE); if (NT_SUCCESS(status)) { KdPrint(("[SysTest] UnloadDriver.\n")); } return; }
Dbgview查看結果:
可以看到每當有一個進程創建的時候就會被回調函數監視到,在這里我們打印出進程的ID和父進程的ID,每當一個進程消亡時也將其ID打印出來。這個簡單的進程監視框架就做好了。
擴展 CreateProcessNotifyEx
PsSetCreateProcessNotifyRoutine只能記錄進程創建或消亡,不能阻止進程的創建,
PsSetCreateProcessNotifyRoutineEx可以阻止進程的創建,先看一下相關函數:
注冊函數:
NTSTATUS PsSetCreateProcessNotifyRoutineEx( _In_ PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine, _In_ BOOLEAN Remove );
回調函數:
VOID
CreateProcessNotifyEx(
__inout PEPROCESS Process,
__in HANDLE ProcessId,
__in_opt PPS_CREATE_NOTIFY_INFO CreateInfo
);可知,回調函數有所變化,在回調函數中,CreateInfo為NULL時,表示一個進程在結束,否則為進程創建,看一下CreateInfo結構:
typedef struct _PS_CREATE_NOTIFY_INFO {
_In_ SIZE_T Size;
union {
_In_ ULONG Flags;
struct {
_In_ ULONG FileOpenNameAvailable : 1;
_In_ ULONG Reserved : 31;
};
};
_In_ HANDLE ParentProcessId; //父進程ID
_In_ CLIENT_ID CreatingThreadId; //父進程信息 ,包括父進程ID,父進程的主線程ID
_Inout_ struct _FILE_OBJECT *FileObject; //進程有關的文件對象
_In_ PCUNICODE_STRING ImageFileName; //進程名
_In_opt_ PCUNICODE_STRING CommandLine; //進程命令行參數,有時候為NULL
_Inout_ NTSTATUS CreationStatus;//返回結果,修改這個結果可以改變進程的創建
} PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO;現在舉一例,利用此回調來阻止記事本的創建:
#include <ntddk.h> VOID UnloadDriver(PDRIVER_OBJECT driver); VOID CreateProcessNotifyEx( __inout PEPROCESS Process, __in HANDLE ProcessId, __in_opt PPS_CREATE_NOTIFY_INFO CreateInfo ); BOOLEAN bSuccess = FALSE; NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING registry) { NTSTATUS status = STATUS_UNSUCCESSFUL; UNREFERENCED_PARAMETER(registry); KdPrint(("[systest] Driver Loading.\n")); driver->DriverUnload = UnloadDriver; status = PsSetCreateProcessNotifyRoutineEx(CreateProcessNotifyEx, FALSE); if (!NT_SUCCESS(status)) { KdPrint(("[systest] PsSetCreateProcessNotifyRoutineEx error code:(%x).\n", status)); return status; } bSuccess = TRUE; return status; } VOID CreateProcessNotifyEx( __inout PEPROCESS Process, __in HANDLE ProcessId, __in_opt PPS_CREATE_NOTIFY_INFO CreateInfo ) { UNREFERENCED_PARAMETER(ProcessId); UNREFERENCED_PARAMETER(Process); PWCHAR pSub = NULL; //為NULL表示進程退出 if (NULL == CreateInfo) { DbgPrint(("[systest]:process exits.\n")); return; } KdPrint(("[systest]process create:(%wZ).\n", CreateInfo->ImageFileName)); pSub = wcswcs(CreateInfo->ImageFileName->Buffer, L"notepad.exe"); if (NULL != pSub) { //修改返回結果為拒絕訪問,使得創建進程失敗 CreateInfo->CreationStatus = STATUS_ACCESS_DENIED; } return; } VOID UnloadDriver(PDRIVER_OBJECT driver) { UNREFERENCED_PARAMETER(driver); KdPrint(("[systest]:driver unload.\n")); if (bSuccess) { PsSetCreateProcessNotifyRoutineEx(CreateProcessNotifyEx, TRUE); } return; }
需要注意的是,PsSetCreateProcessNotifyRoutineEx編譯的時候可能會出現拒絕訪問,解決辦法是在工程屬性中的連接器-->CommandLine,添加“/IntegrityCheck ”即可。