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~

     
  • 相关阅读:
    js中的原生Ajax和JQuery中的Ajax
    this的用法
    static的特性
    时政20180807
    java compiler没有1.8怎么办
    Description Resource Path Location Type Java compiler level does not match the version of the installed Java project facet Unknown Faceted Project Problem (Java Version Mismatch)
    分词器
    [数算]有一个工程甲、乙、丙单独做,分别要48天、72天、96天完成
    一点感想
    解析Excel文件 Apache POI框架使用
  • 原文地址:https://www.cnblogs.com/Joy7/p/3330399.html
Copyright © 2011-2022 走看看