EXE和SYS基于事件同步消息通知

本文介绍了一个Windows内核驱动程序的设计与实现,该驱动通过创建同步事件对象来通知用户空间的应用程序有关进程创建的信息。此外,还实现了设备控制例程以处理来自用户空间的请求,如启动、停止通知及获取数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#ifndef _HEADER_HEAD_FILE
#define _HEADER_HEAD_FILE
#pragma once
#include <ntifs.h>
#include <ntddk.h>

#ifndef MAX_PATH
#define MAX_PATH	260
#endif



NTKERNELAPI UCHAR * PsGetProcessImageFileName(__in PEPROCESS Process);



//驱动控制代码
#define IOCTL_START CTL_CODE(FILE_DEVICE_UNKNOWN, 0x810,METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_STOP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x811,METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_GET_DATA CTL_CODE(FILE_DEVICE_UNKNOWN, 0x812,METHOD_BUFFERED, FILE_ANY_ACCESS)

#endif


#include "Header.h"





//同步事件对象
PRKEVENT g_pEventObject = NULL;
//句柄信息
OBJECT_HANDLE_INFORMATION g_ObjectHandleInfo;

char g_szOutBuf[MAX_PATH] = { 0 };



//获取进程名
PCHAR GetProcessName16ByProcessId(HANDLE ProcessId)
{
	//定义变量
	NTSTATUS status = STATUS_UNSUCCESSFUL;
	PEPROCESS ProcessObj = NULL;
	PUCHAR ProcessName = NULL;

	//进程ID和返回一个引用指针的过程EPROCESS结构
	status = PsLookupProcessByProcessId(ProcessId, &ProcessObj);
	if (NT_SUCCESS(status))
	{
		// ImageFileName    : [16]  "SogouExplorer.e"
		//使用这个函数,只能获取进程名称是16的长度,后面的被截取了。。。
		ProcessName = PsGetProcessImageFileName(ProcessObj);
		ObfDereferenceObject(ProcessObj);
	}

	return ProcessName;
}



VOID CreateProcessNotifyFunction(IN HANDLE  ParentId, IN HANDLE  ProcessId, IN BOOLEAN  Create)
{
	if (Create)
	{
		char* pName=GetProcessName16ByProcessId(ProcessId);
		if (pName)
		{
			RtlZeroMemory(g_szOutBuf, sizeof(g_szOutBuf));
			RtlCopyMemory(g_szOutBuf, pName, strlen(pName)+1);

			//设置事件为有信号,通知应用层
			KeSetEvent(g_pEventObject, 0, FALSE);
		}

	}

	return;
}


VOID DriverUnload(DRIVER_OBJECT *DriverObject)
{
	PsSetCreateProcessNotifyRoutine(CreateProcessNotifyFunction, TRUE);
	UNICODE_STRING Win32Device;
	RtlInitUnicodeString(&Win32Device, L"\\DosDevices\\KernelHandle");
	IoDeleteSymbolicLink(&Win32Device);
	IoDeleteDevice(DriverObject->DeviceObject);
	return;
}

NTSTATUS KernelHandleCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 0;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

NTSTATUS KernelHandleClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
	Irp->IoStatus.Information = 0;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return Irp->IoStatus.Status;
}

NTSTATUS KernelHandleDefaultHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	NTSTATUS status = STATUS_SUCCESS;
	ULONG ulReturn = 0;
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
	ULONG ulCtrlCode = stack->Parameters.DeviceIoControl.IoControlCode;
	PVOID InputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer;
	PVOID OutputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer;
	ULONG ulInputBufferSize = stack->Parameters.DeviceIoControl.InputBufferLength;
	ULONG ulOutputBufferSize = stack->Parameters.DeviceIoControl.OutputBufferLength;

	switch (ulCtrlCode)
	{
	case IOCTL_START:
	{
		//设置同步事件
		if (InputBuffer == NULL || ulInputBufferSize < sizeof(HANDLE))
		{
			KdPrint(("Set Event Error~!\n"));
			break;
		}

		//取得句柄对象
		HANDLE hEvent = *(HANDLE*)InputBuffer;
		status = ObReferenceObjectByHandle(hEvent, GENERIC_ALL, NULL, KernelMode, (PVOID*)&g_pEventObject, &g_ObjectHandleInfo);
		PsSetCreateProcessNotifyRoutine(CreateProcessNotifyFunction, FALSE);
		break;
	}
	case IOCTL_STOP:
	{
	
		//移除进程创建通知函数
		PsSetCreateProcessNotifyRoutine(CreateProcessNotifyFunction, TRUE);
		//释放对象引用
		if (g_pEventObject != NULL)
		{
			ObDereferenceObject(g_pEventObject);
			g_pEventObject = NULL;
		}

		break;
	}
	case IOCTL_GET_DATA:
	{
		int nLength = strlen(g_szOutBuf)+1;
		if (OutputBuffer == NULL && ulOutputBufferSize < nLength)
		{
			KdPrint(("OutputBufferSize is too small ~!\n"));
			break;
		}

		//复制进程到输出缓冲区
		RtlCopyBytes((PCHAR)OutputBuffer, g_szOutBuf, nLength);

		break;
	}
	default:
		break;
	}


	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = ulOutputBufferSize;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return Irp->IoStatus.Status;
}

NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
	NTSTATUS status;
	PDEVICE_OBJECT DeviceObject = NULL;
	UNICODE_STRING DeviceName;
	UNICODE_STRING Win32Device;

	KdBreakPoint();
	DriverObject->DriverUnload = DriverUnload;
	RtlInitUnicodeString(&DeviceName, L"\\Device\\KernelHandle");
	RtlInitUnicodeString(&Win32Device, L"\\DosDevices\\KernelHandle");

	DriverObject->MajorFunction[IRP_MJ_CREATE] = KernelHandleCreate;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = KernelHandleClose;
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KernelHandleDefaultHandler;



	status = IoCreateDevice(DriverObject,0,&DeviceName,FILE_DEVICE_UNKNOWN,0,FALSE,&DeviceObject);
	if (!NT_SUCCESS(status))
		return status;
	if (!DeviceObject)
		return STATUS_UNEXPECTED_IO_ERROR;
	DeviceObject->Flags |= DO_DIRECT_IO;
	DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
	status = IoCreateSymbolicLink(&Win32Device, &DeviceName);
	DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

	return STATUS_SUCCESS;
}





#include <windows.h>
#include <tchar.h>
#include <stdio.h>


HANDLE hDevice;
HANDLE g_hKernelEvent = NULL;

//驱动控制代码
#define IOCTL_START CTL_CODE(FILE_DEVICE_UNKNOWN, 0x810,METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_STOP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x811,METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_GET_DATA CTL_CODE(FILE_DEVICE_UNKNOWN, 0x812,METHOD_BUFFERED, FILE_ANY_ACCESS)


DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
	printf("线程开始运行\n");

	DWORD dwRet;
	char szBuffer[MAX_PATH] = { 0 };

	while (WaitForSingleObject(g_hKernelEvent, INFINITE) == WAIT_OBJECT_0)
	{
		printf("收到状态\n");

		//等待完成,向驱动发送请求
		DeviceIoControl(hDevice,IOCTL_GET_DATA, NULL, 0, szBuffer, MAX_PATH, &dwRet,NULL);

		printf("从内核发来的信息是:%s\n", szBuffer);

		//设置同步事件为无信号,等待下一次通知
		ResetEvent(g_hKernelEvent);
	}

	printf("线程结束\n");
	return 0;
}





int main(void)
{

	//创建手动重置的事件
	g_hKernelEvent = CreateEvent(NULL, TRUE, FALSE, NULL);


	//打开驱动的符号链接
	hDevice = CreateFile(L"\\\\.\\KernelHandle", GENERIC_READ | GENERIC_WRITE, 0,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (INVALID_HANDLE_VALUE == hDevice)
	{
		printf("CreateFile fail!\n");
		getchar();
		getchar();
		return FALSE;
	}
	DWORD dwRet;
	DeviceIoControl(hDevice, IOCTL_START, &g_hKernelEvent, sizeof(g_hKernelEvent), NULL, NULL, &dwRet, NULL);


	HANDLE hThread =CreateThread(NULL, NULL, ThreadProc, NULL, NULL, NULL);
	CloseHandle(hThread);


	getchar();
	getchar();

	DeviceIoControl(hDevice, IOCTL_STOP, NULL, 0, NULL, NULL, &dwRet, NULL);
	CloseHandle(hDevice);
	return 0;
}



### C语言中事件消息处理机制的实现 在C语言中,可以通过多种方法来实现事件消息处理机制。其中一种常见的方式是基于 **消息队列** 的设计模式[^1]。这种机制允许不同进程之间通过共享的消息缓冲区传递数据或通知特定事件的发生。 以下是使用系统V IPC API 创建并管理消息队列的一个简单示例: #### 示例代码:创建操作消息队列 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_TEXT 256 // 定义消息结构体 struct msg_buffer { long msg_type; // 消息类型 char msg_text[MAX_TEXT]; // 消息内容 }; int main() { key_t key; int msgid; // 使用ftok生成唯一的key值 key = ftok("msgq", 'A'); // 创建消息队列 msgid = msgget(key, 0666 | IPC_CREAT); if (msgid == -1) { perror("msgget failed"); exit(EXIT_FAILURE); } struct msg_buffer message; printf("Enter the message to send: "); fgets(message.msg_text, MAX_TEXT, stdin); // 设置消息类型为1 message.msg_type = 1; // 发送消息到队列 msgsnd(msgid, &message, strlen(message.msg_text) + 1, 0); printf("Message sent.\n"); // 接收消息 msgrcv(msgid, &message, sizeof(message), 1, 0); printf("Received Message: %s\n", message.msg_text); // 删除消息队列 msgctl(msgid, IPC_RMID, NULL); return EXIT_SUCCESS; } ``` 上述代码展示了如何使用 `msgget` 函数创建一个消息队列,并通过 `msgsnd` `msgrcv` 进行消息的发送与接收。此过程非常适合于需要异步通信的应用场景。 --- #### 关键点解析 - **消息队列的作用** 消息队列提供了一种可靠的机制,在多个进程中同步或异步地交换信息。它特别适合用于事件驱动型应用程序,例如监控系统、日志记录器或其他实时响应需求较高的环境。 - **消息结构定义** 需要自定义一个包含至少两个字段的数据结构:一个是固定类型的标志位(通常是一个整数),另一个则是实际存储的信息部分。这里我们采用的是标准 POSIX 结构形式。 - **错误处理的重要性** 虽然上面的例子省略了一些细节上的考虑,但在真实项目开发过程中应当加入充分的健壮性检测逻辑,比如检查函数返回值是否成功以及资源释放等问题。 --- #### 动态内容支持扩展 如果希望进一步增强功能以适应更加复杂的业务需求,则可以参考 HTTP 协议里的分块传输编码思路[^2]。尽管两者应用场景有所不同,但核心理念相似——即按需分割大数据流成若干小片段逐一传送至目标端再重新组装还原原始形态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值