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个自己,获取设备大小