纵览: 在comspy的驱动端,drivers obj生成了两个devices obj,一个是无名的位于被过滤com口上层堆栈,发往被过滤com口的所有IRP都是首先经过这个 无名的设备obj,在驱动入口已经设置好IRP转发函数,无名设备在转发IRP给过滤com口之前先设置好完成例程,然后转发IRP给下层的com口,com口 完成了IRP后调用完成例程,在完成例程中,把数据打包放入链表,然后设置事件通知应用程序; 这个无名设备对应的IRP: ComSpy_Read ComSpy_Write ComSpy_IoCtl ComSpy_Create ComSpy_Close ComSpy_DispatchPassThrough ComSpy_Power ComSpy_PnP 对应完成例程: OpenCompletion CloseCompletion ReadCompletion WriteCompletion IOCompletion DefaultCompletion
另外一个device obj就是名为comspy的设备,它负责和应用程序通讯,它通过链表获取com口读写的内容,通过事件和应用程序同步。 对应的IRP: IOCtrl_Write IOCtrl_PnP IOCtrl_Power IOCtrl_Read IOCtrl_IoCtl IOCtrl_CreateClose
1.comspy头文件 构建IO控制码 #define FILE_DEVICE_COMSPY 0x00001001 #define IO_REFERENCE_EVENT \ CTL_CODE(FILE_DEVICE_COMSPY, 0x0803, METHOD_NEITHER, \ FILE_ANY_ACCESS) #define IO_DEREFERENCE_EVENT \ CTL_CODE(FILE_DEVICE_COMSPY, 0x0804, METHOD_NEITHER, \ FILE_ANY_ACCESS)
#define IO_SET_EVENT \ CTL_CODE(FILE_DEVICE_COMSPY, 0x0805, METHOD_NEITHER, \ FILE_ANY_ACCESS) #define IO_CLEAR_EVENT \ CTL_CODE(FILE_DEVICE_COMSPY, 0x0806, METHOD_NEITHER, \ FILE_ANY_ACCESS) #define IO_QUERY_EVENT_STATE \ CTL_CODE(FILE_DEVICE_COMSPY, 0x0807, METHOD_NEITHER, \ FILE_ANY_ACCESS) #define IO_GET_SHAREMEMORY_ADDR \ CTL_CODE(FILE_DEVICE_COMSPY, 0x0808, METHOD_BUFFERED, \ FILE_ANY_ACCESS)
#define IO_CLEAN_SHAREMEMORY_ADDR \ CTL_CODE(FILE_DEVICE_COMSPY, 0x0809, METHOD_BUFFERED, \ FILE_ANY_ACCESS)
/*请求类型枚举*/ enum { REQ_OPEN, REQ_READ, REQ_WRITE, REQ_CLOSE, REQ_FLUSH, REQ_SETBAUDRATE, REQ_SETLINECONTROL, }; // typedef struct tagIO_REQ/*IO请求结构*/ { ULONG SizeTotal; ULONG SizeCopied; CHAR type; LIST_ENTRY entry; PVOID pData;
}IO_REQ, *PIO_REQ;;
typedef struct _DEVICE_EXTENSION/*无名设备的设备扩展*/ {
PDEVICE_OBJECT pFilterDeviceObject; // 过滤设备对象(自身)
PDEVICE_OBJECT TargetDeviceObject; // 绑定的设备对象 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
typedef struct _ZT_DEVICE_EXTENSION/*comspy的设备扩展*/ { PDEVICE_OBJECT fdo; PMDL MyMdl; PVOID SystemVirtualAddress; PVOID UserVirtualAddress;
} ZT_DEVICE_EXTENSION,*PZT_DEVICE_EXTENSION;
2.重要的全局变量
const WCHAR NameBuffer[] = L"\\Device\\ComSpy"; const WCHAR DOSNameBuffer[] = L"\\DosDevices\\ComSpy";
/*DeviceObject设备类型,属于自定义设备类型标识,以区别FILE_DEVICE_SERIAL_PORT*/ #define FILE_DEVICE_COMPORT 0x0000f000
#define DEV_EXT_ATTACHED (0x00000001)
//filter device object过滤设备的全局变量声明 LIST_ENTRY g_data_lst; //DATA队列 KSPIN_LOCK g_req_splock; //读同步自旋锁
ULONG g_szCount = 0; ULONG g_bStartMon = 0;
PVOID gpEventObject = NULL; PVOID SystemVirtualAddress = NULL ;
驱动的开始和结束 1.驱动入口函数 1.设置IRP处理函数 2.IoGetDeviceObjectPointer输入符号链接设备名称获取\\??\\COM1文件对象pTargetFileObject和设备对象pTargetDeviceObject 3.创建驱动对象的设备对象,创建无名的设备对象,设备类型,属性和被过滤的设备一样;保存设备指针和被过滤设备指针到设备扩展结构体里面。 4.IoAttachDeviceByPointer(pDeviceObject,pTargetDeviceObject)添加pDeviceObject到pTargetDeviceObject的上一层,设备堆栈设置。设置设备类型属性以及标志都和被过滤的设备一样。 5.创建另外一个名字为\\Device\\ComSpy的设备对象。 6.初始化链表和自旋锁。
/*sys驱动入口函数*/ NTSTATUS DriverEntry ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) {
// UNREFERENCED_PARAMETER (RegistryPath);
NTSTATUS NtStatus = STATUS_SUCCESS; ULONG uiIndex = 0; PDEVICE_OBJECT pDeviceObject = NULL, pFilteredDevice = NULL; UNICODE_STRING usDeviceToFilter; /*目标设备指针和文件指针*/ PDEVICE_OBJECT pTargetDeviceObject = NULL; PFILE_OBJECT pTargetFileObject = NULL; PDEVICE_EXTENSION pDevExt;
DbgPrint("DriverEntry Called \n"); DbgPrint(("ComSpy.SYS: entering DriverEntry\n"));
/////////////////////////////////////////////////////////////////// /*设置默认的IRP处理函数*/ for(uiIndex = 0; uiIndex < IRP_MJ_MAXIMUM_FUNCTION; uiIndex++) DriverObject->MajorFunction[uiIndex] = ComSpy_DispatchPassThrough; /*设置当前堆栈层的IRP处理函数*/ DriverObject->MajorFunction[IRP_MJ_CLOSE] = ComSpy_Close; DriverObject->MajorFunction[IRP_MJ_CREATE] = ComSpy_Create; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ComSpy_IoCtl; DriverObject->MajorFunction[IRP_MJ_READ] = ComSpy_Read; DriverObject->MajorFunction[IRP_MJ_WRITE] = ComSpy_Write; DriverObject->MajorFunction[IRP_MJ_POWER] = ComSpy_Power; DriverObject->MajorFunction[IRP_MJ_PNP] = ComSpy_PnP; DriverObject->DriverUnload = ComSpy_Unload;
//////////////////////////////////////////////////////////// /*设置要过滤的底层设备名称*/ RtlInitUnicodeString(&usDeviceToFilter, L"\\??\\COM1"); /*输入符号链接设备名称usDeviceToFilter,输出文件对象pTargetFileObject和设备对象pTargetDeviceObject*/ NtStatus = IoGetDeviceObjectPointer( IN &usDeviceToFilter, IN FILE_ALL_ACCESS, OUT &pTargetFileObject, OUT &pTargetDeviceObject ); /*获取文件和设备对象失败时的处理*/ if( !NT_SUCCESS(NtStatus) ) { DbgPrint(("ComSpy.SYS:: Couldn't Get the Device Object\n")); pTargetFileObject = NULL; pTargetDeviceObject = NULL; return( NtStatus ); } /*否则成功获取下一层的设备对象和文件对象*/ DbgPrint("IoGetDeviceObjectPointer ok!\n");
////////////////////////////////////////////////////////////////////////// /*创建驱动对象的设备对象,IN->DriverObjece,OUT->pDeviceObjece,注意!这里是创建无名的设备对象, 因为第三参数DeviceName为NULL,设备类型,属性和被过滤的设备一样*/ NtStatus = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, pTargetDeviceObject->DeviceType, pTargetDeviceObject->Characteristics, FALSE, &pDeviceObject);
/*创建设备对象失败时处理*/ if( !NT_SUCCESS(NtStatus) ) { DbgPrint(("ComSpy.SYS: ComSpy failed to create device!\n"));
RtlFreeUnicodeString( &usDeviceToFilter );
ObDereferenceObject( pTargetFileObject ); pTargetFileObject = NULL;
return STATUS_SUCCESS;
}
/*获取设备扩展结构体的内存,非分页内存*/ pDevExt=ExAllocatePool(NonPagedPool, sizeof( PDEVICE_EXTENSION ) ); (PDEVICE_EXTENSION )( pDeviceObject->DeviceExtension )= pDevExt ; /*保存设备指针和被过滤设备指针到设备扩展结构体里面*/ pDevExt->pFilterDeviceObject = pDeviceObject; pDevExt->TargetDeviceObject = pTargetDeviceObject;
DbgPrint(("IoCreateDevice: Create Device \n")); /*添加pDeviceObject到pTargetDeviceObject的上一层,设备堆栈设置*/ NtStatus = IoAttachDeviceByPointer(pDeviceObject,pTargetDeviceObject); /*添加设备堆栈失败处理*/ if( !NT_SUCCESS(NtStatus) ) { DbgPrint(("ComSpy_Attach: Couldn't attach to COM Device Object\n"));
IoDeleteDevice( pDeviceObject ); pDeviceObject = NULL; ObDereferenceObject( pTargetFileObject ); pTargetFileObject = NULL; pTargetDeviceObject = NULL;
return( NtStatus ); }
DbgPrint(("IoAttachDeviceToDeviceStack: Attach Device OK \n"));
/////////////////////////////////// DbgPrint(("ComSpy.SYS: Attach Device\n")); /*设置设备类型属性以及标志都和被过滤的设备一样*/ pDeviceObject->DeviceType = pTargetDeviceObject->DeviceType; pDeviceObject->Characteristics = pTargetDeviceObject->Characteristics; pDeviceObject->Flags |= ( ( DO_BUFFERED_IO ) ); ///////////////////////////////////////////////////////////////////
DbgPrint(("ComSpy.SYS: Before Dereference TargetFileObject \n")); /*对文件对象的引用计数减1,然后释放该文件对象*/ ObDereferenceObject( pTargetFileObject ); pTargetFileObject = NULL;
/////////////////////////////////////////////////////////////////// /*创建另外一个名字为\\Device\\ComSpy的设备对象*/ NtStatus=Add_IoControlDevice(DriverObject,RegistryPath); /*初始化链表和自旋锁*/ InitializeListHead( &g_data_lst ); KeInitializeSpinLock( &g_req_splock );
DbgPrint(("ComSpy.SYS: Leaving DriverEntry\n"));
return NtStatus;
}
创建comspy设备的函数。 1.创建一个扩展结构为ZT_DEVICE_EXTENSION,名字为\\Device\\ComSpy,设备类型为FILE_DEVICE_COMPORT的设备对象。 2.初始化设备扩展结构,保存设备对象指针到扩展结构体中。 3.申请8字节内核内存构建mdl??what is mdl??保存SystemVirtualAddress到设备扩展。 4.创建uniNameString符号链接uniDOSString。 5.设置设备对象标志,缓冲IO。 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ /*Add_IoControlDevice*/ /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ /*添加一个IO控制的名字为\\Device\\ComSpy,设备类型为FILE_DEVICE_COMPORT的设备对象设备*/ NTSTATUS Add_IoControlDevice( IN PDRIVER_OBJECT DriverObj, IN PUNICODE_STRING RegtryPath) { PDEVICE_OBJECT deviceObject; NTSTATUS status; UNICODE_STRING uniNameString, uniDOSString; PZT_DEVICE_EXTENSION pDevExt;
DbgPrint("ComSpy_IOCtrl Create Device OK \n");
/* const WCHAR NameBuffer[] = L"\\Device\\ComSpy"; const WCHAR DOSNameBuffer[] = L"\\DosDevices\\ComSpy"; */ RtlInitUnicodeString(&uniNameString, NameBuffer); RtlInitUnicodeString(&uniDOSString, DOSNameBuffer); /*创建一个扩展结构为ZT_DEVICE_EXTENSION,名字为\\Device\\ComSpy,设备类型为FILE_DEVICE_COMPORT的设备对象*/ status = IoCreateDevice(DriverObj,sizeof(ZT_DEVICE_EXTENSION), &uniNameString, FILE_DEVICE_COMPORT, 0, FALSE, &deviceObject);
if(!NT_SUCCESS(status)) { return status; } /*初始化设备扩展结构,保存设备对象指针到扩展结构体中*/ pDevExt = (PZT_DEVICE_EXTENSION )( deviceObject->DeviceExtension ); RtlZeroMemory( pDevExt, sizeof( PZT_DEVICE_EXTENSION ) );
pDevExt->fdo=deviceObject;
//////////////////////////////////////////////////////////// /*申请8字节内核内存构建mdl??what is mdl??*/ pDevExt->SystemVirtualAddress = ExAllocatePool(NonPagedPool, 8); pDevExt->MyMdl = IoAllocateMdl(pDevExt->SystemVirtualAddress, 8, FALSE, FALSE, NULL); MmBuildMdlForNonPagedPool(pDevExt->MyMdl); /////////////////////////////////////////////////////////// /*创建uniNameString符号链接uniDOSString*/ status = IoCreateSymbolicLink (&uniDOSString, &uniNameString);
if (!NT_SUCCESS(status)) { return status; } /*设置设备对象标志,缓冲IO*/ deviceObject->Flags |= DO_BUFFERED_IO;
///////////////////////////////////////////////////// return STATUS_SUCCESS;
}
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ /*驱动卸载函数*/ /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ VOID ComSpy_Unload( IN PDRIVER_OBJECT DriverObject ) { BOOLEAN NoRequestsOutstanding = FALSE; UNICODE_STRING uniDOSString; PDEVICE_OBJECT pFirstObj; PDEVICE_OBJECT pNextObj;
PDEVICE_EXTENSION pExt; PZT_DEVICE_EXTENSION pDevExt; PIO_REQ pReq; PLIST_ENTRY link; DbgPrint("ComSpy_Unload Called \r\n"); /*取得驱动对象的第一个设备对象指针*/ pFirstObj=DriverObject->DeviceObject; /*如果此设备对象是自定义类型的设备,\\Device\\ComSpy,符号链接\\DosDevices\\ComSpy*/ if(pFirstObj->DeviceType==FILE_DEVICE_COMPORT) { pDevExt=(PZT_DEVICE_EXTENSION)pFirstObj->DeviceExtension; /*删除符号链接*/ RtlInitUnicodeString(&uniDOSString, DOSNameBuffer); IoDeleteSymbolicLink (&uniDOSString);
/*如果uservirtualaddress不为空,释放mdl关联的映射*/ if(pDevExt->UserVirtualAddress) { MmUnmapLockedPages(pDevExt->UserVirtualAddress, pDevExt->MyMdl); pDevExt->UserVirtualAddress = NULL; } /*如果mdl不空,释放mdl*/ if(pDevExt->MyMdl) { IoFreeMdl(pDevExt->MyMdl); pDevExt->MyMdl = NULL; } /*如果SystemVirtualAddress不为空,释放它*/ if(pDevExt->SystemVirtualAddress) { ExFreePool(pDevExt->SystemVirtualAddress); pDevExt->SystemVirtualAddress = NULL; } /*释放链表的IO_REQ数据结构*/ while (link = ExInterlockedRemoveHeadList(&g_data_lst, &g_req_splock)) { pReq= CONTAINING_RECORD(link,IO_REQ,entry);
ExFreePool(pReq->pData); ExFreePool(pReq); } DbgPrint("ComSpy_Unload IoCtrl First Unload \r\n"); /*得到下一个设备对象的指针,删除上一个设备,弹出设备堆栈,删除下一个设备,释放它的设备扩展*/ pNextObj=pFirstObj->NextDevice; IoDeleteDevice(pFirstObj); pExt= (PDEVICE_EXTENSION)pNextObj->DeviceExtension; IoDetachDevice( pExt->TargetDeviceObject ); IoDeleteDevice(pExt->pFilterDeviceObject); ExFreePool(pExt);
}
DbgPrint("ComSpy_Unload end \r\n"); }
接下来看无名设备的IRP派遣函数: ComSpy_Read ComSpy_Write ComSpy_IoCtl ComSpy_Create ComSpy_Close ComSpy_DispatchPassThrough ComSpy_Power ComSpy_PnP 以ComSpy_Read为例,这些函数都是设置好完成例程后直接转发下一层驱动去处理。 1.如果调用此IRP函数的设备对象是\\Device\\ComSpy,直接调用IOCtrl_前缀的函数处理。 2.否则是无名DEVICEOBJ调用的IRP,得到设备扩展,获取当前IRP堆栈指针。 3.拷贝当前IRP堆栈到下一层,设置IRP完成例程。 4.调用下一层堆栈的驱动。 5.下一层驱动完成IRP后原路返回,遇到完成例程,调用它,然后完成IRP. /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ /*驱动read函数*/ /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ NTSTATUS ComSpy_Read(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
PIO_STACK_LOCATION IrpStack; PDEVICE_EXTENSION pExt; NTSTATUS NtStatus = STATUS_SUCCESS; DbgPrint("ComSpy_Read Called \r\n"); /*如果调用此IRP函数的设备对象的类型是FILE_DEVICE_COMPORT,也就是\\Device\\ComSpy*/ if(DeviceObject->DeviceType==FILE_DEVICE_COMPORT) { return IOCtrl_Read(DeviceObject,Irp); }
/*否则是无名DEVICEOBJ调用的IRP,得到设备扩展,获取当前IRP堆栈指针*/ pExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; IrpStack = IoGetCurrentIrpStackLocation(Irp); /*拷贝当前IRP堆栈到下一层,设置IRP完成例程*/ IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) ReadCompletion, NULL, TRUE, TRUE, TRUE); //care about the result /*调用下一层堆栈的驱动*/ NtStatus = IoCallDriver(pExt->TargetDeviceObject, Irp);
DbgPrint("ComSpy_Read Exit 0x%0x \r\n", NtStatus);
return NtStatus;
}
下面看完成例程 OpenCompletion CloseCompletion DefaultCompletion 以上三个完成例程暂时没有使用,剩下的三个完成例程 ReadCompletion WriteCompletion IOCompletion 流程都一样,以ReadCompletion为例分析: 1.底层IRP完成后返回STATUS_PENDING,则mark irp标志。 2.如果底层IRP完成状态为成功,且开始监控标志已经设置了的话, 获取当前irp堆栈指针 申请IO_REQ结构内存,标志req类型,登记要拷贝的数据大小,如果要拷贝的数据大小不为0, 从Irp->AssociatedIrp.SystemBuffer拷贝req->SizeCopied到req->pData 3.重新计算req大小到req->sizetotal 4.更新全局变量:g_szcount数据总大小 5.把req IO_REQ包插入链表g_data_lst 6.拷贝&g_szCount4字节到SystemVirtualAddress,用来通知应用程序数据的大小。 7.触发事件通知应用程序。
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ /*Comspy_read的完成例程readCompletion*/ /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ NTSTATUS ReadCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context) { PIO_REQ req; DbgPrint("ComSpy ReadCompletion OK \n"); /*底层IRP完成后返回STATUS_PENDING,则mark irp标志*/ if (Irp->PendingReturned) { IoMarkIrpPending(Irp); } /*底层IRP完成状态为成功,且开始监控标志已经设置了*/ if (Irp->IoStatus.Status==STATUS_SUCCESS && g_bStartMon!=0) { PIO_STACK_LOCATION cur; cur = IoGetCurrentIrpStackLocation(Irp);/*获取当前irp堆栈指针*/
req = ExAllocatePool(NonPagedPool,sizeof(IO_REQ));/*申请IO_REQ结构内存*/ req->type=REQ_READ;/*标志req类型*/ req->SizeCopied=Irp->IoStatus.Information;/*要拷贝的数据大小*/
if(req->SizeCopied)/*有数据要拷贝*/ { req->pData=ExAllocatePool(NonPagedPool,req->SizeCopied);/*申请需要的内存*/ /*from Irp->AssociatedIrp.SystemBuffer拷贝req->SizeCopied到req->pData*/ RtlCopyMemory(req->pData,Irp->AssociatedIrp.SystemBuffer,req->SizeCopied); }
req->SizeTotal= sizeof(IO_REQ)+req->SizeCopied;/*重新计算req大小到req->sizetotal*/ g_szCount=g_szCount+req->SizeTotal;/*更新全局变量:g_szcount数据总大小*/ ExInterlockedInsertTailList(&g_data_lst, &(req->entry),&g_req_splock);/*插入链表*/ ///////////////////////////////////////////////////// memcpy(SystemVirtualAddress, &g_szCount, 4);/*拷贝&g_szCount4字节到SystemVirtualAddress*/ DbgPrint("ComSpy ReadCompletion OK Add Bytes %x \n",req->SizeTotal);
KeSetEvent(gpEventObject,0,FALSE);/*触发事件通知*/ } return STATUS_SUCCESS; }
下面看comspy这个和应用程序直接交互的设备对象。 无名设备通过完成例程把监控的com口数据打包放入到链表,然后通知应用程序,应用程序只能去读取comspy这个设备, 所以comspy的任务就是从链表读取数据返回给应用程序。所以暂时不需要写入。 下面三个IRP都是直接完成IRP返回。 IOCtrl_Write IOCtrl_PnP IOCtrl_Power
Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_ACCESS_VIOLATION; IoCompleteRequest(Irp, IO_NO_INCREMENT);
DbgPrint((" Exit IOCtrl_Write routine\n"));
return STATUS_SUCCESS;
重点看IOCtrl_IoCtl()和IOCtrl_Read()函数。 1.IOCtrl_IoCtl()对应着应用程序的IO命令 DeviceIoControl( m_hDevice, IO_REFERENCE_EVENT, (LPVOID) m_hCommEvent,//IN LPVOID lpInBuffer0, NULL, 0, &dwReturn, NULL); 1.首先获取当前irp堆栈指针、设备扩展指针、IO代码、输入缓存长度、输出缓存长度 2.判断IO码,做以下处理: IO_REFERENCE_EVENT: 获取传递进来的缓冲区指针 将缓冲区的句柄赋值给hEvent(应用程序传递进来的同步用事件句柄); 通过ObReferenceObjectByHandle输入句柄,返回事件对象gpEventObjectOBJ指针保存。 IO_DEREFERENCE_EVENT: 如果事件对象gpEvenObject存在,引用计数减1 IO_SET_EVENT:设置事件gpEventObject IO_CLEAR_EVENT:清除事件gpEventObject IO_QUERY_EVENT_STATE:查询事件,获取事件状态送到应用程序 IO_GET_SHAREMEMORY_ADDR:/*获取共享内存地址*/ 将mdl描述的物理pages映射到UserVirtualAddress 然后将此地址送回应用程序 IO_CLEAN_SHAREMEMORY_ADDR:/*清除共享内存地址*/
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ /*IOCtrl_IoCtl*/ /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ NTSTATUS IOCtrl_IoCtl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) { NTSTATUS status; NTSTATUS ret; ULONG info; PIO_STACK_LOCATION IrpStack; ULONG ControlCode; ULONG InputLength,OutputLength; HANDLE hEvent; PVOID inputBuffer; OBJECT_HANDLE_INFORMATION objHandleInfo; LONG* outBuf; PZT_DEVICE_EXTENSION pExt; long dwRet;
IrpStack=IoGetCurrentIrpStackLocation(Irp);/*获取当前irp堆栈指针*/
pExt = (PZT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;/*获取设备扩展指针*/ ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;/*IO代码*/ InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;/*输入缓存长度*/ OutputLength= IrpStack->Parameters.DeviceIoControl.OutputBufferLength;/*输出缓存长度*/ DbgPrint("InputBufferLength: %d OutputBufferLength: %d\n", InputLength, OutputLength ); DbgPrint("ControlCode: %x, Irp: %x\n", ControlCode, (unsigned long)IrpStack); status = STATUS_SUCCESS; info = 0; switch(ControlCode)/*判断IO码,应用程序IOCtl->\\Device\\Comspy*/ { case IO_REFERENCE_EVENT: inputBuffer = Irp->AssociatedIrp.SystemBuffer;/*获取传递进来的缓冲区指针*/ hEvent = (HANDLE) IrpStack->Parameters.DeviceIoControl.Type3InputBuffer;/*将缓冲区的句柄赋值给hEvent*/ DbgPrint("Event Handle: %x \n", hEvent); status = ObReferenceObjectByHandle(/*输入句柄,返回事件对象gpEventObjectOBJ指针*/ hEvent, GENERIC_ALL, NULL, KernelMode, &gpEventObject,/*OUT PVOID *Object,*/ &objHandleInfo); if(status != STATUS_SUCCESS) { DbgPrint("ObReferenceObjectByHandle failed! status = %x\n", status); break; } DbgPrint("Referenct object sussfully!\n"); break; case IO_DEREFERENCE_EVENT: if(gpEventObject)/*如果事件对象gpEvenObject存在,引用计数减1*/ ObDereferenceObject(gpEventObject); DbgPrint("Dereferenct object sussfully!\n"); break;
case IO_SET_EVENT:/*设置事件gpEventObject*/ dwRet=KeSetEvent(gpEventObject,0,FALSE); DbgPrint("KeSetEvent sussfully! %x \n",dwRet); break; case IO_CLEAR_EVENT:/*清除事件gpEventObject*/ KeClearEvent(gpEventObject); DbgPrint("KeClearEvent sussfully!\n"); break; case IO_QUERY_EVENT_STATE:/*查询事件,将结果放到outBuf*/ DbgPrint("in KeReadStateEvent !\n"); outBuf = (LONG*) Irp->UserBuffer;/*获取应用程序的输入缓冲*/ *outBuf = KeReadStateEvent(gpEventObject);/*获取事件状态送到应用程序*/ DbgPrint("KeReadStateEvent sussfully! Return %x \n",*outBuf); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(LONG); IoCompleteRequest(Irp, IO_NO_INCREMENT); return status;
case IO_GET_SHAREMEMORY_ADDR:/*获取共享内存地址*/ __try { /*将mdl描述的物理pages映射到UserVirtualAddress*/ pExt->UserVirtualAddress = MmMapLockedPages (pExt->MyMdl, UserMode ); *((PVOID *)(Irp->AssociatedIrp.SystemBuffer)) = pExt->UserVirtualAddress;/*然后将此地址送回应用程序*/
SystemVirtualAddress=pExt->SystemVirtualAddress; //保存用户地址 Irp->IoStatus.Status = STATUS_SUCCESS;/*完成IRP*/ Irp->IoStatus.Information = sizeof(PVOID); IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } __except(EXCEPTION_EXECUTE_HANDLER) { DbgPrint("GET_SHAREMEMORY_ADDR Failed!\n"); return CompleteRequest(Irp, GetExceptionCode(), 0); } case IO_CLEAN_SHAREMEMORY_ADDR:/*清除共享内存地址*/ ///////////////////////////////////////// if(pExt->UserVirtualAddress) { MmUnmapLockedPages(pExt->UserVirtualAddress, pExt->MyMdl); pExt->UserVirtualAddress = NULL; } break; default: break; } ret = CompleteRequest(Irp, status, info); DbgPrint(("Leaving IoControl routine\n")); return ret; }
再看IOCtrl_Read 1.获取自旋锁g_req_splock,提升IRQl 2.链表是否空,即有没有数据可以读取,如果读数据队列空,完成IRP返回 3.获取当前irp堆栈指针、IO代码、输入缓存长度、输出缓存长度,获取用户层传递的缓冲首址pOutBuf 4.从链表g_data_lst取IO_REQ包裹 5. 如果所请求数据小于一包长度(即传递进来的缓冲不够容纳一个包),重新把包插回链表,返回IRP报告处理失败。 6.拷贝pReq所指数据到pOutBuf,大小为一个IO_REQ,偏移pOutBuf指针,拷贝IO_REQ包的数据,pReq->pData到pOutBuf, 偏移pOutBuf指针,nToReadBytes记录数据大小(包IO_REQ结构大小+pData所指数据大小, 更新全局变量g_szCount总数据大小,释放数据,释放包,取下一个包数据,没有下一个包了,结束,跳出, 取包的IO_REQ结构指针,直到要超过缓冲区的边界了,跳出,把多取的一包回送链表。 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ /*IOCtrl_Read*/ /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ NTSTATUS IOCtrl_Read(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) { NTSTATUS status; KIRQL OldIrql; BOOLEAN bIsEmpty; BOOLEAN bEnd;
PIO_STACK_LOCATION IrpStack; ULONG ControlCode; ULONG InputLength,OutputLength; PUCHAR pOutBuf; ULONG nToReadBytes; PLIST_ENTRY link; PIO_REQ pReq;
DbgPrint("IOCtrl_Read Called \r\n"); /*获取自旋锁g_req_splock,提升IRQl*/ KeAcquireSpinLock( &g_req_splock, &OldIrql ); bIsEmpty = IsListEmpty( &g_data_lst );/*链表是否空,即没数据可以读取*/ KeReleaseSpinLock( &g_req_splock, OldIrql );/**/ if( bIsEmpty )/*读数据队列空,完成IRP返回*/ { DbgPrint(("------ 数据队列为空 --------\n"));
status = STATUS_UNSUCCESSFUL; return CompleteRequest( Irp, status, 0 );
} else/*否则数据队列不为空*/ { IrpStack = IoGetCurrentIrpStackLocation(Irp);/*获取当前irp堆栈指针*/
ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;/*IO代码*/ InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;/*输入缓存长度*/ OutputLength= IrpStack->Parameters.DeviceIoControl.OutputBufferLength;/*输出缓存长度*/ DbgPrint("InputBufferLength: %d OutputBufferLength: %d\n", InputLength, OutputLength );
pOutBuf = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;/*pOutBuf指向Irp->AssociatedIrp.SystemBuffer*/
link = ExInterlockedRemoveHeadList( &g_data_lst, &g_req_splock);//取 读数据 ASSERT( link );/*检查link参数*/
pReq= CONTAINING_RECORD( link, IO_REQ, entry );/*从link取数据*/
if(pReq->SizeTotal>OutputLength)/*读取的数据比请求数据大*/ { DbgPrint(("------ 所请求数据小于一包长度 --------\n"));
ExInterlockedInsertHeadList( &g_data_lst, link, &g_req_splock );//数据未读完 回送至表头 status = STATUS_UNSUCCESSFUL; return CompleteRequest( Irp, status, 0 );/*完成IRP*/ } /*否则pReq->SizeTotal<OutputLength*/ nToReadBytes=0;/*nToReadBytes置0*/ bEnd=FALSE;
while(nToReadBytes + pReq->SizeTotal <= OutputLength) { /*拷贝pReq所指数据到pOutBuf,大小为一个IO_REQ*/ RtlCopyMemory(pOutBuf,pReq,sizeof(IO_REQ)); pOutBuf+=sizeof(IO_REQ);/*偏移pOutBuf指针*/
ASSERT( pReq->pData );/*检查pReq->pData*/ RtlCopyMemory(pOutBuf,pReq->pData,pReq->SizeCopied);/*拷贝IO_REQ包的数据,pReq->pData到pOutBuf*/ pOutBuf+=pReq->SizeCopied;/*偏移pOutBuf指针*/
nToReadBytes+=pReq->SizeTotal;/*nToReadBytes记录数据大小(包IO_REQ结构大小+pData所指数据大小*/ g_szCount-=pReq->SizeTotal;/*更新全局变量g_szCount总数据大小*/
ExFreePool(pReq->pData);/*释放数据*/ ExFreePool(pReq);/*释放包*/
link = ExInterlockedRemoveHeadList( &g_data_lst, &g_req_splock);//取下一个包数据 if(link==NULL) { bEnd=TRUE;/*没有下一个包了,结束,跳出*/ break; }
ASSERT( link ); pReq= CONTAINING_RECORD( link, IO_REQ, entry );/*取包的IO_REQ结构指针*/
} if(bEnd==FALSE) { //多取的一包回送表头 ExInterlockedInsertHeadList( &g_data_lst, link, &g_req_splock ); } DbgPrint("------ 实际请求数据长度 %x-------\n",nToReadBytes );
status = STATUS_SUCCESS; DbgPrint(("-------- Exit ReadIrp routine -----------\n"));
return CompleteRequest( Irp, status, nToReadBytes ); }
}
最后看IOCtrl_CreateClose,在comspy创建和关闭的时候调用 主要是IRP_MJ_CREATE时候设置全局变量申明g_bStartMon=0x1;/*开始监控*/ IRP_MJ_CLOSE时候结束监控,释放链表数据,完成IRP返回。 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ /*\\Device\\ComSpy->IOCtrl_CreateClose*/ /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ NTSTATUS IOCtrl_CreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION IrpStack; NTSTATUS ntStatus; PIO_REQ pReq; PLIST_ENTRY link;
DbgPrint("ComSpy_IOCtrl Dispatch OK \n");
Irp->IoStatus.Status = STATUS_SUCCESS; // 返回状态 Irp->IoStatus.Information = 0; /*得到当前IRP堆栈指针*/ IrpStack = IoGetCurrentIrpStackLocation(Irp); /*判断派遣函数*/ switch (IrpStack->MajorFunction) { case IRP_MJ_CREATE: DbgPrint("ComSpy IOCtrl (IRP_MJ_CREATE)...\n"); g_bStartMon=0x1;/*开始监控*/ break; case IRP_MJ_CLOSE: g_bStartMon=0x0;/*结束监控*/ DbgPrint("ComSpy IOCtrl (IRP_MJ_CLOSE)...\n"); /*释放链表IO_REQ数据结构*/ while (link = ExInterlockedRemoveHeadList(&g_data_lst, &g_req_splock)) { pReq= CONTAINING_RECORD(link,IO_REQ,entry);
ExFreePool(pReq->pData); ExFreePool(pReq); } ///////////////////////////////////////// break; default: Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; DbgPrint("ComSpy IOCtrl (OTHER_MAJOR_FUNCTION)... 0x%x \n",IrpStack->MajorFunction); break; } /*完成IRP后返回*/ ntStatus = Irp->IoStatus.Status; IoCompleteRequest (Irp, IO_NO_INCREMENT); //complete the request return ntStatus; }
|