首页
社区
课程
招聘
[分享]串口过滤源码 生成过滤设备并绑定真实串口
发表于: 2017-6-12 06:01 3247

[分享]串口过滤源码 生成过滤设备并绑定真实串口

2017-6-12 06:01
3247

#include <ntddk.h>
#include <ntstrsafe.h>
#define NTSTRSAFE_LIB
#ifndef SetFlag
#define SetFlag(_F,_SF)       ((_F) |= (_SF))
#endif
#ifndef ClearFlag
#define ClearFlag(_F,_SF)     ((_F) &= ~(_SF))
#endif
#define CCP_MAX_COM_ID 32
// 过滤设备和真实设备
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);// 生成过滤设备,然后绑定之。		IoDeleteDevice
	if (status != STATUS_SUCCESS)
		return status;
	if (oldobj->Flags & DO_BUFFERED_IO)//串口的驱动对象 检测是否有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);	// 绑定一个设备到另一个设备上  过滤设备 串口设备 返回最后被绑定的设备  IoDetachDevice
	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; i < CCP_MAX_COM_ID; i++)
	{
		com_ob = ccpOpenCom(i, &status);// 获得object引用。   打开一个端口设备  遍历从名字获取驱动对象指针 获取串口设备对象
		if (com_ob == NULL)
			continue;
		ccpAttachDevice(driver, com_ob, &s_fltobj[i], &s_nextobj[i]);// 在这里绑定。并不管绑定是否成功。 得到真实设备
		// 取消object引用。
	}
}
#define  DELAY_ONE_MICROSECOND  (-10)
#define  DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
#define  DELAY_ONE_SECOND (DELAY_ONE_MILLISECOND*1000)
void ccpUnload(PDRIVER_OBJECT drv)
{
	ULONG i;
	LARGE_INTEGER interval;
	// 首先解除绑定
	for (i = 0; i < CCP_MAX_COM_ID; i++)//32
	{
		if (s_nextobj[i] != NULL)
			IoDetachDevice(s_nextobj[i]);//真实的32设备解除绑定  解除的是真实设备
	}
	// 睡眠5秒。等待所有irp处理结束
	interval.QuadPart = (5 * 1000 * DELAY_ONE_MILLISECOND);//-10000  这里的负数表示的是相对时间,正数拒说表示绝对时间,我没试出效果。单位是100nm,此处乘以10000是让单位变为s,传入的单位是ms; 
	KeDelayExecutionThread(KernelMode, FALSE, &interval);//睡眠5秒
	// 删除这些设备
	for (i = 0; i < CCP_MAX_COM_ID; i++)
	{
		if (s_fltobj[i] != NULL)
			IoDeleteDevice(s_fltobj[i]);//创建的是过滤设备
	}
}
NTSTATUS ccpDispatch(PDEVICE_OBJECT device, PIRP irp)//所有的28个历程都进入到这里来了  处理所有串口的写入请求
{
	PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);//返回调用者在指定IRP中的I/O栈位置 得到数据包
	NTSTATUS status;
	ULONG i, j;
	for (i = 0; i < CCP_MAX_COM_ID; i++)// 首先得知道发送给了哪个设备。设备一共最多CCP_MAX_COM_ID 32 个,是前面的代码保存好的,都在s_fltobj中。
	{
		if (s_fltobj[i] == device)  // 过滤设备通过原始串口生成的   设备对象指针 自己定义的过滤设备等于进来的设备 com1
		{
			if (irpsp->MajorFunction == 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);//缓冲区   irp->MdlAddress是用户地址映射  转换成了内核地址
				else
					buf = (PUCHAR)irp->UserBuffer;//缓冲区 最效率 内核进程已经切换访问就结束 跳到其它进程空间了
				if (buf == NULL)
					buf = (PUCHAR)irp->AssociatedIrp.SystemBuffer;//缓冲区 比较简单不追求效率
				// 打印内容
				for (j = 0; j < len; ++j)//缓冲区多长
				{
					DbgPrint("comcap: Send Data: %2x\r\n",	buf[j]);
				}
			}
			IoSkipCurrentIrpStackLocation(irp);	// 这些请求直接下发执行即可。我们并不禁止或者改变它  跳过当前栈空间
			return IoCallDriver(s_nextobj[i], irp);//把这个请求发送给真实设备
		}
	}
	// 如果根本就不在被绑定的设备中,那是有问题的,直接返回参数错误。
	irp->IoStatus.Information = 0;//驱动程序操作应用程序提供的缓冲区的字节数  
	irp->IoStatus.Status = STATUS_INVALID_PARAMETER;//无效
	IoCompleteRequest(irp, IO_NO_INCREMENT);  //设置irp已经完成不用传给其它东西了 irp不需要再设备栈上滚动了 不需要流动了   完成请求
	return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
	size_t i;
	for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)//28个历程 	// 所有的分发函数都设置成一样的。
	{
		driver->MajorFunction[i] = ccpDispatch; //处理所有串口的写入请求
	}
	driver->DriverUnload = ccpUnload;// 支持动态卸载。
	ccpAttachAllComs(driver);// 绑定所有的串口 得到真是的设备
	return STATUS_SUCCESS;	// 直接返回成功即可。
}

xp下用超级终端 就可以与串口进行通信了 我选得是com1串口 在虚拟机里可行  源代码分享给大家学习



QQ群582865430 过游戏驱动保护 研究 修改内核 写外挂 交流


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2018-8-17 16:46 被神大蛇编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 3739
活跃值: (3877)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
这是已经有的现成代码吧!
2017-6-12 15:34
0
游客
登录 | 注册 方可回帖
返回
//