驱动开发笔记4—串口的过滤


串口的过滤很简单,在安全开发中意义也不大,只是作为学习,为之后的键盘过滤和文件系统过滤等打基础。

串口

串口是Windows中的一种设备,它比较简单,且有固定名字。第一个串口名为"\Device\Serial0",第二个为"\Device\Serial1",以此类推。

过滤

过滤: 在不影响上层和下层接口的情况下,在Windows系统内核中加入新的层,从而不需要修改上层的软件或者下层的真实驱动程序,就加入了新的功能。

实现过滤: 首先生成一个过滤设备(虚拟的设备对象),将其绑定在一个真实的设备上。一旦绑定,则原本操作系统要发送给真实设备的请求,会先发送到过滤设备上,我们可以通过分析请求来提前捕获到数据。

生成过滤设备对象

函数IoCreateDevice用于创建设备对象。

NTSTATUS
IoCreateDevice(
    IN PDRIVER_OBJECT DriverObject,		// 驱动对象
    IN ULONG DeviceExtensionSize,		// 设备扩展,0
    IN PUNICODE_STRING DeviceName,		// 设备名称,过滤设备不需要,NULL
    IN DEVICE_TYPE DeviceType,			// 设备类型,要与被绑定设备一致
    IN ULONG DeviceCharacteristics,		// 设备特征,0
    IN BOOLEAN Exclusive,				// FALSE
    OUT PDEVICE_OBJECT *DeviceObject);	// 生成的设备对象

获得目标设备对象

在已知设备名的情况下,可以用IoGetDeviceObjectPointer函数。

在得到设备对象的同时,还会得到一个文件对象,注意之后必须把这个文件对象解引用,否则会引起内存泄露。

NTSTATUS
IoGetDeviceObjectPointer(
    IN PUNICODE_STRING ObjectName,      // 设备名
    IN ACCESS_MASK DesiredAccess,       // 访问权限
    OUT PFILE_OBJECT *FileObject,       // 文件对象
    OUT PDEVICE_OBJECT *DeviceObject);	// 设备对象

绑定设备

Windows提供了一系列内核API来实现设备绑定。

1. IoAttachDevice

Windows中许多设备对象都是有名字的,但不是所有的都有,只有有名字的设备,才能用IoAttachDevice绑定。

如果一个设备已经被其他设备绑定了,则它们会形成一个设备栈。这时IoAttachDevice会绑定设备栈最顶层的那个设备。

NTSTATUS
IoAttachDevice(
    IN PDEVICE_OBJECT SourceDevice,			// 过滤设备对象
	IN PUNICODE_STRING TargetDeviceName,	// 目标设备名
	OUT PDEVICE_OBJECT *AttachedDevice);	// 被绑定的设备对象

2. IoAttachDeviceToDeviceStackSafe

对于没有名字的设备,可以用IoAttachDeviceToDeviceStackSafe绑定,它也是绑定设备栈最顶层的那个设备。

NTSTATUS
IoAttachDeviceToDeviceStackSafe(
	IN PDEVICE_OBJECT SourceDevice,		// 过滤设备对象
	IN PDEVICE_OBJECT TargetDevice,		// 要绑定的设备对象
    IN OUT PDEVICE_OBJECT *AttachedToDeviceObject);	// 最终被绑定的设备对象

注意在设备绑定时,要把过滤设备对象的多个子域设置成和目标一致,包括标志和特征。

串口的过滤

创建过滤设备并绑定到串口上之后,当操作系统要发送IRP请求到串口上时,会先发送到我们的过滤设备上,我们可以对其进行过滤处理。

IRP有很多种类,常见的有读请求(IRP_MJ_READ)和写请求(IRP_MJ_WRITE)等。

过滤处理的结果有三种:

  • 允许请求通过:过滤设备只是简单获取一下请求的信息,不对其做任何处理,请求正常下发。
  • 禁止请求通过:该请求结束,并返回错误,应用程序会受到失败的信息。
  • 完成请求:该请求结束,并返回成功。

测试代码

#include "Ring0.h"
#include <ntstrsafe.h>

PDEVICE_OBJECT FltDevices[32] = {
    
     0 };
PDEVICE_OBJECT AttachedDevices[32] = {
    
     0 };

NTSTATUS
OpenDevice(ULONG Index, PDEVICE_OBJECT *DeviceObject)
{
    
    
	NTSTATUS Status = STATUS_UNSUCCESSFUL;
	PFILE_OBJECT FileObject = NULL;
	UNICODE_STRING DeviceName;
	WCHAR Name[32] = {
    
     0 };

	RtlStringCchPrintfW(Name, 32, L"\\Device\\Serial%d", Index);
	RtlInitUnicodeString(&DeviceName, Name);
	Status = IoGetDeviceObjectPointer(&DeviceName,
		FILE_ALL_ACCESS,
		&FileObject,
		DeviceObject);
	if (!NT_SUCCESS(Status))
	{
    
    
		return Status;
	}
	ObDereferenceObject(FileObject);
	return Status;
}

NTSTATUS
AttachDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT TargetDevice,
	PDEVICE_OBJECT *FltDevice, PDEVICE_OBJECT *AttachedDevice)
{
    
    
	NTSTATUS Status = STATUS_UNSUCCESSFUL;

	// 创建过滤设备
	Status = IoCreateDevice(DriverObject,
		0,
		NULL,
		TargetDevice->DeviceType,
		0,
		FALSE,
		FltDevice);
	if (!NT_SUCCESS(Status))
	{
    
    
		return Status;
	}

	// 设置重要标志位
	if (TargetDevice->Flags & DO_BUFFERED_IO)
	{
    
    
		(*FltDevice)->Flags |= DO_BUFFERED_IO;
	}
	if (TargetDevice->Flags & DO_DIRECT_IO)
	{
    
    
		(*FltDevice)->Flags |= DO_DIRECT_IO;
	}
	if (TargetDevice->Characteristics & FILE_DEVICE_SECURE_OPEN)
	{
    
    
		(*FltDevice)->Characteristics |= FILE_DEVICE_SECURE_OPEN;
	}
	(*FltDevice)->Flags |= DO_POWER_PAGABLE;

	// 绑定设备
	Status = IoAttachDeviceToDeviceStackSafe(*FltDevice,
		TargetDevice,
		AttachedDevice);
	if (!NT_SUCCESS(Status))
	{
    
    
		return Status;
	}

	// 设置设备已启动
	(*FltDevice)->Flags &= DO_DEVICE_INITIALIZING;
	return Status;
}

NTSTATUS 
ControlThroughDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    
    
	PIO_STACK_LOCATION IoStackLocation;     //当前IRP调用栈空间

	//获得当前IRP的栈空间(即本层设备对应的IO_STACK_LOCATION)
	IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
	for (ULONG i = 0; i < 32; i++)
	{
    
    
		if (FltDevices[i] == DeviceObject)
		{
    
    
			// 所有的电源操作,全部直接放过
			if (IoStackLocation->MajorFunction == IRP_MJ_POWER)
			{
    
    
				// 直接发送,然后返回说已经被处理了
				PoStartNextPowerIrp(Irp);
				IoSkipCurrentIrpStackLocation(Irp);
				return PoCallDriver(AttachedDevices[i], Irp);
			}
			// 写请求
			if (IoStackLocation->MajorFunction == IRP_MJ_WRITE)
			{
    
    
				ULONG Length = IoStackLocation->Parameters.Write.Length;
				PUCHAR Buffer = NULL;
				if (Irp->MdlAddress != NULL)
				{
    
    
					Buffer = (PUCHAR)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
				}
				else
				{
    
    
					Buffer = (PUCHAR)Irp->UserBuffer;
				}
				if (Buffer == NULL)
				{
    
    
					Buffer = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
				}
				for (ULONG j = 0; j < Length; j++)
				{
    
    
					DbgPrint("comcap: Send Data: %2x\r\n", Buffer[j]);
				}
			}
			// 直接下发请求
			IoSkipCurrentIrpStackLocation(Irp);
			return IoCallDriver(AttachedDevices[i], Irp);
		}

	}
	//构造数据包,发到用户层
	Irp->IoStatus.Status = 0;
	Irp->IoStatus.Information = STATUS_INVALID_PARAMETER;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	return STATUS_SUCCESS;
}

NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
    
    
	// 解引用
	UNREFERENCED_PARAMETER(RegisterPath);
	NTSTATUS Status = STATUS_SUCCESS;
	PDEVICE_OBJECT TargetDevice = NULL;
	UNICODE_STRING ObjectName;

	// 绑定所有串口,假定一共有32个串口
	for (ULONG i = 0; i < 32; i++)
	{
    
    
		Status = OpenDevice(i, &TargetDevice);
		if (!NT_SUCCESS(Status) || TargetDevice == NULL)
		{
    
    
			continue;
		}
		AttachDevice(DriverObject, TargetDevice, &FltDevices[i], &AttachedDevices[i]);
	}

	// 设置派遣函数例程
	for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
	{
    
    
		DriverObject->MajorFunction[i] = ControlThroughDispatch;
	}

	// 设置驱动卸载例程
	DriverObject->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}


void DriverUnload(PDRIVER_OBJECT DriverObject)
{
    
    
	UNREFERENCED_PARAMETER(DriverObject);
	// 解除绑定
	for (ULONG i = 0; i < 32; i++)
	{
    
    
		if (AttachedDevices[i] != NULL)
		{
    
    
			IoDetachDevice(AttachedDevices[i]);
		}
	}
#define DELAY_ONE_MICROSECOND	(-10)
#define DELAY_ONE_MILLISECOND	(DELAY_ONE_MICROSECOND * 1000)
#define DELAY_ONE_SECOND		(DELAY_ONE_MILLISECOND * 1000)
	// 睡眠5秒,等待所有的IRP处理结束
	LARGE_INTEGER Interval;
	Interval.QuadPart = (5000 * DELAY_ONE_MILLISECOND);
	KeDelayExecutionThread(KernelMode, FALSE, &Interval);
	// 删除过滤设备
	for (ULONG i = 0; i < 32; i++)
	{
    
    
		if (FltDevices[i] != NULL)
		{
    
    
			IoDeleteDevice(FltDevices[i]);
		}
	}

}

猜你喜欢

转载自blog.csdn.net/qq_42814021/article/details/121000220