Windows Vista(简称Vista),是微软公司推出的最新的客户端操作系统,内部名称Windows NT 6.0。相对于Windows NT 5.x,其网络结构变化非常大,原有的TDI,NDIS系统挂接方法不再适用。(修改自nrworld.com 作者匿名)
Windows Filtering Platform (WFP) is a set of API and system services that provide a platform for creating firewalls. WFP API allows developers to create code that interacts with the filtering that takes place at several layers in the networking stack and throughout the operating system.
WFP integrates with and provides support for firewall features such as authenticated communication and dynamic firewall configuration based on applications' use of sockets API (application-based policy). Windows Filtering Platform is a development platform and not a firewall itself.
WFPAppAddCallouts()//向WFP系统添加callout DWORD
{
FWPM_CALLOUT0 callout;
DWORD result;
FWPM_DISPLAY_DATA0 displayData;
HANDLE engineHandle = NULL;
FWPM_SESSION0 session; //初始化一次会话
RtlZeroMemory(&session, sizeof(FWPM_SESSION0));
session.displayData.name= L"TEMP WFP Session";
session.displayData.description = L"For Adding callouts";//创建WFP引擎句柄
result = FwpmEngineOpen0( NULL, RPC_C_AUTHN_WINNT, NULL, &session, &engineHandle );
if (NO_ERROR != result) {goto cleanup;} //开始与引擎交互
result = FwpmTransactionBegin0(engineHandle, 0);
if (NO_ERROR != result) {goto abort; } //ADD CALLOUT
RtlZeroMemory(&callout, sizeof(FWPM_CALLOUT0));
displayData.description = MONITOR_FLOW_ESTABLISHED_CALLOUT_DESCRIPTION;
displayData.name = MONITOR_FLOW_ESTABLISHED_CALLOUT_NAME;
callout.calloutKey = TEMP_MONITOR_FLOW_ESTABLISHED_CALLOUT_V4;
callout.displayData = displayData;
callout.applicableLayer = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
callout.flags = FWPM_CALLOUT_FLAG_PERSISTENT; //flags置这个标志表示callout始终被WFP加载
result = FwpmCalloutAdd0(engineHandle, &callout, NULL, NULL);
if (NO_ERROR != result) {goto abort; } //结束本次会话
result = FwpmTransactionCommit0(engineHandle);
if (NO_ERROR == result) {;} goto cleanup; abort: //说明本次会话失败
result = FwpmTransactionAbort0(engineHandle);
if (NO_ERROR == result) {;} cleanup: //关闭引擎
if (engineHandle) { FwpmEngineClose0(engineHandle); }
return result;
}
WFPAppAddFilters(IN HANDLE engineHandle/*,IN FWP_BYTE_BLOB* applicationPath*/) //向WFP系统添加filter DWORD
{
DWORD result = NO_ERROR;
FWPM_SUBLAYER0 monitorSubLayer;
FWPM_FILTER0 filter;
FWPM_FILTER_CONDITION0 filterConditions[1]; //需要几条规则就定义几条 //初始化过滤条件
RtlZeroMemory(filterConditions, sizeof(filterConditions));
filterConditions[0].fieldKey = FWPM_CONDITION_IP_PROTOCOL;//所有IP协议数据
filterConditions[0].matchType = FWP_MATCH_GREATER_OR_EQUAL;//匹配度,大于,小于,大于等于…
filterConditions[0].conditionValue.type = FWP_UINT8;
filterConditions[0].conditionValue.uint8 = IPPROTO_IP;
RtlZeroMemory(&monitorSubLayer, sizeof(FWPM_SUBLAYER0));//初始化子层
monitorSubLayer.subLayerKey = TEMP_MONITOR_SUBLAYER;
monitorSubLayer.displayData.name = L"TEMP Monitor Sub layer";
monitorSubLayer.displayData.description = L"TEMP Monitor Sub layer";
monitorSubLayer.flags = 0;//FWMP_SUBLAYER_FLAG_PERSISTENT; // We don't really mind what the order of invocation is.
monitorSubLayer.weight = 0; //与WFP引擎开始一次会话
result = FwpmTransactionBegin0(engineHandle, 0);
if (NO_ERROR != result) {goto abort;} //增加一个子层
result = FwpmSubLayerAdd0(engineHandle, &monitorSubLayer, NULL);
if (NO_ERROR != result) {goto abort;} //FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4
RtlZeroMemory(&filter, sizeof(FWPM_FILTER0));
filter.layerKey = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
filter.displayData.name = L"Flow established filter.";
filter.displayData.description = L"Sets up flow for traffic that we are interested in.";
filter.action.type = FWP_ACTION_CALLOUT_INSPECTION; //表示把符合条件数据包交给callout处理
filter.action.calloutKey = TEMP_MONITOR_FLOW_ESTABLISHED_CALLOUT_V4;
filter.filterCondition = filterConditions;
filter.subLayerKey = monitorSubLayer.subLayerKey;
filter.weight.type = FWP_EMPTY; //系统自动设置weight。weight值越大加载越靠前
filter.numFilterConditions = 1;//过滤条件数
result = FwpmFilterAdd0(engineHandle, &filter, NULL, &(filterID[0]));
if (NO_ERROR != result) {goto abort;} //结束本次会话
result = FwpmTransactionCommit0(engineHandle);
if (NO_ERROR == result) {;} goto cleanup; abort: //说明本次会话失败
result = FwpmTransactionAbort0(engineHandle);
if (NO_ERROR == result) {;} cleanup: return result;
}
二、NDISfilter NDISfilter是利用系统提供的NDIS过滤引擎,获得MAC级别的网络数据包(这里可以看出WFP,NDISfilter,还有本文未提到的 FileSystemMiniFilter,他们都是利用了微软提供的过滤引擎,向其注册回调函数,得到数据后处理)。关键代码说明,其中的详细数据结构请参阅微软文档NDISfilter一节,
NDIS_FILTER_DRIVER_CHARACTERISTICS FChars;
NdisZeroMemory(&FChars, sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS));
FChars.Header.Type = NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;
FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS);
FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1;
FChars.MajorNdisVersion = FILTER_MAJOR_NDIS_VERSION;
FChars.MinorNdisVersion = FILTER_MINOR_NDIS_VERSION;
FChars.MajorDriverVersion = 1;
FChars.MinorDriverVersion = 0;
FChars.Flags = 0;
FChars.FriendlyName = FriendlyName;
FChars.UniqueName = UniqueName;
FChars.ServiceName = ServiceName;
FChars.SetOptionsHandler = FilterRegisterOptions;
FChars.AttachHandler = FilterAttach;//如果是我们想挂接的网络介质,就在这里通知系统挂接
FChars.DetachHandler = FilterDetach;
FChars.RestartHandler = FilterRestart;
FChars.PauseHandler = FilterPause;
FChars.SetFilterModuleOptionsHandler = FilterSetModuleOptions;
FChars.OidRequestHandler = FilterOidRequest;
FChars.OidRequestCompleteHandler = FilterOidRequestComplete;
FChars.CancelOidRequestHandler = FilterCancelOidRequest;
FChars.SendNetBufferListsHandler = FilterSendNetBufferLists;//发送回调函数
FChars.ReturnNetBufferListsHandler = FilterReturnNetBufferLists;
FChars.SendNetBufferListsCompleteHandler = FilterSendNetBufferListsComplete;
FChars.ReceiveNetBufferListsHandler = FilterReceiveNetBufferLists;//接收回调函数
FChars.DevicePnPEventNotifyHandler = FilterDevicePnPEventNotify;
FChars.NetPnPEventHandler = FilterNetPnPEvent;
FChars.StatusHandler = FilterStatus;
FChars.CancelSendNetBufferListsHandler = FilterCancelSendNetBufferLists;
NDIS_FILTER_DRIVER_CHARACTERISTICS这个结构用来组织NDISfilter功能函数供NDIS系统回调,例如 FilterSendNetBufferLists,发送数据回调函数,NDIS发送MAC帧时回调这个函数,相应数据可以在这个函数里得到处理,之后还给NDIS系统继续处理。
VOID FilterSendNetBufferLists( IN NDIS_HANDLE FilterModuleContext, IN PNET_BUFFER_LIST NetBufferLists, IN NDIS_PORT_NUMBER PortNumber, IN ULONG SendFlags )
{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PNET_BUFFER_LIST CurrNbl;
BOOLEAN DispatchLevel; //这里开始分析PNET_BUFFER_LIST指向的网络数据,并显示如何获得MAC地址
PNET_BUFFER_LIST pNetBufList,pNextNetBufList;
PMDL pMdl;
PNDISPROT_ETH_HEADER pEthHeader = NULL;
ULONG TotalLength,Offset,BufferLength; pNetBufList = NetBufferLists;
while (pNetBufList != NULL)
{
pNextNetBufList = NET_BUFFER_LIST_NEXT_NBL (pNetBufList); //得到当前和包相关的MDL,MDL里即MAC帧,详细的NET_BUFFER_LIST结构请参阅微软相关文档
pMdl = NET_BUFFER_CURRENT_MDL(NET_BUFFER_LIST_FIRST_NB(pNetBufList));
TotalLength = NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(pNetBufList));
Offset = NET_BUFFER_CURRENT_MDL_OFFSET(NET_BUFFER_LIST_FIRST_NB(pNetBufList));
BufferLength = 0;
do
{
ASSERT(pMdl != NULL);
if (pMdl)
{
NdisQueryMdl( pMdl, &pEthHeader, &BufferLength, NormalPagePriority);
}
if (pEthHeader == NULL)
{
BufferLength = 0; break;
}
if (BufferLength == 0){ break;}
ASSERT(BufferLength > Offset);
BufferLength -= Offset;
pEthHeader = (PNDISPROT_ETH_HEADER)((PUCHAR)pEthHeader + Offset);
DbgPrint("DstMAC %x-%x-%x-%x-%x-%x",pEthHeader->DstAddr[0], pEthHeader->DstAddr[1],pEthHeader->DstAddr[2], pEthHeader->DstAddr[3],pEthHeader->DstAddr[4], pEthHeader->DstAddr[5]);
DbgPrint("srcMAC %x-%x-%x-%x-%x-%x",pEthHeader->SrcAddr[0], pEthHeader->SrcAddr[1],pEthHeader->SrcAddr[2], pEthHeader->SrcAddr[3],pEthHeader->SrcAddr[4], pEthHeader->SrcAddr[5]);
DbgPrint("\n");
if (BufferLength < sizeof(NDISPROT_ETH_HEADER)) { break;}
}
while (FALSE);
pNetBufList = pNextNetBufList;
}
}