標籤:style io ar os 使用 sp for on 資料
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的實現大家實現起來不難,我就不多說了,顯得很嘮叨煩人,嘿嘿
驅動層 完成擷取進程網路流量模組(總結)