您的位置:首页 > 理论基础 > 计算机网络

驱动层 完成获取进程网络流量模块(总结)

2014-12-11 10:54 274 查看
xp平台下是使用TDI,win 7平台采用的是WFP的模式

WFP框架下思路

获取进程ID 获取进程的上传数据大小和下载数据大小,然后存储到链表中

链表中节点结构体如下:

typedef struct tagFlowInfoItem

{

/** 链表结构

*/

LIST_ENTRY m_listEntry;

/** 进程ID

*/

HANDLE m_processID;

/** 已上传流量,BYTE为单位

*/

UINT64 m_uploadFlow;

/** 已下载流量,BYTE为单位

*/

UINT64 m_downloadFlow;

/** 上传速度,BYTE为单位

*/

ULONG m_uploadSpeed;

/** 下载速度,BYTE为单位

*/

ULONG m_downloadSpeed;



/** 限制的上传速度,BYTE为单位

*/

ULONG m_limitUploadSpeed;

/** 限制的下载速度,BYTE为单位

*/

ULONG m_limitDownloadSpeed;

} FlowInfoItem;

wfp中是需要注册callout函数的,进程id是在FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4层来获取,而UDP和TCP流数据信息(比如大小,内容)是在FWPM_LAYER_DATAGRAM_DATA_V4和FWPM_LAYER_STREAM_V4层来获取的

,问题来了,在流注册的callout函数中我们可以获取到数据的大小,但是问题来了,怎么样把进程ID和对应的进程数据相对应???

//////////////////////////////////////////////////////////////////////////////////////////////////////

不断的查找资料,研究wdk文档,wdk示例,各种搜索和qq群请教,(*^__^*) 嘻嘻……

//////////////////////////////////////////////////////////////////////////////////////////////////////

最终发现wdk的示例中有相关的代码可以参考一下,

目录如下:C:\WinDDK\7600.16385.1\src\network\trans\msnmntr

主要是用到了一个FwpsFlowAssociateContext0函数,具体的用法看msdn或者示例代码使用,很简单

一定要很仔细的看哦,这个函数有个很需要注意的地方,不然就蓝蓝更健康了哦,(关于DeleteFn函数的注册和写法)

这个FwpsFlowAssociateContext0函数的作用就是把进程id从FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4层传递到了FWPM_LAYER_DATAGRAM_DATA_V4和FWPM_LAYER_STREAM_V4层,然后我们就可以使用链表结构把进程id和进程的数据关联起来了.

那么如何识别是上传数据还是下载数据呢?好问题

解析layerData中的streamData,streamData中有个标志位,

上传数据判断:

和系统定义的宏FWPS_STREAM_FLAG_SEND和FWPS_STREAM_FLAG_SEND_EXPEDITED与(&)操作一下,不就可以得到是否是上传了吗?

下载数据判断:

和上传数据的方法类似.

最后说一句,在操作链表的时候,记得加锁.

xp下比win7下要简单的多,而且TDI的资料也多.实现起来还是容易的多

VOID AnalyzeNetworkIrp(PIRP Irp)

{

PEPROCESS Process;

PIO_STACK_LOCATION IoStackLocation;

NETWORK_USAGE_INFORMATION NetworkUsageInformation;

//memset(&NetworkUsageInformation,0,sizeof(NETWORK_USAGE_INFORMATION));

IoStackLocation = IoGetCurrentIrpStackLocation(Irp);

ASSERT(IoStackLocation->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);



Process = PsGetCurrentProcess();



if (QueryProcessNetworkUsage(Process, &NetworkUsageInformation) == FALSE)

{

NetworkUsageInformation.BytesReceived = 0;

NetworkUsageInformation.BytesSent = 0;

}

if (IoStackLocation->MinorFunction == TDI_RECEIVE) // TDI_RECEIVE

{

DbgPrint("Enter TCP 接收!\n");

PTDI_REQUEST_KERNEL_RECEIVE Parameters;

Parameters = (PTDI_REQUEST_KERNEL_RECEIVE)&IoStackLocation->Parameters;

NetworkUsageInformation.BytesReceived += Parameters->ReceiveLength;

}

else if (IoStackLocation->MinorFunction == TDI_SEND) //TDI_SEND

{

DbgPrint("Enter TCP 发送!\n");

PTDI_REQUEST_KERNEL_SEND Parameters;

Parameters = (PTDI_REQUEST_KERNEL_SEND)&IoStackLocation->Parameters;

NetworkUsageInformation.BytesSent += Parameters->SendLength;

}

else if (IoStackLocation->MinorFunction == TDI_RECEIVE_DATAGRAM) //TDI_RECEIVE_DATAGRAM

{

DbgPrint("Enter UDP 接收!\n");

PTDI_REQUEST_KERNEL_RECEIVEDG Parameters;

Parameters = (PTDI_REQUEST_KERNEL_RECEIVEDG)&IoStackLocation->Parameters;

NetworkUsageInformation.BytesReceived += Parameters->ReceiveLength;

}

else if (IoStackLocation->MinorFunction == TDI_SEND_DATAGRAM) //TDI_SEND_DATAGRAM

{

DbgPrint("Enter UDP 发送!\n");

PTDI_REQUEST_KERNEL_SENDDG Parameters;

Parameters = (PTDI_REQUEST_KERNEL_SENDDG)&IoStackLocation->Parameters;

NetworkUsageInformation.BytesSent += Parameters->SendLength;

}

else if (IoStackLocation->MinorFunction == TDI_CONNECT) //本机向外界发起连接请求

{

DbgPrint("Enter Connect!\n");

PTDI_REQUEST_KERNEL_SENDDG Parameters;

Parameters = (PTDI_REQUEST_KERNEL_SENDDG)&IoStackLocation->Parameters;

NetworkUsageInformation.BytesSent += Parameters->SendLength;

}

else if (IoStackLocation->MinorFunction == TDI_ACCEPT)//外界向本机发起连接请求

{

DbgPrint("Enter Accept!\n");

PTDI_REQUEST_KERNEL_RECEIVEDG Parameters;

Parameters = (PTDI_REQUEST_KERNEL_RECEIVEDG)&IoStackLocation->Parameters;

NetworkUsageInformation.BytesReceived += Parameters->ReceiveLength;

}

// 更新进程的网络使用情况

UpdateProcessNetworkUsage(Process, &NetworkUsageInformation);

return;

}

VOID UpdateProcessNetworkUsage(

__in PEPROCESS Process,

__in PNETWORK_USAGE_INFORMATION NetworkUsageInformation

)

{

KLOCK_QUEUE_HANDLE LockHandle;

KeAcquireInStackQueuedSpinLock(&NetworkUsageGenericTable.TableLock,&LockHandle);

UpdateProcessNetworkUsageUnsafe(Process, NetworkUsageInformation);

KeReleaseInStackQueuedSpinLock(&LockHandle);

return;

}

VOID UpdateProcessNetworkUsageUnsafe(

__in PEPROCESS Process,

__in PNETWORK_USAGE_INFORMATION NetworkUsageInformation

)

{

NETWORK_USAGE_GENERIC_TABLE_NODE TableNode;

PVOID EntryFound;

TableNode.Process = Process;

TableNode.NetworkUsageInformation = *NetworkUsageInformation;

EntryFound = RtlLookupElementGenericTable(&NetworkUsageGenericTable.Table,

(PVOID)&TableNode);

if (EntryFound)

{

BOOLEAN Status;

Status = RtlDeleteElementGenericTable(&NetworkUsageGenericTable.Table, EntryFound);

ASSERT(Status == TRUE);

}

(VOID)RtlInsertElementGenericTable(&NetworkUsageGenericTable.Table,

(PVOID)&TableNode, sizeof(NETWORK_USAGE_GENERIC_TABLE_NODE), NULL);

return;

}

//网络使用情况结构体定义

typedef struct _NETWORK_USAGE_INFORMATION {

ULONGLONG BytesSent;

ULONGLONG BytesReceived;

} NETWORK_USAGE_INFORMATION, *PNETWORK_USAGE_INFORMATION;

typedef struct _NETWORK_USAGE_GENERIC_TABLE_NODE {

PEPROCESS Process;

//UINT32 uProcessID;

NETWORK_USAGE_INFORMATION NetworkUsageInformation;

} NETWORK_USAGE_GENERIC_TABLE_NODE, *PNETWORK_USAGE_GENERIC_TABLE_NODE;

typedef struct _NETWORK_USAGE_GENERIC_TABLE {

RTL_GENERIC_TABLE Table;

KSPIN_LOCK TableLock;

KSPIN_LOCK TrafficLock;

} NETWORK_USAGE_GENERIC_TABLE, *PNETWORK_USAGE_GENERIC_TABLE;

NETWORK_USAGE_GENERIC_TABLE NetworkUsageGenericTable;

思路如此,TDI的实现大家实现起来不难,我就不多说了,显得很唠叨烦人,嘿嘿
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: