纵览:
在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条评论)
登录后参与讨论