久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

監(jiān)聽串口的comspy源碼分析---驅(qū)動部分

 herowuking 2015-05-04

縱覽:
在comspy的驅(qū)動端,,drivers obj生成了兩個devices obj,一個是無名的位于被過濾com口上層堆棧,,發(fā)往被過濾com口的所有IRP都是首先經(jīng)過這個
無名的設備obj,,在驅(qū)動入口已經(jīng)設置好IRP轉(zhuǎn)發(fā)函數(shù),無名設備在轉(zhuǎn)發(fā)IRP給過濾com口之前先設置好完成例程,,然后轉(zhuǎn)發(fā)IRP給下層的com口,,com口
完成了IRP后調(diào)用完成例程,在完成例程中,,把數(shù)據(jù)打包放入鏈表,,然后設置事件通知應用程序;
這個無名設備對應的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口讀寫的內(nèi)容,通過事件和應用程序同步,。
對應的IRP:
IOCtrl_Write
IOCtrl_PnP
IOCtrl_Power
IOCtrl_Read
IOCtrl_IoCtl
IOCtrl_CreateClose



1.comspy頭文件
構(gòu)建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請求結(jié)構(gòu)*/
{
 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設備類型,,屬于自定義設備類型標識,以區(qū)別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 ;


驅(qū)動的開始和結(jié)束
1.驅(qū)動入口函數(shù)
1.設置IRP處理函數(shù)
2.IoGetDeviceObjectPointer輸入符號鏈接設備名稱獲取\\??\\COM1文件對象pTargetFileObject和設備對象pTargetDeviceObject
3.創(chuàng)建驅(qū)動對象的設備對象,創(chuàng)建無名的設備對象,設備類型,,屬性和被過濾的設備一樣,;保存設備指針和被過濾設備指針到設備擴展結(jié)構(gòu)體里面。
4.IoAttachDeviceByPointer(pDeviceObject,pTargetDeviceObject)添加pDeviceObject到pTargetDeviceObject的上一層,,設備堆棧設置,。設置設備類型屬性以及標志都和被過濾的設備一樣。
5.創(chuàng)建另外一個名字為\\Device\\ComSpy的設備對象,。
6.初始化鏈表和自旋鎖,。


/*sys驅(qū)動入口函數(shù)*/
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處理函數(shù)*/
    for(uiIndex = 0; uiIndex < IRP_MJ_MAXIMUM_FUNCTION; uiIndex++)
         DriverObject->MajorFunction[uiIndex] = ComSpy_DispatchPassThrough;
 /*設置當前堆棧層的IRP處理函數(shù)*/
    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");


 //////////////////////////////////////////////////////////////////////////
 /*創(chuàng)建驅(qū)動對象的設備對象,IN->DriverObjece,OUT->pDeviceObjece,注意,!這里是創(chuàng)建無名的設備對象,,
 因為第三參數(shù)DeviceName為NULL,設備類型,屬性和被過濾的設備一樣*/
  NtStatus = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL,
        pTargetDeviceObject->DeviceType,
        pTargetDeviceObject->Characteristics,
        FALSE, &pDeviceObject);


 /*創(chuàng)建設備對象失敗時處理*/
 if( !NT_SUCCESS(NtStatus) )
 {
        DbgPrint(("ComSpy.SYS: ComSpy failed to create device!\n"));


        RtlFreeUnicodeString( &usDeviceToFilter );


  ObDereferenceObject( pTargetFileObject );
  pTargetFileObject = NULL;


        return STATUS_SUCCESS;


 }


 /*獲取設備擴展結(jié)構(gòu)體的內(nèi)存,,非分頁內(nèi)存*/ 
 pDevExt=ExAllocatePool(NonPagedPool, sizeof( PDEVICE_EXTENSION ) );
 (PDEVICE_EXTENSION )( pDeviceObject->DeviceExtension )= pDevExt  ;
 /*保存設備指針和被過濾設備指針到設備擴展結(jié)構(gòu)體里面*/
 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"));
 /*對文件對象的引用計數(shù)減1,然后釋放該文件對象*/
 ObDereferenceObject( pTargetFileObject );
 
 pTargetFileObject = NULL;


 ///////////////////////////////////////////////////////////////////
 /*創(chuàng)建另外一個名字為\\Device\\ComSpy的設備對象*/
   NtStatus=Add_IoControlDevice(DriverObject,RegistryPath);
 /*初始化鏈表和自旋鎖*/
 InitializeListHead( &g_data_lst );
 KeInitializeSpinLock( &g_req_splock );



 DbgPrint(("ComSpy.SYS: Leaving DriverEntry\n"));


 return NtStatus;


}



創(chuàng)建comspy設備的函數(shù),。
1.創(chuàng)建一個擴展結(jié)構(gòu)為ZT_DEVICE_EXTENSION,,名字為\\Device\\ComSpy,設備類型為FILE_DEVICE_COMPORT的設備對象,。
2.初始化設備擴展結(jié)構(gòu),,保存設備對象指針到擴展結(jié)構(gòu)體中。
3.申請8字節(jié)內(nèi)核內(nèi)存構(gòu)建mdl,?,?what is mdl?,?保存SystemVirtualAddress到設備擴展,。
4.創(chuàng)建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);
 /*創(chuàng)建一個擴展結(jié)構(gòu)為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;
 }
 /*初始化設備擴展結(jié)構(gòu),保存設備對象指針到擴展結(jié)構(gòu)體中*/
 pDevExt = (PZT_DEVICE_EXTENSION )( deviceObject->DeviceExtension );
 RtlZeroMemory( pDevExt, sizeof( PZT_DEVICE_EXTENSION ) );


 pDevExt->fdo=deviceObject;


 ////////////////////////////////////////////////////////////
 /*申請8字節(jié)內(nèi)核內(nèi)存構(gòu)建mdl,?,?what is mdl?,?*/
 pDevExt->SystemVirtualAddress = ExAllocatePool(NonPagedPool, 8);
 pDevExt->MyMdl = IoAllocateMdl(pDevExt->SystemVirtualAddress, 8, FALSE, FALSE, NULL);
 MmBuildMdlForNonPagedPool(pDevExt->MyMdl);
 ///////////////////////////////////////////////////////////
 /*創(chuàng)建uniNameString符號鏈接uniDOSString*/
 status = IoCreateSymbolicLink (&uniDOSString, &uniNameString);


 if (!NT_SUCCESS(status))
 {
  return status;
 }
 /*設置設備對象標志,,緩沖IO*/
 deviceObject->Flags |= DO_BUFFERED_IO;


 /////////////////////////////////////////////////////
 return STATUS_SUCCESS;


}



/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/*驅(qū)動卸載函數(shù)*/
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
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");
 /*取得驅(qū)動對象的第一個設備對象指針*/
 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關聯(lián)的映射*/
  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數(shù)據(jù)結(jié)構(gòu)*/
        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派遣函數(shù):
ComSpy_Read
ComSpy_Write
ComSpy_IoCtl
ComSpy_Create
ComSpy_Close
ComSpy_DispatchPassThrough
ComSpy_Power
ComSpy_PnP
以ComSpy_Read為例,,這些函數(shù)都是設置好完成例程后直接轉(zhuǎn)發(fā)下一層驅(qū)動去處理。
1.如果調(diào)用此IRP函數(shù)的設備對象是\\Device\\ComSpy,,直接調(diào)用IOCtrl_前綴的函數(shù)處理,。
2.否則是無名DEVICEOBJ調(diào)用的IRP,得到設備擴展,,獲取當前IRP堆棧指針,。
3.拷貝當前IRP堆棧到下一層,設置IRP完成例程,。
4.調(diào)用下一層堆棧的驅(qū)動,。
5.下一層驅(qū)動完成IRP后原路返回,遇到完成例程,,調(diào)用它,,然后完成IRP.
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/*驅(qū)動read函數(shù)*/
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
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");
 /*如果調(diào)用此IRP函數(shù)的設備對象的類型是FILE_DEVICE_COMPORT,也就是\\Device\\ComSpy*/
 if(DeviceObject->DeviceType==FILE_DEVICE_COMPORT)
 {
    return IOCtrl_Read(DeviceObject,Irp);
 }


 /*否則是無名DEVICEOBJ調(diào)用的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
 /*調(diào)用下一層堆棧的驅(qū)動*/
    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完成狀態(tài)為成功,,且開始監(jiān)控標志已經(jīng)設置了的話,,
獲取當前irp堆棧指針
申請IO_REQ結(jié)構(gòu)內(nèi)存,標志req類型,,登記要拷貝的數(shù)據(jù)大小,,如果要拷貝的數(shù)據(jù)大小不為0,
從Irp->AssociatedIrp.SystemBuffer拷貝req->SizeCopied到req->pData
3.重新計算req大小到req->sizetotal
4.更新全局變量:g_szcount數(shù)據(jù)總大小
5.把req IO_REQ包插入鏈表g_data_lst
6.拷貝&g_szCount4字節(jié)到SystemVirtualAddress,,用來通知應用程序數(shù)據(jù)的大小,。
7.觸發(fā)事件通知應用程序。


/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/*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完成狀態(tài)為成功,,且開始監(jiān)控標志已經(jīng)設置了*/
    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結(jié)構(gòu)內(nèi)存*/
   
   req->type=REQ_READ;/*標志req類型*/
   req->SizeCopied=Irp->IoStatus.Information;/*要拷貝的數(shù)據(jù)大小*/


   if(req->SizeCopied)/*有數(shù)據(jù)要拷貝*/
   {
    req->pData=ExAllocatePool(NonPagedPool,req->SizeCopied);/*申請需要的內(nèi)存*/
    /*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數(shù)據(jù)總大小*/
   
   ExInterlockedInsertTailList(&g_data_lst, &(req->entry),&g_req_splock);/*插入鏈表*/
   /////////////////////////////////////////////////////
   memcpy(SystemVirtualAddress, &g_szCount, 4);/*拷貝&g_szCount4字節(jié)到SystemVirtualAddress*/
   
   DbgPrint("ComSpy ReadCompletion OK  Add Bytes  %x \n",req->SizeTotal); 


   KeSetEvent(gpEventObject,0,FALSE);/*觸發(fā)事件通知*/
   
 }
   
    return STATUS_SUCCESS;
}



下面看comspy這個和應用程序直接交互的設備對象。
無名設備通過完成例程把監(jiān)控的com口數(shù)據(jù)打包放入到鏈表,然后通知應用程序,,應用程序只能去讀取comspy這個設備,,
所以comspy的任務就是從鏈表讀取數(shù)據(jù)返回給應用程序。所以暫時不需要寫入,。
下面三個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()函數(shù)。
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:
獲取傳遞進來的緩沖區(qū)指針
將緩沖區(qū)的句柄賦值給hEvent(應用程序傳遞進來的同步用事件句柄),;
通過ObReferenceObjectByHandle輸入句柄,,返回事件對象gpEventObjectOBJ指針保存。
IO_DEREFERENCE_EVENT:
如果事件對象gpEvenObject存在,,引用計數(shù)減1
IO_SET_EVENT:設置事件gpEventObject
IO_CLEAR_EVENT:清除事件gpEventObject
IO_QUERY_EVENT_STATE:查詢事件,,獲取事件狀態(tài)送到應用程序
IO_GET_SHAREMEMORY_ADDR:/*獲取共享內(nèi)存地址*/
將mdl描述的物理pages映射到UserVirtualAddress
然后將此地址送回應用程序
IO_CLEAN_SHAREMEMORY_ADDR:/*清除共享內(nèi)存地址*/


/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/*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;/*獲取傳遞進來的緩沖區(qū)指針*/
  hEvent = (HANDLE) IrpStack->Parameters.DeviceIoControl.Type3InputBuffer;/*將緩沖區(qū)的句柄賦值給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存在,,引用計數(shù)減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:/*查詢事件,將結(jié)果放到outBuf*/
  DbgPrint("in KeReadStateEvent !\n");
  outBuf = (LONG*) Irp->UserBuffer;/*獲取應用程序的輸入緩沖*/
  *outBuf = KeReadStateEvent(gpEventObject);/*獲取事件狀態(tài)送到應用程序*/
  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:/*獲取共享內(nèi)存地址*/
  __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:/*清除共享內(nèi)存地址*/
   /////////////////////////////////////////
  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.鏈表是否空,,即有沒有數(shù)據(jù)可以讀取,如果讀數(shù)據(jù)隊列空,,完成IRP返回
3.獲取當前irp堆棧指針,、IO代碼、輸入緩存長度,、輸出緩存長度,,獲取用戶層傳遞的緩沖首址pOutBuf
4.從鏈表g_data_lst取IO_REQ包裹
5. 如果所請求數(shù)據(jù)小于一包長度(即傳遞進來的緩沖不夠容納一個包),重新把包插回鏈表,,返回IRP報告處理失敗,。
6.拷貝pReq所指數(shù)據(jù)到pOutBuf,大小為一個IO_REQ,,偏移pOutBuf指針,,拷貝IO_REQ包的數(shù)據(jù),pReq->pData到pOutBuf,
偏移pOutBuf指針,,nToReadBytes記錄數(shù)據(jù)大?。ò麵O_REQ結(jié)構(gòu)大小+pData所指數(shù)據(jù)大小,
更新全局變量g_szCount總數(shù)據(jù)大小,,釋放數(shù)據(jù),,釋放包,取下一個包數(shù)據(jù),,沒有下一個包了,,結(jié)束,跳出,,
取包的IO_REQ結(jié)構(gòu)指針,,直到要超過緩沖區(qū)的邊界了,跳出,,把多取的一包回送鏈表,。

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/*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 );/*鏈表是否空,,即沒數(shù)據(jù)可以讀取*/
 KeReleaseSpinLock( &g_req_splock, OldIrql );/**/
 
 if( bIsEmpty )/*讀數(shù)據(jù)隊列空,,完成IRP返回*/
 {
   DbgPrint(("------  數(shù)據(jù)隊列為空  --------\n"));


            status = STATUS_UNSUCCESSFUL;
   return CompleteRequest( Irp, status, 0 ); 


 }
 else/*否則數(shù)據(jù)隊列不為空*/
 {
  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);//取 讀數(shù)據(jù)
  ASSERT( link );/*檢查link參數(shù)*/


  pReq= CONTAINING_RECORD( link, IO_REQ, entry );/*從link取數(shù)據(jù)*/


  if(pReq->SizeTotal>OutputLength)/*讀取的數(shù)據(jù)比請求數(shù)據(jù)大*/
  {
   DbgPrint(("------  所請求數(shù)據(jù)小于一包長度  --------\n"));


   ExInterlockedInsertHeadList( &g_data_lst, link, &g_req_splock );//數(shù)據(jù)未讀完 回送至表頭
           
   status = STATUS_UNSUCCESSFUL;
   return CompleteRequest( Irp, status, 0 );/*完成IRP*/ 
  }
 /*否則pReq->SizeTotal<OutputLength*/
  nToReadBytes=0;/*nToReadBytes置0*/
  bEnd=FALSE;


  while(nToReadBytes + pReq->SizeTotal <= OutputLength)
  {
   /*拷貝pReq所指數(shù)據(jù)到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包的數(shù)據(jù),pReq->pData到pOutBuf*/
   pOutBuf+=pReq->SizeCopied;/*偏移pOutBuf指針*/


   nToReadBytes+=pReq->SizeTotal;/*nToReadBytes記錄數(shù)據(jù)大?。ò麵O_REQ結(jié)構(gòu)大?。玴Data所指數(shù)據(jù)大小*/
   
   g_szCount-=pReq->SizeTotal;/*更新全局變量g_szCount總數(shù)據(jù)大小*/


   ExFreePool(pReq->pData);/*釋放數(shù)據(jù)*/
   ExFreePool(pReq);/*釋放包*/


   link = ExInterlockedRemoveHeadList( &g_data_lst, &g_req_splock);//取下一個包數(shù)據(jù)
   if(link==NULL)
   {
    bEnd=TRUE;/*沒有下一個包了,結(jié)束,,跳出*/
    break;
   }


   ASSERT( link );
   pReq= CONTAINING_RECORD( link, IO_REQ, entry );/*取包的IO_REQ結(jié)構(gòu)指針*/


  }
  if(bEnd==FALSE)
  {
   //多取的一包回送表頭
   ExInterlockedInsertHeadList( &g_data_lst, link, &g_req_splock );
  }
  DbgPrint("------  實際請求數(shù)據(jù)長度  %x-------\n",nToReadBytes );


  status = STATUS_SUCCESS;
  DbgPrint(("--------      Exit ReadIrp routine   -----------\n"));


  return CompleteRequest( Irp, status, nToReadBytes ); 
 }


}



最后看IOCtrl_CreateClose,,在comspy創(chuàng)建和關閉的時候調(diào)用
主要是IRP_MJ_CREATE時候設置全局變量申明g_bStartMon=0x1;/*開始監(jiān)控*/
IRP_MJ_CLOSE時候結(jié)束監(jiān)控,釋放鏈表數(shù)據(jù),,完成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; // 返回狀態(tài)
    Irp->IoStatus.Information = 0;
 /*得到當前IRP堆棧指針*/   
 IrpStack = IoGetCurrentIrpStackLocation(Irp);
 /*判斷派遣函數(shù)*/
 switch (IrpStack->MajorFunction)
 {
  case IRP_MJ_CREATE: 
    DbgPrint("ComSpy IOCtrl (IRP_MJ_CREATE)...\n");
   g_bStartMon=0x1;/*開始監(jiān)控*/
   break;
  case IRP_MJ_CLOSE:
   g_bStartMon=0x0;/*結(jié)束監(jiān)控*/
    DbgPrint("ComSpy IOCtrl (IRP_MJ_CLOSE)...\n");
   /*釋放鏈表IO_REQ數(shù)據(jù)結(jié)構(gòu)*/
   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;
}

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多