縱覽: 在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; }
|