IRP

 

IRP

Irp(I/O Resquet Package)即输入输出请求包,其处理机制类似于Ring3下应用程序的消息处理机制。Ring3 根据接收的消息类别进行处理Irp   驱动程序根据接收不同类型的Irp后,进入不同的派遣函数,在派遣函数中IRP得到相应的处理。

IRP的结构比较复杂,现先了解两个基本属性 MajorFuntion  MinorFuntion主类型和子类型,在一个驱动中DriverObject->MajorFunction 是一个数组,主要记录派遣函数的地址,操作系统会根据接收的IRP进入不同的派遣函数中,在派遣函数中还会判断这个IRP属于那种MinorFuntion。

下面代码ring3 下调用了WriteFile ReadFile GetFileSize,会产生3个不同的Irp IRP_MJ_READ  IRP_MJ_WRITE IRP_MJ_QUERY_INFORMATION.

 1 //Load函数 
 2 BOOL LoadNtDriver(char* pDriverName, char* pDriverPath )
 3 {
 4      SC_HANDLE hServiceMgr=NULL;         
 5      SC_HANDLE hServiceDDK=NULL;             
 6      DWORD dwRtn;
 7      __try
 8      {
 9 
10      hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
11      if (hServiceMgr==NULL)
12      {
13          return FALSE;
14      }
15      hServiceDDK = CreateService( hServiceMgr,//SCM管理器句柄 
16          pDriverName, //驱动程序的在注册表中的名字  
17          pDriverName, // 注册表驱动程序的 DisplayName 值  
18          SERVICE_ALL_ACCESS, // 加载驱动程序的访问权限  
19          SERVICE_KERNEL_DRIVER,// 表示加载的服务是驱动程序  
20          SERVICE_DEMAND_START, // 注册表驱动程序的 Start 值  
21          SERVICE_ERROR_IGNORE, // 注册表驱动程序的 ErrorControl 值  
22          pDriverPath, // 注册表驱动程序的 ImagePath 值  
23          NULL,              //要开启服务的 用户组
24          NULL,  //输出验证标签
25          NULL,   //所依赖的服务的名称
26          NULL,   //用户账户名称
27          NULL);  //用户口令
28      if( hServiceDDK == NULL ) 
29      {
30          //可能已经存在了
31         dwRtn=GetLastError();
32         if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS )
33         {
34             //其他错误引起的
35             return FALSE;
36         }
37         hServiceDDK = OpenService( hServiceMgr, pDriverName, SERVICE_ALL_ACCESS );  
38         if( hServiceDDK == NULL )  
39         {
40             //打开失败
41             return FALSE;
42         }
43      }
44      if(!StartService( hServiceDDK, NULL, NULL ))
45      {
46          AfxMessageBox(_T("启动失败"));
47      }
48      }
49      __finally
50      {
51 
52          if(hServiceDDK)
53          {
54              CloseServiceHandle(hServiceDDK);
55          }
56          if(hServiceMgr)
57          {
58              CloseServiceHandle(hServiceMgr);
59          }
60      }
61 return TRUE;
62 
63 }
//驱动卸载函数
BOOL UnloadNtDriver(char* pDriverName)
{
    BOOL bRet = FALSE;
    SC_HANDLE hSCM=NULL;//SCM管理器的句柄,用来存放OpenSCManager的返回值
    SC_HANDLE hService=NULL;//NT驱动程序的服务句柄,用来存放OpenService的返回值
    SERVICE_STATUS SvrSta;
    //二打开SCM管理器
    __try
    {

    hSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );  
    if( hSCM == NULL )  
    {
        //带开SCM管理器失败
        TRACE( "OpenSCManager() Faild %d ! \n", GetLastError() );  
        bRet = FALSE;
        return bRet;
    }  
    else  
    {
        //打开SCM管理器成功
        TRACE( "OpenSCManager() ok ! \n" );  
    }
    //三打开驱动所对应的服务
        hService = OpenService( hSCM, pDriverName, SERVICE_ALL_ACCESS ); 
        if( hService == NULL )  
        {
            return FALSE;
        }

        if( !ControlService( hService, SERVICE_CONTROL_STOP , &SvrSta ) )  
        {  
            TRACE( "用ControlService() 停止驱动程序失败 错误号:%d !\n", GetLastError() );  
        }  
        if( !DeleteService( hService ) )  //TRUE//FALSE
        {
            //卸载失败
            TRACE( "卸载失败:DeleteSrevice()错误号:%d !\n", GetLastError() );  
        }  

    }
    __finally
    {
        if(hService>0)
        {
            CloseServiceHandle(hService);
        }
        if(hSCM>0)
        {
            CloseServiceHandle(hSCM);
        }

    }
    return TRUE;


}
void OnLoad() 
{
    m_Message.SetWindowText(_T(""));
     HANDLE hDevice = INVALID_HANDLE_VALUE;
     char buffer[1024]={0};
     char wbuf[64]={0};
      DWORD dwByteRead;
      DWORD dwByteWrite;
      DWORD dwSize;
    // TODO: Add extra validation here
    CFileDialog  file(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,_T("驱动文件(SYS)|*.sys|"),NULL);
    if(file.DoModal()==IDOK)
    {
        CString str1,str2;
        str1=file.GetFileName();
        str2=file.GetPathName();
        if(LoadNtDriver(str1.GetBuffer(str1.GetLength()),str2.GetBuffer(str2.GetLength())))
        {
            path=str1;
            m_Message.SetWindowText(_T("加载成功"));
            AddMessage(_T("加载成功"));
            hDevice = CreateFile(L"\\\\.\\LinkSmkDevice",GENERIC_READ | GENERIC_WRITE,0,                         
                            NULL,OPEN_EXISTING,     
                            FILE_ATTRIBUTE_NORMAL,NULL ); //发送IRP_MJ_CREATE
               if ( hDevice != INVALID_HANDLE_VALUE )
               {
                  
                   AddMessage(_T("打开设备成功"));
                  
               }

            memset(wbuf,'S',64);
              if ( WriteFile(hDevice,&wbuf, 64, &dwByteWrite, NULL  ) ) //向设备写入64个字节的 'S'
              {
                AddMessage(_T("W设备"));
              }
              
              if(ReadFile( hDevice, &buffer, sizeof(buffer), &dwByteRead, NULL ))//读取设备中缓存
              {
                  CString str;
                  str.Format(_T("%s-%d"),buffer,dwByteRead);
                  AddMessage(str);
             }
              DWORD ret=GetFileSize(hDevice,&dwSize);
              if (ret)
              {

                  CString st2r;
                  st2r.Format(_T("GetSize Success \r\n FileSize:%d"),ret);
                    AddMessage(st2r);
              }
               if( DeviceIoControl( hDevice,                        
                   CTL_CODE( FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS ),                        
                   &buffer, dwByteRead, &buffer, sizeof(buffer), &dwByteRead, NULL ) )


                    if ( hDevice != INVALID_HANDLE_VALUE) 
                    {                 
                        if ( CloseHandle( hDevice ) ) 
                        {                        
                            AddMessage( _T("关闭设备句柄成功!\n" ));                 
                        }
                        else 
                        {                         
                            AddMessage( _T("关闭设备句柄失败!\n" ));                
                        }         
                    } 
        }
    }
    
}
void AddMessage(CString str)
{
    CString temp;
    m_Message.GetWindowText(temp);
    temp.Format(_T("%s\r\n%s"),temp,str);
    m_Message.SetWindowText(temp);
}

load的代码包含了驱动加载 CreateFile ReadFile WriteFile GetFileSize DeviceControl CloseFile,都会发送相应的IRP

驱动的代码

//入口函数 只指定了 Read Wirte Close Create query,其他的派遣函数系统默认
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
{

#if DBG
    _asm int 3
#endif
        CreateComs(DriverObject);

    DriverObject->MajorFunction[IRP_MJ_READ]   = ReadDispatch;         
    DriverObject->MajorFunction[IRP_MJ_CLOSE]  = GenerDispatch;         
    DriverObject->MajorFunction[IRP_MJ_WRITE]  = WriteDispatch;        
    DriverObject->MajorFunction[IRP_MJ_CREATE] = GenerDispatch;        
    DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = QueFileDispatch;

        DriverObject->DriverUnload=UnLoad;
    return 1;
}
//一般的派遣函数 基本不干事的
NTSTATUS GenerDispatch(PDEVICE_OBJECT pDevice, PIRP irp)
{
    /*IoSkipCurrentIrpStackLocation(irp);
    //return IoCallDriver(((PC2P_DEV_EXT)pDevice->DeviceExtension)->LowerObject,irp);
    return IoCallDriver(pDevice,irp);*/
        
        UCHAR type;
        PIO_STACK_LOCATION pStack = NULL;           //建立一个字符串数组与IRP类型对应起来        
        

          static char* SzIrpName[] = 
          {                        
              "IRP_MJ_CREATE",                         
              "IRP_MJ_CREATE_NAMED_PIPE",                         
              "IRP_MJ_CLOSE",                         
              "IRP_MJ_READ",                         
              "IRP_MJ_WRITE",                         
              "IRP_MJ_QUERY_INFORMATION",                         
              "IRP_MJ_SET_INFORMATION",                        
              "IRP_MJ_QUERY_EA",                        
              "IRP_MJ_SET_EA",                         
              "IRP_MJ_FLUSH_BUFFERS",                         
              "IRP_MJ_QUERY_VOLUME_INFORMATION",                         
              "IRP_MJ_SET_VOLUME_INFORMATION",                        
              "IRP_MJ_DIRECTORY_CONTROL",                         
              "IRP_MJ_FILE_SYSTEM_CONTROL",                         
              "IRP_MJ_DEVICE_CONTROL",                         
              "IRP_MJ_INTERNAL_DEVICE_CONTROL",                         
              "IRP_MJ_SHUTDOWN",                         
              "IRP_MJ_LOCK_CONTROL",                         
              "IRP_MJ_CLEANUP",                         
              "IRP_MJ_CREATE_MAILSLOT",                        
              "IRP_MJ_QUERY_SECURITY",                        
              "IRP_MJ_SET_SECURITY",                        
              "IRP_MJ_POWER",                        
              "IRP_MJ_SYSTEM_CONTROL",                         
              "IRP_MJ_DEVICE_CHANGE",                         
              "IRP_MJ_QUERY_QUOTA",                         
              "IRP_MJ_SET_QUOTA",                         
              "IRP_MJ_PNP", 
          };           
          pStack = IoGetCurrentIrpStackLocation( irp );        
          type =  pStack->MajorFunction;          
          if ( type >= 28) 
          {                
              KdPrint(( "未知的功能号 %d\n", type ));       
          }
          else 
          {                
              KdPrint(( "功能号为 %s\n", SzIrpName[type] ));
          }
          //一般分发函数的处理套路就是这样       
          irp->IoStatus.Information = 0;        
          irp->IoStatus.Status = STATUS_SUCCESS;         
          IoCompleteRequest( irp, IO_NO_INCREMENT );         
          KdPrint(( "Irp_DispatchRoutine 执行完毕" ));         
          return STATUS_SUCCESS; 
}
//wirte 派遣函数
#pragma  code_seg( "PAGE" )
NTSTATUS WriteDispatch(PDEVICE_OBJECT pDevice, PIRP irp)
{
    PCHAR buffer=NULL;
    ULONG BufferLenth=0;
    ULONG WriteOffset=0;
    PDEVICE_EXT pDExt;
    PIO_STACK_LOCATION pStack = NULL;  

    pDExt=(PDEVICE_EXT)pDevice->DeviceExtension;
    pStack = IoGetCurrentIrpStackLocation( irp );        
    BufferLenth=pStack->Parameters.Write.Length;//希望写得长度
    WriteOffset=pStack->Parameters.Write.ByteOffset.QuadPart;
    if(irp->MdlAddress!=NULL)
    {
        buffer=(PCHAR)MmGetSystemAddressForMdlSafe(irp->MdlAddress,NormalPagePriority);
    }
    else
    {
        buffer=(PCHAR)irp->UserBuffer;
        if(buffer==NULL)
            buffer=(PCHAR)irp->AssociatedIrp.SystemBuffer;
    }
    if(buffer!=NULL)
    {
        KdPrint(("buffer form ring3 :%s\r\n",buffer));
        if(WriteOffset+BufferLenth>MAXFILE)
        {
            KdPrint(("Size > Max\r\n"));
        }
        else
        {
            KdPrint(("buffer offset :%d\r\n",WriteOffset));
            RtlCopyMemory(pDExt->buffer+WriteOffset,buffer,BufferLenth);
            pDExt->file_lenth=WriteOffset+BufferLenth;
            irp->IoStatus.Information = BufferLenth;     //实际写得长度 返回给WriteFile 中的第4个参数值
            irp->IoStatus.Status = STATUS_SUCCESS;         
            IoCompleteRequest( irp, IO_NO_INCREMENT );         
            KdPrint(( "Irp_DispatchRoutine 执行完毕 wirte lenth %d",BufferLenth ));         
            return STATUS_SUCCESS;
        }
    }
}
//query 派遣函数
#pragma  code_seg( "PAGE" )
NTSTATUS QueFileDispatch(PDEVICE_OBJECT pDevice, PIRP irp)
{

    ULONG BufferLenth=0;
    PDEVICE_EXT pDExt;
    FILE_INFORMATION_CLASS info;
    PFILE_STANDARD_INFORMATION pinfo;
    PIO_STACK_LOCATION pStack = NULL;  
    pDExt=(PDEVICE_EXT)pDevice->DeviceExtension;
    pStack = IoGetCurrentIrpStackLocation( irp );    

    info=pStack->Parameters.QueryFile.FileInformationClass;
    if(info==FileStandardInformation)
    {
        KdPrint(("FileStandardInformation\r\n"));
        pinfo=(PFILE_STANDARD_INFORMATION)irp->AssociatedIrp.SystemBuffer;
        pinfo->EndOfFile=RtlConvertLongToLargeInteger(pDExt->file_lenth);
    }
    BufferLenth=pStack->Parameters.QueryFile.Length;
    irp->IoStatus.Information = BufferLenth;        
    irp->IoStatus.Status = STATUS_SUCCESS; 
    KdPrint(( "IRP_MJ_QUERY_INFORMATION 执行完毕 %d" ,pStack->Parameters.QueryFile.Length));  
    IoCompleteRequest( irp, IO_NO_INCREMENT );         

    return STATUS_SUCCESS; 
}
//Read派遣函数
#pragma  code_seg( "PAGE" )
NTSTATUS ReadDispatch(PDEVICE_OBJECT pDevice, PIRP irp)
{        
        PCHAR buffer=NULL;
        ULONG BufferLenth=0;
        ULONG ReadOffset=0;
        PDEVICE_EXT pDExt;
        PIO_STACK_LOCATION pStack = NULL;  

        pDExt=(PDEVICE_EXT)pDevice->DeviceExtension;
        pStack = IoGetCurrentIrpStackLocation( irp );        
        BufferLenth=pStack->Parameters.Read.Length;
        ReadOffset=pStack->Parameters.Read.ByteOffset.QuadPart;

        if (ReadOffset+BufferLenth>MAXFILE)
        {
            KdPrint(("Read Size > Max\r\n"));
             BufferLenth=0;
        }
        else
        {
            RtlCopyMemory(irp->AssociatedIrp.SystemBuffer,pDExt->buffer+ReadOffset,BufferLenth);
            
        }
        irp->IoStatus.Information = BufferLenth;        
        irp->IoStatus.Status = STATUS_SUCCESS;         
        IoCompleteRequest( irp, IO_NO_INCREMENT );         
        KdPrint(( "Irp_DispatchRoutine 执行完毕" ));         
        return STATUS_SUCCESS; 

}

程序流程是这样的,加载驱动创建一个设备,向该设备写入64个字节('S'),从该设备读取1024个自己,获取设备大小






posted on 2012-04-09 22:19  xmcc  阅读(1572)  评论(0编辑  收藏  举报

导航