deviceiocontrol true什么意思_device driver service

deviceiocontrol true什么意思_device driver service与驱动程序通信的函数,除了ReadFile和WriteFile函数还有DeviceIoControl函数,而且DeviceIoControl函数那是相当的彪悍。因为它可以自定义控制码,你只要在IRP_MJ_DEVICE_CONTROL对应的派遣函数中读取控制码,然后针对控制码,你就可以实现自定义的功能了。 函数原型:BOOLWINAPIDeviceIoControl( __

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

与驱动程序通信的函数,除了ReadFile和WriteFile函数还有DeviceIoControl函数,而且DeviceIoControl函数那是相当的彪悍。因为它可以自定义控制码,你只要在IRP_MJ_DEVICE_CONTROL对应的派遣函数中读取控制码,然后针对控制码,你就可以实现自定义的功能了。

 

函数原型:

BOOL WINAPI DeviceIoControl(

 __in         HANDLEhDevice,

 __in         DWORDdwIoControlCode,

 __in_opt     LPVOID lpInBuffer,

 __in         DWORDnInBufferSize,

 __out_opt    LPVOID lpOutBuffer,

 __in         DWORDnOutBufferSize,

 __out_opt    LPDWORD lpBytesReturned,

 __inout_opt  LPOVERLAPPED lpOverlapped

);

 

其中lpBytesReturned的值来自于IRP结构中的pIRP->IoStatus.Information。DeviceIoControl的第二个参数就是控制码,控制码是一个32为无符号整型,需要符合DDK的规定。

控制代码中各数据位字段的含义如下: 
◎ DeviceType–设备类型(31-16bit指 出了设备的类型,微软保留了0-7FFFh的取值,剩下的8000h-0FFFFh   供开发商定义新的内核模式驱动程序。我们可以在\include\w2k\ntddk.inc文件中找到一组FILE_DEVICE_XXX  符号常量,这些值都是微软保留的 值,我们可以使用其中的FILE_DEVICE_UNKNOWN。当然你也可以定义另外一个FILE_DEVICE_XXX值

◎ Access–存取代码(15-14bit指明应用程序存取设备的方式,由于这个字段只有2位,所以只有4种可能性: 

· FILE_ANY_ACCESS (0)–最大的存取权限,就是什么操作都可以 

· FILE_READ_ACCESS (1)–读权限,设备将数据传递到指定的缓冲区 

· FILE_WRITE_ACCESS (2)–写权限,可以从内存中向设备传递数据 

· FILE_READ_ACCESS or FILE_WRITE_ACCESS (3)–读写权限,设备和内存缓冲区之间可以互相传递数据 

◎ Function–功能代码(13-2bit)用来描述要进行的操作,我们可以用800h-0FFFh来定义自己的I/O控制代码,

   0-7FFh之间的值是被微软保留的,用来定义公用的I/O控制代码 

◎ Method–缓冲模式(0-1bit)表示I/O管理器如何对输入和输出的数据进行缓冲,这个字段的长度是2位,所以有

   4种可能性: 

·METHOD_BUFFERED (0)–对I/O进行缓冲 

·METHOD_IN_DIRECT (1)–对输入不进行缓冲 

·METHOD_OUT_DIRECT (2)–对输出不进行缓冲 

·METHOD_NEITHER (3)–都不缓冲 

 

缓冲区模式虽然会损失点性能,但是其安全性好。

 

下面将分别讲述这几种模式。

 

缓冲内存模式(对应代码中的IOCTL_TEST1)

首先要将控制码中的Method设置为METHOD_BUFFERED。

往驱动中Input数据:在Win32 APIDeviceIoControl函数的内部,用户提供的输入缓冲区的内容被复制到IRP的pIRP->AssociatedIrp.SystemBuffer的内存地址,复制的字节是有DeviceControl指定的输入字节数。从驱动中Output数据:派遣函数可以向pIRP->AssociatedIrp.SystemBuffer写入数据,被当做是设备输出的数据。操作系统会将AssociatedIrp.SystemBuffer的数据再次复制到DeviceIoControl提供的输出缓冲区,复制的字节数有pIrp->IoStatus.Information指定,DeviceIoControl也可以通过参数lpBytesReturned得到复制的字节数。       

原理就是这样了,理论上就可以实现读和写的双向操作了。

直接内存模式(对应代码中的IOCTL_TEST2)

首先将Method设置为METHOD_IN_DIRECT 或METHOD_OUT_DIRECT ,这两者的不同只是体现在打开设备的权限上,当以只读权限打开设备时,METHOD_IN_DIRECT 就可以顺利操作,而METHOD_OUT_DIRECT 就会失败。如果以读写权限打开时,两者都可以执行成功。

往驱动中Input数据:这部分和上面的缓冲内存模式一样,输入缓冲区的数据复制到pIrp->AssociateIrp.SystemBuffer内存地址,复制的字节数是按照DeviceIoControl指定的。

从驱动中Output数据:操作系统会为DeviceIoControl指定的输出缓冲区锁定,然后在内核模式地址下重新映射到一段地址。在派遣函数中可以先获取DeviceIoControl指定的输出缓冲区(lpOutBufferb被记录在pIrp->AssociateIrp.SystemBuffer),然后再通过MmGetSystemAddressForMdlSafe获取其在核地址中的映射值。

 

 

 

其他内存模式(对应代码中的IOCTL_TEST3)

个人觉得这种方式挺麻烦的而且少被用到,由于它是直接访问用户模式地址,要求调用DeviceIoControl的线程和派遣函数运行在同一个线程设备上下文中,自己有个印象就行了。

首先将指定的Method参数设置为METHOD_NEITHER。

往驱动中Input数据:通过I/O堆栈的Parameters.DeviceIoControl.Type3InputBuffer得到DeviceIoControl提供的输入缓冲区地址,Parameters.DeviceIoControl.InputBufferLength得到其长度。由于不能保证传递过来的地址合法,所以需要先要结果ProbeRead函数进行判断。

从驱动中Output数据:通过pIrp->UserBuffer得到DeviceIoControl函数提供的输出缓冲区地址,再通过Parameters.DeviceIoControl.OutputBufferLength得到输出缓冲区大小。同样的要用ProbeWrite函数先进行判断。

 

 

 

下面给出一个实例代码,来自于张帆的《Windows驱动开发详解》

 

首先是控制码设置:

#define IOCTL_TEST1 CTL_CODE(\

                        FILE_DEVICE_UNKNOWN, \

                        0x800, \

                        METHOD_BUFFERED, \

                        FILE_ANY_ACCESS)

 

#define IOCTL_TEST2 CTL_CODE(\

                        FILE_DEVICE_UNKNOWN, \

                       0x801, \

                        METHOD_IN_DIRECT, \

                        FILE_ANY_ACCESS)

 

#define IOCTL_TEST3 CTL_CODE(\

                        FILE_DEVICE_UNKNOWN, \

                        0x802, \

                        METHOD_NEITHER, \

                        FILE_ANY_ACCESS)

 

再是IRP_MJ_DEVICE_CONTROL派遣函数:

NTSTATUSIOCTRLDRIVER_DispatchDeviceControl(

       IN PDEVICE_OBJECT              DeviceObject,

       IN PIRP                                pIrp

       )

{

       NTSTATUS status = STATUS_SUCCESS;

 

       PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);

       //得到输入缓冲区大小

       ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;

       //得到输出缓冲区大小

       ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;

       //得到IOCTL码

       ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;

       ULONG info = 0;

       switch(code)

       {

       case IOCTL_TEST1:

                {

                        KdPrint(("zhui:IOCTL_TEST1\n"));

                       

                        UCHAR* InputBuffer =(UCHAR*)pIrp->AssociatedIrp.SystemBuffer;

                        for (ULONGi=0;i<cbin;i++)

                        {

                                KdPrint(("zhui:%X\n",InputBuffer[i]));

                        }

 

                        //操作输出缓冲区

                        UCHAR* OutputBuffer =(UCHAR*)pIrp->AssociatedIrp.SystemBuffer;

                       memset(OutputBuffer,0xAA,cbout);

                        //设置实际操作输出缓冲区长度

                        info = cbout;

                        break;

                }

       case IOCTL_TEST2:

                {

                        KdPrint(("zhui:IOCTL_TEST2\n"));

                       

                        UCHAR* InputBuffer =(UCHAR*)pIrp->AssociatedIrp.SystemBuffer;

                        for (ULONGi=0;i<cbin;i++)

                        {

                               KdPrint(("zhui:%X\n",InputBuffer[i]));

                        }

 

                        //pIrp->MdlAddress为DeviceIoControl输出缓冲区地址相同

                        KdPrint(("zhui:UserAddress:0X%08X\n",MmGetMdlVirtualAddress(pIrp->MdlAddress)));

 

                        UCHAR* OutputBuffer =(UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);

                        //InputBuffer被映射到内核模式下的内存地址,必定在0X80000000-0XFFFFFFFF之间

                       memset(OutputBuffer,0xAA,cbout);

                        //设置实际操作输出缓冲区长度

                        info = cbout;

                        break;

                }

       case IOCTL_TEST3:

                {

                        KdPrint(("zhui:IOCTL_TEST3\n"));

                       

                        UCHAR* UserInputBuffer= (UCHAR*)stack->Parameters.DeviceIoControl.Type3InputBuffer;

                        KdPrint(("zhui:UserInputBuffer:0X%0X\n",UserInputBuffer));

 

                        //得到用户模式地址

                        PVOID UserOutputBuffer= pIrp->UserBuffer;

 

                        KdPrint(("zhui:UserOutputBuffer:0X%0X\n",UserOutputBuffer));

 

                        __try

                        {

                               KdPrint(("zhui:Enter __try block\n"));

 

                                //判断指针是否可读

                               ProbeForRead(UserInputBuffer,cbin,4);

                                //显示输入缓冲区内容

                                for (ULONGi=0;i<cbin;i++)

                                {

                                       KdPrint(("zhui:%X\n",UserInputBuffer[i]));

                                }

 

                                //判断指针是否可写

                               ProbeForWrite(UserOutputBuffer,cbout,4);

 

                                //操作输出缓冲区

                               memset(UserOutputBuffer,0xAA,cbout);

 

                                //由于在上面引发异常,所以以后语句不会被执行!

                                info = cbout;

 

                               KdPrint(("zhui:Leave __try block\n"));

                        }

                       __except(EXCEPTION_EXECUTE_HANDLER)

                        {

                               KdPrint(("zhui:Catch the exception\n"));

                               KdPrint(("zhui:The program will keep going\n"));

                                status =STATUS_UNSUCCESSFUL;

                        }

 

                        info = cbout;

                        break;

                }

       default:

                status =STATUS_INVALID_DEVICE_REQUEST;

                break;

       }

       pIrp->IoStatus.Status = status;

       pIrp->IoStatus.Information = info;

       IoCompleteRequest(pIrp, IO_NO_INCREMENT);

       return status;

}

 

测试的main函数:

int main()

{

       HANDLE hDevice =

               CreateFile("\\\\.\\HelloDDK",

                                       GENERIC_READ | GENERIC_WRITE,

                                        0,              // share mode none

                                       NULL,   // no security

                                       OPEN_EXISTING,

                                       FILE_ATTRIBUTE_NORMAL,

                                        NULL);         // no template

 

       if (hDevice == INVALID_HANDLE_VALUE)

       {

                printf("Failed to obtainfile handle to device: "

                        "%s with Win32error code: %d\n",

                       "MyWDMDevice", GetLastError() );

                return 1;

       }

 

       UCHAR InputBuffer[10];

       UCHAR OutputBuffer[10];

       //将输入缓冲区全部置成0XBB

       memset(InputBuffer,0xBB,10);

       DWORD dwOutput;

       //输入缓冲区作为输入,输出缓冲区作为输出

 

       BOOL bRet;

       bRet = DeviceIoControl(hDevice, IOCTL_TEST1, InputBuffer, 10,&OutputBuffer, 10, &dwOutput, NULL);

       if (bRet)

       {

                printf("Output buffer:%dbytes\n",dwOutput);

                for (inti=0;i<(int)dwOutput;i++)

                {

                        printf("%02X",OutputBuffer[i]);

                }

                printf("\n");

       }

 

       bRet = DeviceIoControl(hDevice, IOCTL_TEST2, InputBuffer, 10,&OutputBuffer, 10, &dwOutput, NULL);

       if (bRet)

       {

                printf("Output buffer:%dbytes\n",dwOutput);

                for (inti=0;i<(int)dwOutput;i++)

                {

                        printf("%02X",OutputBuffer[i]);

                }

               printf("\n");

       }

 

       bRet = DeviceIoControl(hDevice, IOCTL_TEST3, InputBuffer, 10,&OutputBuffer, 10, &dwOutput, NULL);

       if (bRet)

       {

                printf("Output buffer:%dbytes\n",dwOutput);

                for (int i=0;i<(int)dwOutput;i++)

                {

                        printf("%02X",OutputBuffer[i]);

                }

                printf("\n");

       }

 

       CloseHandle(hDevice);

 

       return 0;

}


首先是控制码设置:

#define IOCTL_TEST1 CTL_CODE(\
			FILE_DEVICE_UNKNOWN, \
			0x800, \
			METHOD_BUFFERED, \
			FILE_ANY_ACCESS)

#define IOCTL_TEST2 CTL_CODE(\
			FILE_DEVICE_UNKNOWN, \
			0x801, \
			METHOD_IN_DIRECT, \
			FILE_ANY_ACCESS)

#define IOCTL_TEST3 CTL_CODE(\
			FILE_DEVICE_UNKNOWN, \
			0x802, \
			METHOD_NEITHER, \
			FILE_ANY_ACCESS)

再是IRP_MJ_DEVICE_CONTROL派遣函数:

NTSTATUS IOCTRLDRIVER_DispatchDeviceControl(
	IN PDEVICE_OBJECT		DeviceObject,
	IN PIRP					pIrp
	)
{
	NTSTATUS status = STATUS_SUCCESS;

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	//得到输入缓冲区大小
	ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
	//得到输出缓冲区大小
	ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
	//得到IOCTL码
	ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
	ULONG info = 0;
	switch(code)
	{
	case IOCTL_TEST1:
		{
			KdPrint(("zhui:IOCTL_TEST1\n"));
			
			UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
			for (ULONG i=0;i<cbin;i++)
			{
				KdPrint(("zhui:%X\n",InputBuffer[i]));
			}

			//操作输出缓冲区
			UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
			memset(OutputBuffer,0xAA,cbout);
			//设置实际操作输出缓冲区长度
			info = cbout;
			break;
		}
	case IOCTL_TEST2:
		{
			KdPrint(("zhui:IOCTL_TEST2\n"));
			
			UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
			for (ULONG i=0;i<cbin;i++)
			{
				KdPrint(("zhui:%X\n",InputBuffer[i]));
			}

			//pIrp->MdlAddress为DeviceIoControl输出缓冲区地址相同
			KdPrint(("zhui:User Address:0X%08X\n",MmGetMdlVirtualAddress(pIrp->MdlAddress)));

			UCHAR* OutputBuffer = (UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);
			//InputBuffer被映射到内核模式下的内存地址,必定在0X80000000-0XFFFFFFFF之间
			memset(OutputBuffer,0xAA,cbout);
			//设置实际操作输出缓冲区长度
			info = cbout;
			break;
		}
	case IOCTL_TEST3:
		{
			KdPrint(("zhui:IOCTL_TEST3\n"));
			
			UCHAR* UserInputBuffer = (UCHAR*)stack->Parameters.DeviceIoControl.Type3InputBuffer;
			KdPrint(("zhui:UserInputBuffer:0X%0X\n",UserInputBuffer));

			//得到用户模式地址
			PVOID UserOutputBuffer = pIrp->UserBuffer;

			KdPrint(("zhui:UserOutputBuffer:0X%0X\n",UserOutputBuffer));

			__try
			{
				KdPrint(("zhui:Enter __try block\n"));

				//判断指针是否可读
				ProbeForRead(UserInputBuffer,cbin,4);
				//显示输入缓冲区内容
				for (ULONG i=0;i<cbin;i++)
				{
					KdPrint(("zhui:%X\n",UserInputBuffer[i]));
				}

				//判断指针是否可写
				ProbeForWrite(UserOutputBuffer,cbout,4);

				//操作输出缓冲区
				memset(UserOutputBuffer,0xAA,cbout);

				//由于在上面引发异常,所以以后语句不会被执行!
				info = cbout;

				KdPrint(("zhui:Leave __try block\n"));
			}
			__except(EXCEPTION_EXECUTE_HANDLER)
			{
				KdPrint(("zhui:Catch the exception\n"));
				KdPrint(("zhui:The program will keep going\n"));
				status = STATUS_UNSUCCESSFUL;
			}

			info = cbout;
			break;
		}
	default:
		status = STATUS_INVALID_DEVICE_REQUEST;
		break;
	}
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = info;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return status;
}



测试的main函数:

int main()
{
	HANDLE hDevice = 
		CreateFile("\\\\.\\HelloDDK",
					GENERIC_READ | GENERIC_WRITE,
					0,		// share mode none
					NULL,	// no security
					OPEN_EXISTING,
					FILE_ATTRIBUTE_NORMAL,
					NULL );		// no template

	if (hDevice == INVALID_HANDLE_VALUE)
	{
		printf("Failed to obtain file handle to device: "
			"%s with Win32 error code: %d\n",
			"MyWDMDevice", GetLastError() );
		return 1;
	}

	UCHAR InputBuffer[10];
	UCHAR OutputBuffer[10];
	//将输入缓冲区全部置成0XBB
	memset(InputBuffer,0xBB,10);
	DWORD dwOutput;
	//输入缓冲区作为输入,输出缓冲区作为输出

	BOOL bRet;
	bRet = DeviceIoControl(hDevice, IOCTL_TEST1, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);
	if (bRet)
	{
		printf("Output buffer:%d bytes\n",dwOutput);
		for (int i=0;i<(int)dwOutput;i++)
		{
			printf("%02X ",OutputBuffer[i]);
		}
		printf("\n");
	}

	bRet = DeviceIoControl(hDevice, IOCTL_TEST2, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);
	if (bRet)
	{
		printf("Output buffer:%d bytes\n",dwOutput);
		for (int i=0;i<(int)dwOutput;i++)
		{
			printf("%02X ",OutputBuffer[i]);
		}
		printf("\n");
	}

 	bRet = DeviceIoControl(hDevice, IOCTL_TEST3, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);
	if (bRet)
	{
		printf("Output buffer:%d bytes\n",dwOutput);
		for (int i=0;i<(int)dwOutput;i++)
		{
			printf("%02X ",OutputBuffer[i]);
		}
		printf("\n");
	}

	CloseHandle(hDevice);

	return 0;
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/196412.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • mysql datetime格式化日期(sql 日期格式)

    mysql查询记录如果有时间戳字段时,查看结果不方便,不能即时看到时间戳代表的含义,现提供mysql格式换时间函数,可以方便的看到格式化后的时间。1.DATE_FORMAT()函数用于以不同的格式显示日期/时间数据。DATE_FORMAT(date,format)format参数的格式有%a缩写星期名%b缩写月名%c月,数值%D带有英文前缀的月中的天%d月的天,数值(00-31)%e月的天,数…

  • android系统中toast是什么_Android个人资料简单布局

    android系统中toast是什么_Android个人资料简单布局老规矩,先上效果图吧主要实现了几种常用的方式:1.最基本的Toast系统自带Toast采用的是队列的方式,等当前Toast消失后,下一个Toast才能显示出来;原因是Toast的管理是在队列中,点击一次,就会产生一个新的Toast,要等这个队列中的Toast处理完,这个显示Toast的任务才算结束。 so~我们可以把Toast改成单例模式,没有Toast再新建它,这样也就…

  • 我的世界区块显示_我的世界怎么显示区块线

    我的世界区块显示_我的世界怎么显示区块线我的世界手游区块是一个独特的机制,很多玩家对于区块是什么不太了解,区块显示指令以及区块的产生不是很熟悉,为了帮助到大家,今天小编就为大家带来我的世界手游区块显示指令分享:区块玩法操作详解的内容,希望大家能够喜欢,下面就让我们一起来看看吧!区块相关1.出生点区块在出生点附近的区块是一块围绕世界出生点的区域中的一个区块,只要有玩家在主世界,它就不会被从内存中卸载。这意味着像红石元件和刷怪会继续,甚至所…

  • win7、win10系统JDK环境变量配置

    win7、win10系统JDK环境变量配置jdk环境变量配置共包括三项:JAVA_HOME、CLASSPATH、PATH。配置过程如下:右键点击“我的电脑”(有的系统叫“计算机”、“此电脑”等等),属性—>高级系统设置—>环境变量,在“系统变量”栏下进行以下操作:1.新建变量名:JAVA_HOME变量值:jdk安装路径,如:D:\Java\jdk1.6.0_452.新建变量名:CL…

  • javawebday30(验证码在客户端 用当前时间来请求下一张图片 VerifyCode代码)[通俗易懂]

    javawebday30(验证码在客户端 用当前时间来请求下一张图片 VerifyCode代码)[通俗易懂]页面运行servlet500错误信息tomcat报错卡住可能是因为映射错误即web.xml中的问题405post改成get方法如果出现不支持post提交可能需要修改表单中的提交方式VerifyCode.javapublicclassVerifyCode{privateintw=70;privateinth=35;…

  • 常见的距离计算公式——欧式距离(Euclidean Distance)

    常见的距离计算公式——欧式距离(Euclidean Distance)计算公式二维空间的公式其中,为点与点之间的欧氏距离;为点到原点的欧氏距离。三维空间的公式n维空间的公式

    2022年10月24日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号