--- title: Windows内核驱动-进程创建回调 description: 如何创建一个进程创建回调项目 date: 2025-04-01 slug: windows-process-driver image: process.png keywords: - 驱动 - driver - windows - process - 进程 - 回调 categories: - Windows tags: - driver - windows --- # 一、核心代码 一共三部分: 1. 定义回调函数 2. 注册回调 3. 移除回调 ```cpp #include // 定义回调函数,在后续实现 VOID ProcessNotifyRoutine( _Inout_ PEPROCESS Process, // 进程对象,这是个不透明结构,不建议强行使用其中的字段 _In_ HANDLE ProcessId, // 进程ID _In_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo // 进程创建信息 ); // 定义卸载函数,在后续实现 NTSTATUS DriverUnload(_In_ PDRIVER_OBJECT DriverObject); // 在DriverEntry中注册回调 NTSTATUS DriverEntry( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) { UNREFERENCED_PARAMETER(RegistryPath); // 未使用的参数,需要UNREFERENCED_PARAMETER处理,不然会warning NTSTATUS status; // 注册卸载函数 DriverObject->DriverUnload = DriverUnload; // 注册进程回调,第二个参数表示是否移除,true表示移除,false表示注册 status = PsSetCreateProcessNotifyRoutineEx(ProcessNotifyRoutine, FALSE); return STATUS_SUCCESS; } // 在卸载函数中移除回调 NTSTATUS DriverUnload(_In_ PDRIVER_OBJECT DriverObject) { UNREFERENCED_PARAMETER(DriverObject); NTSTATUS status; // 移除回调,第二个参数表示是否移除,true表示移除,false表示注册 status = PsSetCreateProcessNotifyRoutineEx(ProcessNotifyRoutine, TRUE); return status; } // 进程回调实现 VOID ProcessNotifyRoutine( _Inout_ PEPROCESS Process, // 进程对象,这是个不透明结构,不建议强行使用其中的字段 _In_ HANDLE ProcessId, // 进程ID _In_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo // 进程创建信息 ) { UNREFERENCED_PARAMETER(Process); UNREFERENCED_PARAMETER(ProcessId); UNREFERENCED_PARAMETER(CreateInfo); // 这里可以记录进程的创建和销毁 if (CreateInfo != NULL) { // 进程创建 // 如果需要阻止进程创建,则可以 // 设置 CreateInfo 中的 CreationStatus 字段为 STATUS_ACCESS_DENIED // CreateInfo->CreationStatus = STATUS_ACCESS_DENIED; } else { // 进程销毁 } } ``` # 二、关键操作 ## 2.1 链接器设置 上述代码编译后,无法正确触发 `ProcessNotifyRoutine` 回调,需要为链接器增加参数: ``` /INTEGRITYCHECK ``` 这一点需要着重注意。 ## 2.2 PsSetCreateProcessNotifyRoutineEx 注册回调 函数原型: ```cpp NTSTATUS PsSetCreateProcessNotifyRoutineEx ( _In_ PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine, _In_ BOOLEAN Remove ); ``` 参数解释: 第一个参数:回调函数,当进程创建或者销毁时会调用此函数,类型为 `PCREATE_PROCESS_NOTIFY_ROUTINE_EX` 第二个参数:是否移除,true表示移除,false表示注册 其中`PCREATE_PROCESS_NOTIFY_ROUTINE_EX` 定义为: ``` typedef VOID (*PCREATE_PROCESS_NOTIFY_ROUTINE_EX) ( _Inout_ PEPROCESS Process, _In_ HANDLE ProcessId, _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo ); ``` `PEPROCESS` 是内核态进程对象,`HANDLE` 是进程ID,`PPS_CREATE_NOTIFY_INFO` 是进程创建信息,如果为NULL,表示进程销毁,否则表示进程创建。 ## 2.3 获取进程信息 如上的 `PCREATE_PROCESS_NOTIFY_ROUTINE_EX` 定义,我们可以通过回调函数的 `CreateInfo` 参数获取进程相关信息。 `PPS_CREATE_NOTIFY_INFO` 定义如下: ``` 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; _In_ CLIENT_ID CreatingThreadId; _Inout_ struct _FILE_OBJECT *FileObject; _In_ PCUNICODE_STRING ImageFileName; _In_opt_ PCUNICODE_STRING CommandLine; _Inout_ NTSTATUS CreationStatus; } PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO; ``` 可以直接获得: - `ParentProcessId`:父进程ID - `CreatingThreadId`:创建进程的线程ID - `FileObject`:文件对象,可以获得文件路径 - `ImageFileName`:进程映像文件名,也就是可执行文件路径 - `CommandLine`:进程启动命令行,如果为NULL,表示没有命令行,否则为命令行字符串 ## 2.4 阻止进程创建 `PPS_CREATE_NOTIFY_INFO` 中有一个 `CreationStatus` 字段,如果设置为 `STATUS_ACCESS_DENIED`,则表示阻止进程创建。 # 三、参考资料 [1] [Windows 内核不透明结构](https://learn.microsoft.com/zh-cn/windows-hardware/drivers/kernel/eprocess#eprocess) [2] [PsSetCreateProcessNotifyRoutineEx 函数 (ntddk.h)](https://learn.microsoft.com/zh-cn/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreateprocessnotifyroutineex) [3] [PCREATE_PROCESS_NOTIFY_ROUTINE_EX回调函数 (ntddk.h)](https://learn.microsoft.com/zh-cn/windows-hardware/drivers/ddi/ntddk/nc-ntddk-pcreate_process_notify_routine_ex) [4] [PS_CREATE_NOTIFY_INFO 结构 (ntddk.h)](https://learn.microsoft.com/zh-cn/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_ps_create_notify_info)