DeviceIoControl方式 sys和exe通訊

 
 
常識:
IRP:I/O Request Package  即輸入輸出請求包
exe和sys通訊時,exe會發出I/O請求。操做系統會將I/O請求轉化爲相應的IRP數據,
不一樣類型傳遞到不一樣的dispatch function
 
過程:
DeviceIoControl函數產生IRP_MJ_DEVICE_CONTROL 派遣例程
DeviceIoControl函數是用來向指定設備發送控制碼,當指定的 設備接收到DeviceIoControl函數發來的控制碼後
會調用IRP_MJ_DEVICE_CONTROL對應的派遣例程,針對不一樣的控制碼進行處理。
 
BOOL DeviceIoControl(  HANDLE hDevice,              // handle to device
  DWORD dwIoControlCode,       // operation control code
  LPVOID lpInBuffer,           // input data buffer
  DWORD nInBufferSize,         // size of input data buffer
  LPVOID lpOutBuffer,          // output data buffer
  DWORD nOutBufferSize,        // size of output data buffer
  LPDWORD lpBytesReturned,     // byte count
  LPOVERLAPPED lpOverlapped    // overlapped information);
 
 
 
直接內存模式IOCTL:
DDK中有CTL_CODE定義,應用層中沒有CTL_CODE定義
即驅動程序中使用CTL_CODE須要只須要包含ntddk.h頭文件,
而在應用程序中須要包含winioctl.h頭文件
 
#define CTL_CODE(DeviceType, Function, Method, Access)  直接看 MSDN
DeviceType應和IoCreateDevice的類型相匹配。形如:FILE_DEVICE_XX的宏
Function:這是驅動程序定義的IOCTL碼,0x800到0xFFFF由程序猿本身定義
mothod參數:應該指定METHOD_IN_DIRECT
 
效果:一樣能夠避免驅動程序訪問用戶模式的內存地址。
 
例如:
#define add_code CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_IN_DIRECT,FILE_ANY_ACCESS)
 
Direct Mode:
exe應用層代碼:
cpp
 1 // test_exe.cpp : Defines the entry point for the console application.
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <windows.h>
 6 #include "ctl_code.h"
 7 
 8 int add(HANDLE hDevice, int a,int b)
 9 {
10     
11     int port[2];
12     int bufret;
13     ULONG dwWrite;
14     port[0]=a;
15     port[1]=b;
16     
17     DeviceIoControl(hDevice, add_code , &port, 8, &bufret, 4, &dwWrite, NULL);
18     return bufret;
19     
20 }
21 
22 int main(int argc, char* argv[])
23 {
24 
25     //CreateFile 打開設備 獲取hDevice
26     HANDLE hDevice = 
27         CreateFile("\\\\.\\Templet", //\\??\\My_DriverLinkName
28         GENERIC_READ | GENERIC_WRITE,
29         0,        // share mode none
30         NULL,    // no security
31         OPEN_EXISTING,
32         FILE_ATTRIBUTE_NORMAL,
33         NULL );        // no template
34 
35     printf("start\n");
36 
37     if (hDevice == INVALID_HANDLE_VALUE)
38     {
39         printf("獲取驅動句柄失敗: %s with Win32 error code: %d\n","MyDriver", GetLastError() );
40         getchar();
41         return -1;
42     }
43     int a=11;
44     int b=33;
45     int r=add(hDevice,a,b);
46     printf("%d+%d=%d \n",a,b,r);
47     getchar();
48     CloseHandle(hDevice);
49     return 0;
50 }

 

.hwindows

#define add_code CTL_CODE(FILE_DEVICE_UNKNOWN, 	0x800, 	METHOD_IN_DIRECT,FILE_ANY_ACCESS)

 

sys驅動層核心代碼:app

#pragma code_seg("PAGE")
NTSTATUS DispatchRoutine_DeviceIoControl(IN PDEVICE_OBJECT pDevobj,IN PIRP pIrp	)
{   //
	ULONG info;
	//獲得當前棧指針
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	ULONG mf=stack->MajorFunction;//區分IRP
	switch (mf)
	{
	case IRP_MJ_DEVICE_CONTROL:
		{ 
			KdPrint(("Enter myDriver_DeviceIOControl\n"));
			NTSTATUS status = STATUS_SUCCESS;	

			//獲得輸入緩衝區大小
			ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
			//獲得輸出緩衝區大小
			ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
			//獲得IOCTL碼
			ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
			switch (code)
			{ 
			case add_code:
				{  		
					int a,b;
					KdPrint(("add_code Direct Mode \n"));
					//緩衝區方式IOCTL
					//獲取緩衝區數據	a,b		
					int * InputBuffer = (int*)pIrp->AssociatedIrp.SystemBuffer;




					//KdPrint(("%d,%d\n",cbin,cbout));

					_asm
					{
						mov eax,InputBuffer
							mov ebx,[eax]
						mov a,ebx
							mov ebx,[eax+4]
						mov b,ebx
					}
					KdPrint(("a=%d,b=%d \n", a,b));

					a=a+b;
					//C、驅動層返回數據至用戶層
					//操做輸出緩衝區
					//int* OutputBuffer = (int*)pIrp->AssociatedIrp.SystemBuffer;

					UCHAR* OutputBuffer =(UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
					KdPrint(("MmGetSystemAddressForMdlSafe=%x",OutputBuffer));
					_asm
					{
						mov eax,a
							mov ebx,OutputBuffer
							mov [ebx],eax //bufferet=a+b

					}
					KdPrint(("a+b=%d \n",a));

					//設置實際操做輸出緩衝區長度
					info = cbout;
					break;
				}
			case sub_code:
				{
					break;
				}
			}//end code switch
			break;
		}
	case IRP_MJ_CREATE:
		{
			break;
		}
	case IRP_MJ_CLOSE:
		{
			break;
		}
	case IRP_MJ_READ:
		{
			break;
		}

	}

	//對相應的IPR進行處理
	pIrp->IoStatus.Information = info;//設置操做的字節數
	pIrp->IoStatus.Status=STATUS_SUCCESS;//返回成功
	IoCompleteRequest(pIrp,IO_NO_INCREMENT);//指示完成此IRP
	KdPrint(("離開派遣函數\n"));//調試信息
	return STATUS_SUCCESS; //返回成功
}

 

緩衝區內存模式IOCTL函數

強調下:在驅動中最好不要直接訪問用戶模式下的內存地址,緩衝區方式能夠避免程序猿訪問內存模式下的內存地址。測試

#pragma code_seg("PAGE")
NTSTATUS DispatchRoutine_DeviceIoControl(IN PDEVICE_OBJECT pDevobj,IN PIRP pIrp	)
{   //
	ULONG info;
	//獲得當前堆棧
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	ULONG mf=stack->MajorFunction;//區分IRP
	switch (mf)
	{
	case IRP_MJ_DEVICE_CONTROL:
		{ 
			KdPrint(("Enter myDriver_DeviceIOControl\n"));
			NTSTATUS status = STATUS_SUCCESS;	

			//獲得輸入緩衝區大小
			ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
			//獲得輸出緩衝區大小
			ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
			//獲得IOCTL碼
			ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
			switch (code)
			{ 
			case add_code:
				{  		
					int a,b;
					KdPrint(("add_code Buffered Mode \n"));
					//緩衝區方式IOCTL
					//獲取緩衝區數據	a,b		
					int * InputBuffer = (int*)pIrp->AssociatedIrp.SystemBuffer;

					//KdPrint(("%d,%d\n",cbin,cbout));

					_asm
					{
						mov eax,InputBuffer
							mov ebx,[eax]
						mov a,ebx
							mov ebx,[eax+4]
						mov b,ebx
					}
					KdPrint(("a=%d,b=%d \n", a,b));

					a=a+b;
					//C、驅動層返回數據至用戶層

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

					//Direct Mode
					//UCHAR* OutputBuffer =(UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
					KdPrint(("MmGetSystemAddressForMdlSafe=%x",OutputBuffer));
					_asm
					{
						mov eax,a
							mov ebx,OutputBuffer
							mov [ebx],eax //bufferet=a+b

					}
					KdPrint(("a+b=%d \n",a));

					//設置實際操做輸出緩衝區長度
					info = cbout;
					break;
				}
			case sub_code:
				{
					break;
				}
			default:
				status = STATUS_INVALID_VARIANT; //其餘的控制碼
			}//end code switch
		}
	case IRP_MJ_CREATE:
		{
			break;
		}
	case IRP_MJ_CLOSE:
		{
			break;
		}
	case IRP_MJ_READ:
		{
			break;
		}

	}

	//對相應的IPR進行處理
	pIrp->IoStatus.Information = info;//設置操做的字節數
	pIrp->IoStatus.Status=STATUS_SUCCESS;//返回成功
	IoCompleteRequest(pIrp,IO_NO_INCREMENT);//指示完成此IRP
	KdPrint(("離開派遣函數\n"));//調試信息
	return STATUS_SUCCESS; //返回成功
}

 

二者不一樣的地方:spa

1) 定義CTL_CODE宏時的method參數,操作系統

  direct mode(直接方式)是METHOD_IN_DIRECT,指針

  buffered mode(緩衝區方式)是METHOD_BUFFERED.調試

  固然,exe和sys都須要修改。code

2)在操做輸出緩衝區的時候,orm

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

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

  

IDE:VS2010+WDK   VC++6.0

測試環境:XP SP3

最後固然是保證可以不藍屏,可以輸出correct。

over~

相關文章
相關標籤/搜索