windows下串口过滤

主要参考windows内核安全与驱动开发的第七章

实现原理如下图

 

windows下串口过滤_第1张图片

 源码如下

///
/// @file		comcap.c
/// @author	crazy_chu
/// @date		2008-6-18
/// 

#include 
#define NTSTRSAFE_LIB
#include 

#ifndef SetFlag
#define SetFlag(_F,_SF)       ((_F) |= (_SF))
#endif
#ifndef ClearFlag
#define ClearFlag(_F,_SF)     ((_F) &= ~(_SF))
#endif
#define CCP_MAX_COM_ID 32

// 使能函数。
void cppSetEnable(BOOLEAN enable);

// 过滤掉所有的irp。对现有的irp
BOOLEAN ccpIrpFilter(PDEVICE_OBJECT device, PIRP irp, NTSTATUS *status);

// 在irp的时候过滤。如果返回TRUE则表示已经处理过的irp.
BOOLEAN ccpFileIrpFilter(
	PDEVICE_OBJECT next_dev,
	PIRP irp,
	PIO_STACK_LOCATION irpsp,
	NTSTATUS *status);

// 卸载的时候调用。可以解除绑定。
void ccpUnload();

// 这个函数在DriverEntry中调用,可以绑定所有的串口。
void ccpAttachAllComs(PDRIVER_OBJECT driver);

enum {
	CCP_IRP_PASS = 0,
	CCP_IRP_COMPLETED = 1,
	CCP_IRP_GO_ON = 2
};

extern int ccpIrpPreCallback(
	PDEVICE_OBJECT device,
	PDEVICE_OBJECT next_dev,
	PIRP irp, ULONG i,
	PVOID *context);

extern void ccpIrpPostCallback(
	PDEVICE_OBJECT device,
	PDEVICE_OBJECT next_dev,
	PIRP irp,
	PIO_STACK_LOCATION irpsp,
	ULONG i,
	PVOID context);

// 过滤设备和真实设备
static PDEVICE_OBJECT s_fltobj[CCP_MAX_COM_ID] = { 0 };
static PDEVICE_OBJECT s_nextobj[CCP_MAX_COM_ID] = { 0 };

// 打开一个端口设备
PDEVICE_OBJECT ccpOpenCom(ULONG id, NTSTATUS *status)
{
	UNICODE_STRING name_str;
	static WCHAR name[32] = { 0 };
	PFILE_OBJECT fileobj = NULL;
	PDEVICE_OBJECT devobj = NULL;

	// 输入字符串。
	memset(name, 0, sizeof(WCHAR)* 32);
	RtlStringCchPrintfW(
		name, 32,
		L"\\Device\\Serial%d", id);
	RtlInitUnicodeString(&name_str, name);

	// 打开设备对象
	*status = IoGetDeviceObjectPointer(&name_str, FILE_ALL_ACCESS, &fileobj, &devobj); 
	//如果文件对象打开了,一定要对文件对象解除引用
	if (*status == STATUS_SUCCESS)
		ObDereferenceObject(fileobj);

	return devobj;
}

NTSTATUS
ccpAttachDevice(
PDRIVER_OBJECT driver,
PDEVICE_OBJECT oldobj,
PDEVICE_OBJECT *fltobj,
PDEVICE_OBJECT *next)
{
	NTSTATUS status;
	PDEVICE_OBJECT topdev = NULL;

	// 生成虚拟设备,然后绑定之。
	status = IoCreateDevice(driver,
		0,
		NULL,
		oldobj->DeviceType,
		0,
		FALSE,
		fltobj);

	if (status != STATUS_SUCCESS)
		return status;

	// 拷贝重要标志位。
	if (oldobj->Flags & DO_BUFFERED_IO)
		(*fltobj)->Flags |= DO_BUFFERED_IO;
	if (oldobj->Flags & DO_DIRECT_IO)
		(*fltobj)->Flags |= DO_DIRECT_IO;
	if (oldobj->Flags & DO_BUFFERED_IO)
		(*fltobj)->Flags |= DO_BUFFERED_IO;
	if (oldobj->Characteristics & FILE_DEVICE_SECURE_OPEN)
		(*fltobj)->Characteristics |= FILE_DEVICE_SECURE_OPEN;
	(*fltobj)->Flags |= DO_POWER_PAGABLE;
	// 绑定一个设备到另一个设备上
	topdev = IoAttachDeviceToDeviceStack(*fltobj, oldobj);
	if (topdev == NULL)
	{
		// 如果绑定失败了,销毁设备,重新来过。
		IoDeleteDevice(*fltobj);
		*fltobj = NULL;
		status = STATUS_UNSUCCESSFUL;
		return status;
	}
	*next = topdev;

	// 设置这个设备已经启动。
	(*fltobj)->Flags = (*fltobj)->Flags & ~DO_DEVICE_INITIALIZING;
	return STATUS_SUCCESS;
}

// 这个函数绑定所有的串口。
void ccpAttachAllComs(PDRIVER_OBJECT driver)
{
	ULONG i;
	PDEVICE_OBJECT com_ob;
	NTSTATUS status;
	for (i = 0; iMajorFunction == IRP_MJ_POWER)
			{
				// 直接发送,然后返回说已经被处理了。
				PoStartNextPowerIrp(irp);
				IoSkipCurrentIrpStackLocation(irp);
				return PoCallDriver(s_nextobj[i], irp);
			}
			// 此外我们只过滤写请求。写请求的话,获得缓冲区以及其长度。
			// 然后打印一下。
			if (irpsp->MajorFunction == IRP_MJ_WRITE)
			{
				// 如果是写,先获得长度
				ULONG len = irpsp->Parameters.Write.Length;
				// 然后获得缓冲区
				PUCHAR buf = NULL;
				if (irp->MdlAddress != NULL)
					buf =
					(PUCHAR)
					MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
				else
					buf = (PUCHAR)irp->UserBuffer;
				if (buf == NULL)
					buf = (PUCHAR)irp->AssociatedIrp.SystemBuffer;

				// 打印内容
				for (j = 0; jIoStatus.Information = 0;
	irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
	IoCompleteRequest(irp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
	DbgPrint("start driver_test5");

	size_t i;
	// 所有的分发函数都设置成一样的。
	for (i = 0; iMajorFunction[i] = ccpDispatch;
	}

	// 支持动态卸载。
	driver->DriverUnload = ccpUnload;

	// 绑定所有的串口。
	ccpAttachAllComs(driver);

	// 直接返回成功即可。
	return STATUS_SUCCESS;
}






效果验证
由于我没有串口设备,也没使用作者说的超级终端,所以我在虚拟机中安装了串口调试助手sscom5.13.1.exe(此前我的虚拟机已经搭建好双机调试环境,可以在虚拟机中的串口调试助手看见串口)。如果在串口助手中发送数据,则在debugView中可以捕获相关打印,如下图

windows下串口过滤_第2张图片

你可能感兴趣的:(Windows系统编程)