zoukankan      html  css  js  c++  java
  • 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
    ");
    36 
    37     if (hDevice == INVALID_HANDLE_VALUE)
    38     {
    39         printf("获取驱动句柄失败: %s with Win32 error code: %d
    ","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 
    ",a,b,r);
    47     getchar();
    48     CloseHandle(hDevice);
    49     return 0;
    50 }

    .h

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

     

    sys驱动层核心代码:

    #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
    "));
    			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 
    "));
    					//缓冲区方式IOCTL
    					//获取缓冲区数据	a,b		
    					int * InputBuffer = (int*)pIrp->AssociatedIrp.SystemBuffer;
    
    
    
    
    					//KdPrint(("%d,%d
    ",cbin,cbout));
    
    					_asm
    					{
    						mov eax,InputBuffer
    							mov ebx,[eax]
    						mov a,ebx
    							mov ebx,[eax+4]
    						mov b,ebx
    					}
    					KdPrint(("a=%d,b=%d 
    ", 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 
    ",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(("离开派遣函数
    "));//调试信息
    	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
    "));
    			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 
    "));
    					//缓冲区方式IOCTL
    					//获取缓冲区数据	a,b		
    					int * InputBuffer = (int*)pIrp->AssociatedIrp.SystemBuffer;
    
    					//KdPrint(("%d,%d
    ",cbin,cbout));
    
    					_asm
    					{
    						mov eax,InputBuffer
    							mov ebx,[eax]
    						mov a,ebx
    							mov ebx,[eax+4]
    						mov b,ebx
    					}
    					KdPrint(("a=%d,b=%d 
    ", 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 
    ",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(("离开派遣函数
    "));//调试信息
    	return STATUS_SUCCESS; //返回成功
    }
    

    两者不同的地方:

    1) 定义CTL_CODE宏时的method参数,

      direct mode(直接方式)是METHOD_IN_DIRECT,

      buffered mode(缓冲区方式)是METHOD_BUFFERED.

      当然,exe和sys都需要修改。

    2)在操作输出缓冲区的时候,

      //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~

     
  • 相关阅读:
    【原】iOS学习之XML与JSON两种数据结构比较和各自底层实现
    ios 10 访问设置问题
    蛇形输出
    苹果内购流程详解
    iOS多线程比较
    App iCON 尺寸
    学习网站
    c++ lesson 一(命名空间输入输出)
    iOS中WebSocket的使用
    MAC TXT文本
  • 原文地址:https://www.cnblogs.com/Joy7/p/3330399.html
Copyright © 2011-2022 走看看