zcc1414

博客园 首页 联系 订阅 管理

除了 读设备和  写设备 外  还可以有一个API DeviceIoControl 操作设备 创建一个IRP_MJ_DEVICE_CONTROL 类型的IRP 

DeviceIoControl

hDevice Long,设备句柄
dwIoControlCode Long,应用程序调用驱动程序的控制命令,就是IOCTL_XXX IOCTLs。
lpInBuffer Any,应用程序传递给驱动程序的数据缓冲区地址。
nInBufferSize Long,应用程序传递给驱动程序的数据缓冲区大小,字节数。
lpOutBuffer Any,驱动程序返回给应用程序的数据缓冲区地址。
nOutBufferSize Long,驱动程序返回给应用程序的数据缓冲区大小,字节数。
lpBytesReturned Long,驱动程序实际返回给应用程序的数据字节数地址。
lpOverlapped OVERLAPPED,这个结构用于重叠操作。针对同步操作,请用ByVal As Long传递零值


应用程序 源码:

头文件:

#ifndef IOCTLS_H
#define IOCTLS_H


#ifndef CTL_CODE
	#pragma message("CTL_CODE undefined. Include winioctl.h or wdm.h")
#endif


#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)


#endif
CPP文件:

#include <windows.h>
#include <stdio.h>
//使用CTL_CODE必须加入winioctl.h
#include <winioctl.h>
#include "..\NT_Driver\Ioctls.h"

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;
	//缓冲内存模式  IOCTL////////////////////////////////////////////////
	bRet = DeviceIoControl(hDevice, IOCTL_TEST1, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);
	//InputBuffer 为输入缓冲区		OutputBuffer为接收的缓冲区
	if (bRet)
	{
		printf("Output buffer:%d bytes\n",dwOutput);
		for (int i=0;i<(int)dwOutput;i++)
		{
			printf("%02X ",OutputBuffer[i]);
		}
		printf("\n");
	}
	//直接内存模式  IOCTL////////////////////////////////////////////////
	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");
	}
	//其他内存模式  IOCTL////////////////////////////////////////////////
 	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;
}
内核模式  显示  应用程序字符串:

#pragma PAGEDCODE
NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;
	KdPrint(("Enter HelloDDKDeviceIOControl\n"));
	//得到当前堆栈
	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)
	{						// process request
		case IOCTL_TEST1:
		{
			KdPrint(("IOCTL_TEST1\n"));
			//缓冲区方式IOCTL
			//显示输入缓冲区数据
 			UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
			for (ULONG i=0;i<cbin;i++)
			{
				KdPrint(("%X\n",InputBuffer[i]));
			}

			//操作输出缓冲区
			UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
			memset(OutputBuffer,0xAA,cbout);
			//设置实际操作输出缓冲区长度
 			info = cbout;
			break;
		}
		case IOCTL_TEST2:
		{
			KdPrint(("IOCTL_TEST2\n"));
			//缓冲区方式IOCTL
			//显示输入缓冲区数据

			//缓冲区方式IOCTL
			//显示输入缓冲区数据
 			UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
			for (ULONG i=0;i<cbin;i++)
			{
				KdPrint(("%X\n",InputBuffer[i]));
			}

			//pIrp->MdlAddress为DeviceIoControl输出缓冲区地址相同
			KdPrint(("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(("IOCTL_TEST3\n"));

			//缓冲区方式IOCTL
			//显示输入缓冲区数据
 			UCHAR* UserInputBuffer = (UCHAR*)stack->Parameters.DeviceIoControl.Type3InputBuffer;
			KdPrint(("UserInputBuffer:0X%0X\n",UserInputBuffer));

			//得到用户模式地址
			PVOID UserOutputBuffer = pIrp->UserBuffer;
			
			KdPrint(("UserOutputBuffer:0X%0X\n",UserOutputBuffer));

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

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

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

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

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

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

 			info = cbout;
			break;
		}

		default:
			status = STATUS_INVALID_VARIANT;
	}

	// 完成IRP
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = info;	// bytes xfered
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );

	KdPrint(("Leave HelloDDKDeviceIOControl\n"));

	return status;
}






posted on 2013-09-07 12:40  zcc1414  阅读(259)  评论(0编辑  收藏  举报