`

Windows Vista 核心网络过滤

阅读更多

 Windows Vista(简称Vista),是微软公司推出的最新的客户端操作系统,内部名称Windows NT 6.0。相对于Windows NT 5.x,其网络结构变化非常大,原有的TDI,NDIS系统挂接方法不再适用。(修改自nrworld.com 作者匿名)

 
  在Vista系统中,微软引入了两种新的网络过滤系统,WFP和 NDISfilter。由于WFP和NDIS系统十分庞大,本文从个人防火墙的技术需求出发详细叙述需要的技术细节,其他更多的内容,请参阅微软相关文档。(转载请注明wsdgs)
 
一、 WFP (Windows Filtering Platform)

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.

  其包含从用户态到核心态的一系列应用层,根据需要可以在某一层设置回调函数拦截数据。
  1、 callout callout是WFP系统提供的扩展其功能的一种机制,callout由一组callout函数组成,每组有三种函数, ClassifyFunction,处理收到的网络数据,例如端口号IP地址等。NotifyFunction,处理加载、删除callout事件。 FlowDeleteFunction,删除层与层之间关联的上下文。 callout由callout驱动具体实现,每个驱动可以注册多个callout。 
  2、WFP的层和层数据WFP有很多层,每一层分成若干子层,具体有哪些请参阅微软文档,我以FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4层为例进行讲解。这层位于ALE层,是其子层之一。面向连接的应用程序准备连接,面向无连接的程序准备通信,都发生在这一层。如果在这里拒绝了上述操作,应用程序就不能访问网络,这类似以前的TDI程序的Create事件,就是应用程序访问网络的请求刚到协议栈还没有处理。WFP每一层都有其特定的数据,根据这些数据又有特定的过滤条件,例如这层包括FWPS_METADATA_FIELD_PROCESS_ID类型数据,这个类型由UINT64类型数据定义,表示和本次网络访问请求相关的进程ID,可是FWPS_LAYER_INBOUND_IPPACKET_V4层就不包括这一类型的数据,其实 FWPS_LAYER_INBOUND_IPPACKET_V4已经到了IP层,这里进程ID已经没用了。因此在 FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4层可以以进程ID作为过滤条件,而到了 FWPS_LAYER_INBOUND_IPPACKET_V4层就不能用进程ID作为过滤条件了。每一层都有哪些数据类型,根据这些数据有哪些过滤条件可用,请参阅微软的WFP文档层标识符等章节。综上,WFP系统很像一个已经有了数据过滤引擎的防火墙,但是没有规则。我们编写用户层的程序给WFP引擎设置规则,编写核心态的callout驱动处理 WFP抓到的网络数据包。根据微软的文档所示,WFP能够到达IP层,如果我们想进行MAC层的处理,就必须利用NDISfilter驱动。
 
  3、应用WFP实现应用程序访问网络时提示这是个人防火墙的基本功能之一,当有应用程序访问网络时询问用户是否允许。首先我们编写一个callout驱动,用来处理WFP抓到的网络数据。由于 WFP抓到的数据只送到callout驱动不会送到用户层程序,所以这里必须用驱动根据数据判定放行还是阻止。Callout驱动向系统注册 callout函数:
 
FWPS_CALLOUT0 sCallout;
sCallout.calloutKey = *calloutKey;
sCallout.flags = flags;
sCallout.classifyFn = ClassifyFunction;//MonitorCoFlowEstablishedCalloutV4
sCallout.notifyFn = NotifyFunction; sCallout.flowDeleteFn = FlowDeleteFunction;
status = FwpsCalloutRegister0(deviceObject, &sCallout, calloutId);
 
FWPS_CALLOUT0结构用来组织一组callout函数,之后用FwpsCalloutRegister0函数注册。这里详细介绍下ClassifyFunction函数,这个函数主要处理网络数据包,
 
NTSTATUS MonitorCoFlowEstablishedCalloutV4
(IN const FWPS_INCOMING_VALUES0* inFixedValues,//WFP传进来的本层特有的数据
 IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,//本层相关的扩展数据
 IN VOID* packet,
 IN const FWPS_FILTER0* filter,
 IN UINT64 flowContext,
 OUT FWPS_CLASSIFY_OUT0* classifyOut//用这个结构里的字段告知WFP对数据包做出处理
)
{
 NTSTATUS status = STATUS_SUCCESS;
 UINT64 flowHandle;
 UINT64 flowContextLocal;
 UINT32 index;
 UINT32 LocalIPADDRv4,remoteIPADDRv4;
 USHORT LocalPort,remotePort;
 UNREFERENCED_PARAMETER(packet);
 UNREFERENCED_PARAMETER(filter);
 UNREFERENCED_PARAMETER(flowContext);
 index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS;
 LocalIPADDRv4 = inFixedValues->incomingValue[index].value.uint32;
 index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_PORT;
 LocalPort = inFixedValues->incomingValue[index].value.uint16;
 index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_ADDRESS;
 remoteIPADDRv4 = inFixedValues->incomingValue[index].value.uint32;
 index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_PORT;
 remotePort = inFixedValues->incomingValue[index].value.uint16;
 DbgPrint("BaseTDI: LocalIP %lx LocalPort %d \n remoteIP %lx remotePort %d",LocalIPADDRv4,LocalPort, remoteIPADDRv4,remotePort);
 DbgPrint("BaseTDI: PID %d ,PID's PATH %s",inMetaValues->processId,inMetaValues->processPath->data); DbgPrint("\n");
 if (monitoringEnabled)
 { //访问规则代码,在这里通知用户态程序
  AskUser(LocalIP, LocalPort, remoteIP, remotePort, PID);
  If classifyOut->actionType = FWP_ACTION_PERMIT;//允许发送或接收
  else classifyOut->actionType = FWP_ACTION_BLOCK; //不允许发送或接收
 }
 return status;
 
在完成callout驱动后,下面介绍用户态程序如何设置WFP系统。
 
设置的大体流程如下,主要代码讲解,
 

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;
 }
}

分享到:
评论

相关推荐

    寒江独钓-Windows内核安全编程(高清完整版).part4

    全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的核心组件的具体编程。...

    寒江独钓-Windows内核安全编程(高清完整版).part7

    全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的核心组件的具体编程。...

    寒江独钓-Windows内核安全编程(高清完整版).part1

    全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的核心组件的具体编程。...

    寒江独钓-Windows内核安全编程(高清完整版).part5

    全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的核心组件的具体编程。...

    寒江独钓-Windows内核安全编程(高清完整版).part6

    全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的核心组件的具体编程。...

    寒江独钓-Windows内核安全编程(高清完整版).part2

    全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的核心组件的具体编程。...

    寒江独钓-Windows内核安全编程(高清完整版).part3

    全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的核心组件的具体编程。...

    最新版Radmin3.4完美破解版-隐藏任务栏图标

     2.Radmin支持被控端以服务的方式运行、支持多个连接和IP 过滤(即允许特定的IP控制远程机器)、个性化的档互传、远程关机、支持高分辨率模式、基于Windows NT的安全支持及密码保护以及提供日志文件支持等。...

    ess_nt32_chs

    对 Windows 安全中心(包括 Vista)进行优化 个人防火墙 个人防火墙监视受保护的计算机和网络中其它计算机之间的所有通信。ESET 个人防火墙包含下列高级功能。 功能 说明 低层网络通信扫描 能够扫描数据...

    破解版为最新完美版。支持WIN7隐藏任务栏图标

     2.Radmin支持被控端以服务的方式运行、支持多个连接和IP 过滤(即允许特定的IP控制远程机器)、个性化的档互传、远程关机、支持高分辨率模式、基于Windows NT的安全支持及密码保护以及提供日志文件支持等。...

    免费开源的 RSS 订阅器 QuiteRSS 0.19.3 中文绿色免费版.zip

    如果您习惯使用 RSS 来阅读新闻,那说明您一定是相当关注新闻的及时性或阅读的效率。QuiteRSS 是一个功能丰富、易于使用,并且开源免费的...支持 Windows XP、Vista、Win7、Win8、Win8.1、Win10 等平台,支持简体中文。

    Xplorer2 功能强大资源管理器(带序列号)

    1,在两个面板的文件夹绝对路径上右击任何一级目录可以快速跳转,当你访问一个具有大量文件夹的文件夹时(如system32),可以用来列出目录,这和windows vista和7的功能是一样的,不过这个更加好用。 2,扩展名过滤...

    IIS6.0 IIS,互联网信息服务

    同Windows XP一样,在Windows Vista的默认设置下,IIS (Internet 信息服务) 7.0未予安装,要想使用它,必须首先安装IIS。下面简单介绍IIS的安装过程: 依次点击“开始” =&gt; “控制面板” =&gt; “程序”,选择“打开或...

    OneKey Ghost Y5.0 正式版(版本号:5.0.10.19)

    1、默认核心是 Ghost 11.0.2,可自定义 Ghost 版本 2、程序默认对当前系统所在分区进行备份、还原操作,可选择其他分区 3、本程序纯绿色,不会给系统留下任何临时文件 4、备份时可选压缩方式、默认为快速压缩 5、可...

Global site tag (gtag.js) - Google Analytics