原创 监听串口的comspy源码分析_驱动部分

2010-7-30 22:07 3429 10 10 分类: 软件与OS

纵览:
在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;
}

文章评论0条评论)

登录后参与讨论
我要评论
0
10
关闭 站长推荐上一条 /2 下一条