moonlightwatch 965f382cc5
All checks were successful
Build and Upload / Explore-Gitea-Actions (push) Successful in 2m2s
post: windows-process-driver
2025-04-01 14:42:31 +08:00

5.2 KiB
Raw Permalink Blame History

title, description, date, slug, image, keywords, categories, tags
title description date slug image keywords categories tags
Windows内核驱动-进程创建回调 如何创建一个进程创建回调项目 2025-04-01 windows-process-driver process.png
驱动
driver
windows
process
进程
回调
Windows
driver
windows

一、核心代码

一共三部分:

  1. 定义回调函数
  2. 注册回调
  3. 移除回调
#include <ntddk.h>

// 定义回调函数,在后续实现
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 注册回调

函数原型:

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 是进程IDPPS_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 内核不透明结构
[2] PsSetCreateProcessNotifyRoutineEx 函数 (ntddk.h)
[3] PCREATE_PROCESS_NOTIFY_ROUTINE_EX回调函数 (ntddk.h)
[4] PS_CREATE_NOTIFY_INFO 结构 (ntddk.h)