进程监控驱动 PsSetCreateProcessNotifyRoutine

函数原型:
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下查看结果:
进程监控驱动 PsSetCreateProcessNotifyRoutine - Prairie - work labor and play
可以看到每当有一个进程创建的时候就会被回调函数监视到,在这里我们打印出进程的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 ”即可。

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
驱动级注入DLL源码是一段用于实现在内核层次进行DLL注入的代码。通常情况下,DLL注入用于在目标进程的地址空间中运行指定的DLL文件,从而实现对目标进程监控、修改或增强功能。 驱动级注入DLL源码需要使用Windows驱动开发工具包(WDK)来编写,以下是一种可能的实现方式: ```c #include <ntifs.h> // 目标进程ID #define TARGET_PROCESS_ID 1234 // 待注入DLL路径 #define DLL_PATH L"C:\\path\\to\\mydll.dll" // 在进程创建时触发的回调函数 VOID ProcessNotifyCallback(HANDLE hParentId, HANDLE hProcessId, BOOLEAN bCreate) { UNICODE_STRING usDllPath; PUNICODE_STRING pusDllPath; NTSTATUS status; HANDLE hTargetProcess; PEPROCESS pTargetProcess; PVOID pAllocatedMemory; SIZE_T ulDllPathSize; // 判断是否为目标进程创建 if (hParentId != NULL && hTargetProcess != NULL && (HANDLE)PsGetCurrentProcessId() == hParentId) { // 打开目标进程 status = PsLookupProcessByProcessId(hProcessId, &pTargetProcess); if (NT_SUCCESS(status)) { // 分配内存来保存DLL路径 ulDllPathSize = sizeof(DLL_PATH); pAllocatedMemory = ExAllocatePoolWithTag(NonPagedPool, ulDllPathSize, 'DLLI'); if (pAllocatedMemory != NULL) { RtlInitUnicodeString(&usDllPath, DLL_PATH); pusDllPath = (PUNICODE_STRING)pAllocatedMemory; RtlCopyUnicodeString(pusDllPath, &usDllPath); // 注入DLL status = ZwOpenProcess(&hTargetProcess, PROCESS_ALL_ACCESS, NULL, &hProcessId); if (NT_SUCCESS(status)) { status = LdrLoadDll(pTargetProcess, NULL, pusDllPath, &hModule); ZwClose(hTargetProcess); } // 释放内存 ExFreePoolWithTag(pAllocatedMemory, 'DLLI'); } } } } // 注册进程创建通知回调 NTSTATUS RegisterProcessNotifyCallback(VOID) { PVOID pCallbackRegistration; return PsSetCreateProcessNotifyRoutine(ProcessNotifyCallback, FALSE, &pCallbackRegistration); } // 取消注册进程创建通知回调 VOID UnregisterProcessNotifyCallback(VOID) { PsSetCreateProcessNotifyRoutine(ProcessNotifyCallback, TRUE, NULL); } // 驱动入口函数 NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING puniRegistryPath) { NTSTATUS status; // 注册进程创建通知回调 status = RegisterProcessNotifyCallback(); if (!NT_SUCCESS(status)) { DbgPrint("Failed to register process notify callback\n"); return status; } // 等待驱动被卸载 KeWaitForSingleObject(&(pDriverObject->DeviceObject->DeviceLock), Executive, KernelMode, FALSE, NULL); // 取消注册进程创建通知回调 UnregisterProcessNotifyCallback(); return STATUS_SUCCESS; } ``` 以上代码是一种简单的驱动级注入DLL的实现方式。当目标进程创建时,会触发回调函数,该回调函数会打开目标进程并注入指定的DLL文件。 需要注意的是,驱动级DLL注入在实际使用中需要谨慎使用,因为其对系统稳定性和安全性有较大的影响,一般情况下最好选择更安全可靠的用户级DLL注入方式。此外,驱动级开发需要高深的系统内核知识和经验,对于普通开发者而言较为复杂。使用驱动级DLL注入时务必遵守法律法规和道德规范,避免造成不良后果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值