zoukankan      html  css  js  c++  java
  • 内核知识第七讲,内核中设备常用的三种通信方式,以及控制回调的编写

            内核知识第七讲,内核中设备常用的三种通信方式,以及控制回调的编写

    一丶ring3和ring0下的三种通讯方式

    ring3和ring0下有常用三种通信方式:

    1.缓冲区通信方式

    2.直接IO通信方式

    3.其它通信方式

    缓冲区通信方式

    我们的ring3和ring0通讯的时候.ring3会给一个虚拟地址. 然后内核中的参数会通过IRP来获取.

    其中有个缓冲区. 我们只要操作这个缓冲区.那么对应的就是操作了三环的缓冲区.

    例如:

      

    当我们三环和0环通信的时候, 3环如果选择的是缓冲区通信. 那么久类似于上图.  操作系统会在高2G申请一个额外的缓冲区.

    然后ring3下的缓冲区拷贝到里面. 然后我们的内核程序操作这个缓冲区之后. 操作系统将这个缓冲区的数据重新写入到ring3下的虚拟缓冲区中.

    优点:

      优点是安全.操作系统会创建一个中间层的缓冲区让我们进行操作.然后操作中间层就相当于操作ring3的缓冲区.

    缺点:

      高2G内核中的内存是很宝贵的.如果我们交互的时候.传出的数据太大.那么就会消耗计算机内存资源.

    如果想看完整流程图,请查看WDK的帮助文档.

    2.直接IO通信方式

      为什么叫做直接通信方式. 原因是 ring3可以直接和ring0进行通讯了.不需要额外的缓冲区进行操作.

    ring3的虚拟内存会通过内存映射的方式.映射到高2G的内存. 然后ring3的虚拟内存进行保护. 这样我们操作ring0的高2G缓冲区.就相当于操作ring3的缓冲区.

    优点:

      如果数据量比较大.可以使用这种

    缺点:

      不安全.如果我们的ring3不进行保护.那么通过C语言进行对ring3缓冲区越界访问.那么就相当于访问ring0的物理内存了.

    不过幸好.内核中提供了宏让我们自己进行操作.

    lpBuff = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);

    需要注意的是我们这种通信方式获取的缓冲区不是 IRP中的 SystemBuf;

    3.其它通信方式

    其它通信方式,这是直接使用用户的虚拟内存,也就是IRP中的 userBuf;

    二丶控制回调的编写

    以前我们操作设备的时候. 都是通过Read或者Write去操作.

    但是现在我们有控制了. 

    这个时候我们要控制设备,就要编写控制码.

    控制码:

      

    CTL_CODE(FILE_DEVICE_UNKNOWN, (CODE_BASE+(code)), METHOD_BUFFERED, FILE_ANY_ACCESS)

    VC++6.0给了一个宏.而NTDDK.h中也有这个. 如果你配置好了环境,那么你就要用VC中提供的了.

    控制码的格式:

      

    设备类型,控制码,通讯方式. 权限.

    如果用我们的上面的宏,则填写即可.内部会自己进行移位运算.

    完整代码:

      

     PIO_STACK_LOCATION pIrpStack = NULL;
      PVOID lpBuff = NULL;
      ULONG IoControlCode;            //获取控制的控制码
      ULONG InputBufferLength;         //用户输入的缓冲区,这个缓冲区一般做参数
      ULONG OutputBufferLength;        //ring0返回出去的缓冲区.一般做写出.
      NTSTATUS status = STATUS_UNSUCCESSFUL;//各种变量.暂时不用管.
      ULONG bytes = 0;
    
      KdBreakPoint();
      
      KdPrint(("[FirstWDK] DispatchControl PID:%d TID:%d
    ", PsGetCurrentProcessId(), PsGetCurrentThreadId()));
    
    
      pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
      InputBufferLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;//获取长度
      OutputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;//获取输出缓冲区
      IoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;//获取控制码
      lpBuff = pIrp->AssociatedIrp.SystemBuffer;
    
      switch(IoControlCode)
      {
      case MYCTL_GET_GDT_SIZE:      //自定义的控制码
        {
          break;
        }
      case MYCTL_GET_GDT:
        {
          PCONTORL_PARAMS pParams = (PCONTORL_PARAMS)lpBuff;
          char szGDT[6];
    
          if (InputBufferLength < sizeof(CONTORL_PARAMS))
            break;
    
          __asm
          {
            sgdt szGDT
          }
          KdPrint(("limit:%p  GDT:%p
    ", *(short*)szGDT, *(int*)(szGDT + 2)));
          if (OutputBufferLength >= sizeof(szGDT))
          {
            RtlCopyMemory(lpBuff, szGDT, sizeof(szGDT));
            bytes = sizeof(szGDT);
            status = STATUS_SUCCESS;
          }
          break;
        }
      case MYCTL_GET_LDT:
        {
          break;
        }
      }
    
     
      
      pIrp->IoStatus.Status = status;
      pIrp->IoStatus.Information = bytes;
      IoCompleteRequest(pIrp, IO_NO_INCREMENT);
      
      return status;
    }

    关于自定义的控制码.

    这些本质来说就是我们的宏替换.

    #define CODE_BASE 0x800
    #define MY_CTL_CODE(code)  CTL_CODE(FILE_DEVICE_UNKNOWN, (CODE_BASE+(code)), METHOD_BUFFERED, FILE_ANY_ACCESS)
    
    #define MYCTL_GET_GDT      MY_CTL_CODE(1)  
    #define MYCTL_GET_GDT_SIZE MY_CTL_CODE(2) 
    #define MYCTL_GET_LDT      MY_CTL_CODE(3) 

    我们每次定义,都要写CTL_CODE.很麻烦.所以我们用心的宏替换一下即可.

    PS:

      当控制码为缓冲区方式,直接方式.以及其它方式的时候.我们分别从IRP中获取的参数缓冲区是不同的.

    1.当我们的控制码给定的是缓冲区通信方式

      如果是缓冲区通信方式,那么获得的就是IRP中的SystemBuf.   这个缓冲区可以当做ring3传递的参数.然后你往这个缓冲区写数据,则是传出的数据

    2.当我们的控制码为直接IO的方式

      如果是直接IO的方式.那么你要二选一. 如果你指定了用户的输入缓冲区为直接IO方式,那么对应的输出缓冲区则是缓冲区方式,

      那么用户缓冲区的获得方式就是使用上面介绍直接方式的API进行获取了.

    例如:

      

    lpBuff = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);

    3.如果我们的控制码为其它方式

      如果是其它方式,那么用户的缓冲区是 IRP中的UserBuf缓冲区.而输入缓冲区则是用IRP中的.Type3InputBuffer

    缓冲区.

  • 相关阅读:
    alt、title和label
    css3-transform
    word break和word wrap
    聊聊svg
    JS严格模式
    JS提前声明和定义方式
    js跨域
    IE7append新的元素自动补充完整路径
    HTML5摇一摇
    基于jQuery仿uploadify的HTML5图片上传控件jquery.html5uploader
  • 原文地址:https://www.cnblogs.com/iBinary/p/8299232.html
Copyright © 2011-2022 走看看