做招聘网站需要做什么公司,桂林市是哪个省的,免费申请网站官网,妻子2018高清免费视频http://blog.csdn.net/charlesprince/article/details/5924376 TDI FILTER 过滤驱动的功能一般用来进行整个系统中的所有网络流量的分析#xff0c;记录和管理#xff0c;可以实现非常强大的管理功能#xff0c;这里就将讨论它的设计架构#xff0c;和具体实现的方法。 … http://blog.csdn.net/charlesprince/article/details/5924376 TDI FILTER 过滤驱动的功能一般用来进行整个系统中的所有网络流量的分析记录和管理可以实现非常强大的管理功能这里就将讨论它的设计架构和具体实现的方法。 进行系统级网络数据包的过滤很明显第一步需要在系统内核中截取到网络数据包那么在WINDOWS平台下应该如何实现这样的功能 在WINDOWS内核中数据的通信载体是IRP包如果希望截取到IRP数据包当然必须生成核模块以驱动的方式加载至内核之中。如果只是需要用来进行IRP数据包的截取进而进行数据的分析及下一步工作的控制。比较合适的方式就是使用TDI FILTER驱动的方式。 它在内核中的结构如图所示TDI FILTER ( 你的DRIVER ) TDI DRIVER ( AFD.SYS ) 附加至TDI设备的方法 在DriverEntry时生成两个设备将其附加至(Attach)至Tdi驱动的Udp和Tcp设备实现IRP包过滤功能具体代码如下 #define UDP_DEVICE_NAME L//Device//Udp
#define TCP_DEVICE_NAME L//Device//Tcp
#define TDI_FILTER_DEVICE_NAME L//Device//TdiFiltertypedef struct __TDI_FILTER_DEVICE_EXTENSION
{//过滤设备至少需要记录下真正Tdi网络设备的指针来调用真正的TDI设备功能。PDEVICE_OBJECT pTdiDeviceObject;
} TDI_FILTER_DEVICE_EXTENSION, *PTDI_FILTER_DEVICE_EXTENSION;DriverEntry( PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath )
{UNICODE_STRING TdiDeviceName;......RtlInitUnicodeString( ( PUNICODE_STRING )TdiDeviceName, UDP_DEVICE_NAME );ntStatus IoCreateDevice( DriverObject, sizeof( TDI_FILTER_DEVICE_EXTENSION ), //指定设备扩展长度NULL, FILE_DEVICE_NETWORK, //网络类型设备0, 0, DeviceObject ); //生成一个无名、网络类型设备附加至TDI TCP/UDP设备实现过滤功能。if( NT_SUCCESS( ntStatus ) ){DeviceObject-Flags | DO_DIRECT_IO; //生成新的页表将同样的用户内存空间映射至系统虚拟内存空间来进行通信ntStatus IoAttachDevice( DeviceObject, TdiDeviceName, ( PDEVICE_OBJECT* )DeviceObject-DeviceExtension //附加至的设备的指针将会输出至此参数中这样就将真正的TDI设备的指针记录在过滤设备的扩展中); }
} TDI驱动的组织结构分为两个部分 1.庞大的INTERNAL IO CONTROL子功能包括以下功能 TDI_ASSOCIATE_ADDRESS 可以通过它截取出自己和对端的套接字信息一般就是IP地址端口号可以在此IRP功能响应中进行套接字信息的记录。 TDI_DISASSOCIATE_ADDRESS 它的IRP包是在closesocket函数时发生的所以如果我们在 TDI_ASSOCIATE_ADDRESS中记录了信息需要在此IRP的功能响应中取消之前的记录。 TDI_CONNECT主动连接 TDI_LISTEN TDI_ACCEPT TDI_DISCONNECT TDI_SEND 它的IRP包是在调用send函数时发生的必然对它的响应将会实现对基于TCP协议的网络上传流量的截取。 TDI_RECEIVE 它的IRP包是在调用recv函数时发生的必然对它的响应将会实现对基于TCP协议的网络下载流量的截取。 TDI_SEND_DATAGRAM 它的IRP包是在调用sendto函数时发生的必然对它的响应将会实现对基于UDP协议的网络上传流量的截取。 TDI_RECEIVE_DATAGRAM 它的IRP包是在调用recvfrom函数时发生的必然对它的响应将会实现对基于UDP协议的网络下载流量的截取。 TDI_SET_EVENT_HANDLER 它的IRP包是在TDI驱动中注册一些回调用函数当接收到数据包时将会首先执行它们它的具体功能将会在下一步讲述。 TDI_QUERY_INFORMATION TDI_SET_INFORMATION TDI_ACTION TDI_DIRECT_SEND TDI_DIRECT_SEND_DATAGRAM 在TDI_SET_EVENT_HANDLER子功能中可以注册以下回调涵数 TDI_EVENT_CONNECT被动连接 TDI_EVENT_DISCONNECT TDI_EVENT_ERROR TDI_EVENT_RECEIVE 对应于recv函数有返回数据时将会调用此回调函数。 TDI_EVENT_RECEIVE_DATAGRAM 对应于recvfrom函数接收到数据时将会调用此回调函数。 TDI_EVENT_RECEIVE_EXPEDITED 对应于函数接收到带外数据时将会调用此回调函数。( 带外数也就是OOB数据, 在全部IRP数据包中会优先进行发送或接收TCP协议功能 ) TDI_EVENT_SEND_POSSIBLE 以下将讲述数据具体传输回调功能的过滤方法 4.实现事件回调函数挂钩的方法 响应IRP_MJ_INTERNAL_DEVICE_CONTROL中的TDI_SET_EVENT_HANDLER子功能记录下原始的注册事件回调函数和参数但真正注册的是自己的回调函数来截取所有的事件回调函数调用实现过滤功能。 具体代码如下 typedef struct __TDI_EVENT_CONTEXT_WRAP
{DWORD dwEventContextMark; //对自己生成的结构实例加一个四字节的标志可以不使用。DWORD dwEventType; //记录事件回调函数的类型PVOID pOrgEventHandler; //记录原始的事件回调函数PVOID pOrgEventContext; //记录原始的事件回调函数参数PFILE_OBJECT pAssocAddr; //记录事件回调函数所绑定的本机套接字PDEVICE_OBJEXT pDeviceObjext; //记录注册事件IRP所发送至的TDI设备
} TDI_EVENT_HANDLER_WRAP, *PTDI_EVENT_HANDLER_WRAP;typedef struct __TDI_EVENT_HANDLER_LINK
{LIST_ENTRY List; //将事件回调钩子记录以链表形式进行管理PTDI_EVENT_HANDLER_WRAP pTdiEventHandlerWrap;
} TDI_EVENT_HANDLER_LIST, *PTDI_EVENT_HANDLER_LIST;LIST_ENTRY g_TdiEventHandlerInfoList;NTSTATUS DeviceInternalIoControl( PDEVICE_OBJECT DeviceObject, PIRP Irp )
{PKIRQL OldIrql;PLIST_ENTRY pListEntry;PIO_STACK_LOCATION IrpSp;PTDI_EVENT_HANDLER_WRAP pTdiEventHandlerWrap;PTDI_EVENT_HANDLER_LIST pTdiEventHandlerList;PTDI_EVENT_HANDLER_WRAP pTdiEventHandlerWrap_;PTDI_EVENT_HANDLER_LIST pTdiEventHandlerList_;PTDI_FILTER_DEVICE_EXTENSION pTdiDeviceExtension; pTdiDeviceExtension ( PTDI_FILTER_DEVICE_EXTENSION )DeviceObject-DeviceExtension;switch( IrpSp-MinorFunction ){case TDI_SET_EVENT_HANDLER:pTdiSetEvent ( PTDI_REQUEST_KERNEL_SET_EVENT )pIrpSp-Parameters;if( TDI_EVENT_RECEIVE pTdiSetEvent-EventType )//|| TDI_EVENT_RECEIVE_EXPEDITED pTdiSetEvent-EventType || TDI_EVENT_CHAINED_RECEIVE pTdiSetEvent-EventType || TDI_EVENT_CHAINED_RECEIVE_EXPEDITED pTdiSetEvent-EventType || TDI_EVENT_RECEIVE_DATAGRAM pTdiSetEvent-EventType ){pTdiEventHandlerList NULL;pTdiEventHandlerWrap NULL;pProcessNetWorkTrafficInfo NULL;if( NULL pTdiSetEvent-EventHandler ){//注意如果注册的事件回调函数是NULL的话它表示的取消之前曾经注册过的事件回调函数, 这里当然不能挂钩可以加入释放钩子资源的操作。goto CALL_PDO_DRIVER;}KeAcquireSpinLock( g_SpLockTdiEventHandlerInfo, OldIrql ); //对事件回调函数钩子列表写操作加锁保护pListEntry g_TdiEventHandlerInfoList.Flink;for( ; ; ){if( pListEntry g_TdiEventHandlerInfoList ){pTdiEventHandlerWrap_ NULL;break;}pTdiEventHandlerList_ ( PTDI_EVENT_HANDLER_LIST )pListEntry;pTdiEventHandlerWrap_ pTdiEventHandlerList_-pTdiEventHandlerWrap;if( pTdiEventHandlerWrap_-pAssocAddr pFileObject pTdiEventHandlerWrap_-dwEventType dwEventType ) //如果此本机套接字对象的相应事件回调函数已经存在则直接对其进行修改就可以了而不是不断的新建事件件回调钩子{pTdiEventHandlerWrap_-pOrgEventHandler pEventHandler;pTdiEventHandlerWrap_-pOrgEventContext pEventContext;break;}}if( NULL pTdiEventHandlerWrap_ ) //没有找到加入新的事件回调函数钩子{pTdiEventHandlerWrap ( PTDI_EVENT_HANDLER_WRAP )ExAllocatePoolWithTag( NonPagedPool, sizeof( TDI_EVENT_HANDLER_WRAP ), 0 );if( NULL pTdiEventHandlerWrap ){goto RELEASE_RESOURCE;}pTdiEventHandlerList ( PTDI_EVENT_HANDLER_LIST )ExAllocatePoolWithTag( NonPagedPool, sizeof( TDI_EVENT_HANDLER_LIST ), 0 );if( NULL pTdiEventHandlerList ){goto RELEASE_RESOURCE;}pTdiEventHandlerWrap-dwEventContextMark TDI_EVENT_CONTEXT_MARK;pTdiEventHandlerWrap-dwEventType dwEventType;pTdiEventHandlerWrap-pOrgEventHandler pEventHandler;pTdiEventHandlerWrap-pOrgEventContext pEventContext;pTdiEventHandlerWrap-pAssocAddr pFileObject;pTdiEventHandlerWrap-pDeviceObject pTdiDeviceExtension-pTdiDeviceObject;pTdiEventHandlerList-pTdiEventHandlerWrap pTdiEventHandlerWrap;InsertTailList( g_TdiEventHandlerInfoList, pTdiEventHandlerList );}else{pTdiEventHandlerWrap pTdiEventHandlerWrap_;pTdiEventHandlerList pTdiEventHandlerList_;}KeReleaseSpinLock( g_SpLockTdiEventHandlerInfo, OldIrql ); //释放事件回调钩子列表锁if( TDI_EVENT_RECEIVE pTdiSetEvent-EventType || TDI_EVENT_RECEIVE_EXPEDITED pTdiSetEvent-EventType ){pTdiSetEvent-EventHandler TdiFilterRecvEventHandler; //加入自己的事件过滤回调函数}else if( TDI_EVENT_CHAINED_RECEIVE pTdiSetEvent-EventType ||TDI_EVENT_CHAINED_RECEIVE_EXPEDITED pTdiSetEvent-EventType ){pTdiSetEvent-EventHandler TdiFilterChainedRecvHandler;}else{pTdiSetEvent-EventHandler TdiFilterRecvDatagramEventHandler;}pTdiSetEvent-EventContext pTdiEventHandlerWrap;IoSkipCurrentIrpStackLocation( pIrp );ntStatus IoCallDriver( pDeviceExtension-pTdiDeviceObject, pIrp );if( !NT_SUCCESS( ntStatus ) ){if( NULL pTdiEventHandlerWrap_ ){//如果是新加入的事件回调函数钩子可以在出错时将其释放, 也可以保留至套接字关闭时再进行释放KeAcquireSpinLock( g_SpLockTdiEventHandlerInfo, OldIrql ); //对事件回调函数钩子列表写操作加锁保护RemoveEntryList( ( PLIST_ENTRY )pTdiEventHandlerList );ExFreePoolWithTag( pTdiEventHandlerWrap );ExFreePoolWithTag( pTdiEventHandlerList );KeReleaseSpinLock( g_SpLockTdiEventHandlerInfo, OldIrql ); //释放事件回调钩子列表锁}}return ntStatus;}break;default:goto CALL_PDO_DRIVER;break;}RELEASE_RESOURCE:if( NULL ! pTdiEventHandlerWrap ){ExFreePoolWithTag( pTdiEventHandlerWrap, NonPagedPool );}if( NULL ! pTdiEventHandlerList ){ExFreePoolWithTag( pTdiEventHandlerList, NonPagedPool );}CALL_PDO_DRIVER:IoSkipCurrentIrpStackLocation( pIrp );return IoCallDriver( pDeviceExtension-pTdiDeviceObject, pIrp );
} 以上对事件回调函数加入了钩子下一步必须考虑对其释放的问题否则当原始回调函数对应的套接字释放后你的系统将会崩溃以下为具体代码 在套接字关闭后要在IRP_MJ_CLEANUP功能函数中将相关的事件回调钩子释放掉 NTSTATUS TdiFilterCleanUp(PDEVICE_OBJECT DeviceObject, PIRP pIrp )
{NTSTATUS ntStatus;KIRQL OldIrql;PTDI_EVENT_HANDLER_LIST pTdiEventHandlerList;PTDI_EVENT_HANDLER_WRAP pTdiEventHandlerWrap;PFILE_OBJECT pFileObject;TDI_FILTER_DEVICE_EXTENSION *pDeviceExtension;PIO_STACK_LOCATION pIrpSp;pDeviceExtension ( TDI_FILTER_DEVICE_EXTENSION* )DeviceObject-DeviceExtension;pIrpSp IoGetCurrentIrpStackLocation( pIrp );pFileObject pIrpSp-FileObject;...//如果是主控制设备要将调用IoCompleteIrp完成Irp, 如果是过滤设备调用PDO设备驱动
IoSkipCurrentIrpStackLocation( pIrp );ntStatus IoCallDriver( pDeviceExtension-pTdiDeviceObject, pIrp );if( !NT_SUCCESS( ntStatus ) ){DebugPrintEx( CLEANUP_INFO,netmon TdiFilterCleanUp IoCallDriver return ERROR/n );return ntStatus;}//下一步释放套接字对应的事件回调钩子KeAcquireSpinLock( g_SpLockTdiEventHandlerInfo, OldIrql );FIND_LIST_AGAIN:pListEntry g_TdiEventHandlerInfoList.Flink;for( ; ; ){if( pListEntry g_TdiEventHandlerInfoList ){break;}pTdiEventHandlerList ( PTDI_EVENT_HANDLER_LIST )pListEntry;pTdiEventHandlerWrap pTdiEventHandlerList-pTdiEventHandlerWrap;if( pTdiEventHandlerWrap-pAssocAddr pFileObject ){RemoveEntryList( pListEntry );ExFreePoolWithTag( pTdiEventHandlerWrap, 0 );ExFreePoolWithTag( pTdiEventHandlerList, 0 );goto FIND_LIST_AGAIN;}pListEntry pListEntry-Flink;}KeReleaseSpinLock( g_SpLockTdiEventHandlerInfo, OldIrql );return ntStatus;
} 那么可以在事件回调过滤钩子函数对数据进行处理了 NTSTATUS TdiFilterRecvEventHandler( IN PVOID TdiEventContext,IN CONNECTION_CONTEXT ConnectionContext,IN ULONG ReceiveFlags,IN ULONG BytesIndicated,IN ULONG BytesAvailable,OUT ULONG *BytesTaken,IN PVOID Tsdu,OUT PIRP *IoRequestPacket)
{NTSTATUS ntStatus;PIO_STACK_LOCATION pIrpSp;PTDI_EVENT_HANDLER_WRAP pEventHandlerWrap;PTDI_COMPLETION_WRAP pCompletionWrap;LARGE_INTEGER RecvedDataSize;pEventHandlerWrap ( PTDI_EVENT_HANDLER_WRAP )TdiEventContext;if( FALSE g_bFiltering ) //是否进行过滤{goto CALL_ORIGINAL_EVENT_HANDLER;}if( FALSE ! bStopRecv ){ ntStatus STATUS_DATA_NOT_ACCEPTED;goto RELEASE_PROCESS_IO_INFO_RETURN;}ntStatus ( ( ClientEventReceive )pEventHandlerWrap-pOrgEventHandler )( pEventHandlerWrap-pOrgEventContext, ConnectionContext, ReceiveFlags, BytesIndicated, BytesAvailable, BytesTaken, Tsdu, IoRequestPacket );if( NULL ! BytesTaken 0 ! *BytesTaken ){//这里对数据进行处理, 比如可以进行通信数据量的统计}if( STATUS_MORE_PROCESSING_REQUIRED ! ntStatus ){goto RELEASE_PROCESS_IO_INFO_RETURN;}if( NULL *IoRequestPacket ){goto RELEASE_PROCESS_IO_INFO_RETURN;}//IoRequestPacket表示当前接收IRP中的数据如果并不完整, 并且认为接下来的数据是有价值需要接收的话那么需要自己新建一个IRP包将其指针传入此参数中并返回STATUS_MORE_PROCESSING_REQUIRED通知IO管理不终止此IRPTDI驱动将继续接收接下来的数据。//所以如果此IRP包存在可以截取它的信息具体方法下一步讲述。return ntStatus;CALL_ORIGINAL_EVENT_HANDLER:return ( ( ClientEventReceive )pEventHandlerWrap-pOrgEventHandler )( //直接调用原始的IRP钩子函数不进行处理pEventHandlerWrap-pOrgEventContext, ConnectionContext, ReceiveFlags, BytesIndicated, BytesAvailable, BytesTaken, Tsdu, IoRequestPacket);
} 上面讲述了使用事件回调函数钩子的方式进行通信数据的截取方法下面讲述直接IRP包数据传输方式也就是以下4个子功能的截取方法 TDI_SEND TDI_RECEIVE TDI_SEND_DATAGRAM TDI_RECEIVE_DATAGRAM 在IRP_MJ_INTERNAL_DEVICE_CONTROL函数中响应以上子功能时确认参数DeviceObject为TDI过滤设备对所有截取到的IRP加入自己的完成函数在此IRP被完成时( 调用IoCompleteRequest )此完成函数被调用取得IRP处理的返回结果进行处理。具体数据的处理对应于TDI_SEND子功能可以在IoCallDriver之前得到因为它是应用程序传给你的而TDI_RECEIVE子功能应该在TDI事件回调函数或Completion回调函数中取得。相关代码如下 typedef struct __TDI_COMPLETION_WRAP
{...//可以加入用来记录/处理数据的成员, 比如通信标志, 流量统计等PIO_COMPLETION_ROUTINE pCompletionRoutine;LPVOID pContext;
} TDI_COMPLETION_WRAP, *PTDI_COMPLETION_WRAP; 加入自定义的CompletionRoutine的方法 if( TDI_SEND MinorFunction ||TDI_SEND_DATAGRAM MinorFunction || TDI_RECEIVE MinorFunction || TDI_RECEIVE_DATAGRAM MinorFunction )
{if( TDI_RECEIVE MinorFunction TDI_RECEIVE_PEEK ( ULONG )pIrpSp-Parameters.Others.Argument2 ){//TDI_RECEIVE_PEEK不会真正接收数据可以不需要对其进行过滤。goto SKIP_CURRENT_STACK_LOCATION;}pCompletionWrap ( PTDI_COMPLETION_WRAP )ExAllocateFromNPagedLookasideList( g_CompletionWrapList ); //可以使用链表或HASH等数据结构来管理所有的CompletionRoutine包装信息这里使用了NPAGED_LOOKASIDE_LIST它的优势在于系统中所有的NPAGED_LOOKASIDE_LIST资源的最大占用量将会被内存管理器动态管理if( NULL pCompletionWrap ){goto SKIP_CURRENT_STACK_LOCATION;}//这里可以设置CompletionRoutine的具体工作参数比如具体操作的类型原始的Completion函数等在用户层传送至的IRP中是不会设置CompletionRoutine函数的但其它驱动传送至的IRP中可能会进行设置如在Receive事件回调函数中的IoRequestPacket参数IoCopyCurrentIrpStackLocationToNext( pIrp ); //设置下一个设备栈工作参数
IoSetCompletionRoutine( pIrp, TdiFilterCompletion, pCompletionWrap, TRUE, TRUE, TRUE);//这里就为这个IRP加入自己的CompletionRoutine函数goto CALL_PDO_DRIVER;SKIP_CURRENT_STACK_LOCATION:IoSkipCurrentIrpStackLocation( pIrp );CALL_PDO_DRIVER:return IoCallDriver( pDeviceExtension-pTdiDeviceObject, pIrp );
} 具体的Completion函数的工作: NTSTATUS TdiFilterCompletion( PDEVICE_OBJECT pDeviceObject, PIRP pIrp, LPVOID pContext )
{NTSTATUS ntStatus;PTDI_COMPLETION_WRAP pCompletionWrap;LARGE_INTEGER TransferredDataSize;PIRP pMasterIrp;PIO_STACK_LOCATION pIrpSp;ntStatus pIrp-IoStatus.Status;pCompletionWrap ( PTDI_COMPLETION_WRAP )pContext;if( NT_SUCCESS( ntStatus ) ){//可以在这里对成功传输的数据进行处理}//这里可以调用原始的Completion函数RETURN_SUCCESS:return ntStatus;
} 需要注意的是如果为IRP包加入了CompletionRoutine之后那么在驱动卸载( Unload )之前必须保证所有IRP已经执行过此Completion函数, 如果在驱动被从内存中卸载后才执行, 将会使系统崩溃。处理方法为 1.不实现DriverUnload函数使驱动只有在系统关闭底层设备被卸载时才能完成真正的卸载。这是的一般 FILTER驱动的工作方式 2.使用线程同步的方法保证Completion函数的执行Windows XP或之后的系统也提供了一个API, SetCompletionRoutineEx来保证驱动在Completion函数完成前不被卸载。 至此讲述TDI过滤驱动组织框架可以为它添加一些更加完善的功能。 转载于:https://www.cnblogs.com/himessage/archive/2013/01/15/2860834.html