WFP防火墙的作用
WFP防火墙是在Vista/Win2008之后的操作系统中才引入的一套流量管控平台。提供一套API接口供开发人员调用。应用层和驱动层都有不同的模块可以调用。用于取代之前的LSP过滤器、TDI过滤器、NDIS过滤器等。通过WFP API,可以实现防火墙、网络管控工具等流量管控服务。
使用WFP防火墙时注意的事项
- WFP防火墙仅在Vista/Win 2008以后的系统中方可生效。
- 在Vista/Win 2008中,过滤器的添加不支持"或"策略。如果需求中包含对个IP段、多个端口号、多个协议或多个进程同时存在时,在Vista/Win2008中,需要依次进行较为复杂的交叉匹配,依次添加。这一点需要注意。只有在Win7/Win2008 R2系统中,WFP防火墙才能直接添加策略运行。
基本概念以及决策逻辑
- Layer(层):层是过滤器的容器,其功能是将过滤器组织成为集合,由层ID决定过滤器生效的位置。每一个层里面都包含一套内置的子层,用户可以添加自定义的子层。
- SubLayer(子层):过滤器的容器,在对应的层中生效。
- Filter(过滤器):过滤器是对出/入数据包进行匹配的规则。过滤器负责告诉过滤引擎如何处理数据包。添加过滤器时,使用FWPM_FILTER0结构体中的flags参数,可以指定过滤器的生效时间。
Layer(层)的过滤决策策略:
- 按照权重由高到低的顺序对每个子层进行决策匹配
- 即使有更高优先级的子层决定阻塞流量,下方的子层也会依次得到评估的机会。所以,每个子层都可以匹配到通过当前层的所有数据包
- 如果有一个子层明确返回阻断,当前层的决策即为阻断。(这里只谈应用层的决策策略,在Callout驱动层中,返回阻断,依然会被其它策略所修改,放在以后讨论。)
SubLayer(子层)的过滤决策策略:
- 按照权重从高到底的顺序对每个过滤器进行匹配
- 在匹配的过程中,如果有过滤器明确返回了"Permit"或"Block",则马上中断匹配,权重更低的过滤器不会收到数据包的信息。如果所有过滤器都返回"Continue",则会一直匹配到列表耗尽。
- 最后一个执行匹配的过滤器返回值,即为当前子层最终的过滤决策。
常用的随手便签
netsh wfp show state
该命令可以打印系统中当前存活的WFP防火墙层、子层、过滤器等。是在调试的过程中最实用的命令,也许没有之一。
调用流程
打开与关闭WFP防火墙
打开防火墙句柄
DWORD FwpmEngineOpen0(
const wchar_t *serverName,
UINT32 authnService,
SEC_WINNT_AUTH_IDENTITY_W *authIdentity,
const FWPM_SESSION0 *session,
HANDLE *engineHandle
);
- 输入参数
- serverName:必须为空。
- authnService:身份验证方式,可选为RPC_C_AUTHN_WINNT和RPC_C_AUTHN_DEFAULT。
- authIdentity:身份验证和授权凭证,可以为NULL。
- session:会话指针,不使用的话可以为NULL。
- engineHandle:用于输出防火墙引擎句柄,其它对防火墙操作的函数大都依赖此句柄。
- 输出参数
- ERROR_SUCCESS为成功,其它参考错误码
关闭防火墙句柄
DWORD FwpmEngineClose0(
HANDLE engineHandle
);
- 输入参数
- engineHandle:防火墙引擎句柄,由FwpmEngineOpen0参数返回
- 输出参数
- ERROR_SUCCESS为成功,其它参考错误码
枚举当前所有层
创建层枚举句柄
DWORD FwpmLayerCreateEnumHandle0(
HANDLE engineHandle,
const FWPM_LAYER_ENUM_TEMPLATE0 *enumTemplate,
HANDLE *enumHandle
);
- 输入参数
- engineHandle:引擎句柄,由FwpmEngineOpen0创建。
- enumTemplate:枚举参数,实际上内容保留使用,可以为NULL。
- enumHandle:输出参数,用于传出枚举句柄
- 输出参数
- ERROR_SUCCESS为成功,其它参考错误码
执行枚举操作
DWORD FwpmLayerEnum0(
HANDLE engineHandle,
HANDLE enumHandle,
UINT32 numEntriesRequested,
FWPM_LAYER0 ***entries,
UINT32 *numEntriesReturned
);
- 输入参数
- engineHandle:引擎句柄
- enumHandle:枚举句柄,FwpmLayerCreateEnumHandle0创建
- numEntriesRequested:请求的数目
- entries:用于返回的层参数数组,需要FwpmFreeMemory0释放(这里需要注意,该参数定义为:FWPM_LAYER0** p=NULL,释放使用FwpmFreeMemory0((void**)&p))
- numEntriesReturned:本次返回的结构体数目
- 输出参数
- ERROR_SUCCESS为成功
销毁层枚举句柄
DWORD FwpmLayerDestroyEnumHandle0(
HANDLE engineHandle,
HANDLE enumHandle
);
- 输入参数
- engineHandle:引擎句柄,由FwpmEngineOpen0创建
- enumHandle:枚举句柄,由FwpmLayerCreateEnumHandle0创建
- 输出参数
- ERROR_SUCCESS为成功,其它参考错误码
参考代码
#define SESSION_LAYER L"session_layer";
GUID SESSION_GUID = { 0x2ec66da9, 0x2ae4, 0x4f83, { 0x81, 0xc7, 0x34, 0x5d, 0x19,
0x6a, 0xe3, 0xd7 } };
int main()
{
HANDLE engineHandle = NULL;
DWORD result = ERROR_SUCCESS;
FWPM_SESSION0 fwpmSession;
memset(&fwpmSession, 0, sizeof(FWPM_SESSION0));
fwpmSession.flags = FWPM_SESSION_FLAG_DYNAMIC;
result = FwpmEngineOpen0(NULL, RPC_C_AUTHN_DEFAULT, NULL, &fwpmSession,
&engineHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmEngineOpen0 failed;Return value:%d.\n", __FUNCTION__,
result);
return 0;
}
HANDLE enumHandle = NULL;
result = FwpmLayerCreateEnumHandle0(engineHandle, NULL, &enumHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmFilterCreateEnumHandle0, Return value:%d\n", __FUNCTION__,
result);
FwpmEngineClose0(engineHandle);
return 0;
}
UINT32 numEntriesReturned = 0;
do
{
FWPM_LAYER0** fwpmLayerList = NULL;
numEntriesReturned = 0;
result = FwpmLayerEnum0(engineHandle, enumHandle, 1, &fwpmLayerList,
&numEntriesReturned);
if (result != ERROR_SUCCESS || numEntriesReturned == 0)
{
break;
}
std::string strLayerName = boost::locale::conv::from_utf(fwpmLayerList[0]->displayData.name, "GBK");
printf("layer name:%s\n", strLayerName.c_str());
FwpmFreeMemory0((void**)&fwpmLayerList);
} while (numEntriesReturned > 0);
result = FwpmLayerDestroyEnumHandle0(engineHandle, enumHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmFilterDestroyEnumHandle0, Return value:%d\n", __FUNCTION__,
result);
}
result = FwpmEngineClose0(engineHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmEngineClose0 failed; Return value:%d\n", __FUNCTION__,
result);
return 0;
}
printf("[%s]result Success\n", __FUNCTION__);
}
执行结果

枚举当前所有子层
创建子层枚举句柄
DWORD FwpmSubLayerCreateEnumHandle0(
HANDLE engineHandle,
const FWPM_SUBLAYER_ENUM_TEMPLATE0 *enumTemplate,
HANDLE *enumHandle
);
- 输入参数
- engineHandle:防火墙引擎句柄,由FwpmEngineOpen0创建
- enumTemplate:选择参数,可以为NULL
- enumHandle:枚举句柄,用于输出
- 输出参数
- ERROR_SUCCESS为成功,其它为错误码
执行子层枚举
DWORD FwpmSubLayerEnum0(
HANDLE engineHandle,
HANDLE enumHandle,
UINT32 numEntriesRequested,
FWPM_SUBLAYER0 ***entries,
UINT32 *numEntriesReturned
);
- 输入参数
- engineHandle:防火墙引擎,由FwpmEngineOpen0创建
- enumHandle:枚举句柄,由FwpmSubLayerCreateEnumHandle0创建
- numEntriesRequested:本次请求的个数
- entries:用于输出子层参数,需要FwpmFreeMemory0手动释放
- numEntriesReturned:本次返回的子层个数
- 输出参数
- ERROR_SUCCESS为成功,其它为错误码
销毁子层枚举句柄
DWORD FwpmSubLayerDestroyEnumHandle0(
HANDLE engineHandle,
HANDLE enumHandle
);
- 输入参数
- engineHandle:防火墙引擎句柄,由FwpmEngingOpen0创建
- enumHandle:枚举句柄
- 输出参数
- ERROR_SUCCESS为成功,其它为错误码
参考代码
#define SESSION_LAYER L"session_layer";
GUID SESSION_GUID = { 0x2ec66da9, 0x2ae4, 0x4f83, { 0x81, 0xc7, 0x34, 0x5d, 0x19,
0x6a, 0xe3, 0xd7 } };
int main()
{
std::cout << "Hello World!\n";
HANDLE engineHandle = NULL;
DWORD result = ERROR_SUCCESS;
FWPM_SESSION0 fwpmSession;
memset(&fwpmSession, 0, sizeof(FWPM_SESSION0));
fwpmSession.flags = FWPM_SESSION_FLAG_DYNAMIC;
result = FwpmEngineOpen0(NULL, RPC_C_AUTHN_DEFAULT, NULL, &fwpmSession,
&engineHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmEngineOpen0 failed;Return value:%d.\n", __FUNCTION__,
result);
return 0;
}
HANDLE enumHandle = NULL;
result = FwpmSubLayerCreateEnumHandle0(engineHandle, NULL, &enumHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmSubLayerCreateEnumHandle, Return value:%d\n", __FUNCTION__,
result);
FwpmEngineClose0(engineHandle);
return 0;
}
UINT32 numEntriesReturned = 0;
do
{
FWPM_SUBLAYER0** fwpmSubLayerList = NULL;
numEntriesReturned = 0;
result = FwpmSubLayerEnum0(engineHandle, enumHandle, 1, &fwpmSubLayerList,
&numEntriesReturned);
if (result != ERROR_SUCCESS || numEntriesReturned == 0)
{
break;
}
std::string subLayerName =
boost::locale::conv::from_utf(fwpmSubLayerList[0]->displayData.name, "GBK");
printf("[%s]subLayer name:%s\n", __FUNCTION__, subLayerName.c_str());
FwpmFreeMemory0((void**)&fwpmSubLayerList);
} while (numEntriesReturned > 0);
result = FwpmSubLayerDestroyEnumHandle0(engineHandle, enumHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmSubLayerDestroyEnumHandle, Return value:%d\n",
__FUNCTION__, result);
FwpmEngineClose0(engineHandle);
return 0;
}
result = FwpmEngineClose0(engineHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmEngineClose0 failed; Return value:%d\n", __FUNCTION__,
result);
return 0;
}
printf("[%s]result Success\n", __FUNCTION__);
return 0;
}
执行结果

枚举子层内所有过滤器
创建过滤器枚举器
DWORD FwpmFilterCreateEnumHandle0(
HANDLE engineHandle,
const FWPM_FILTER_ENUM_TEMPLATE0 *enumTemplate,
HANDLE *enumHandle
);
- 输入参数
- engineHandle:防火墙引擎句柄
- enumTemplate:过滤参数,可以为NULL
- enumHandle:枚举句柄,用于输出
- 输出参数
- ERROR_SUCCESS为成功
执行过滤器枚举
DWORD FwpmFilterEnum0(
HANDLE engineHandle,
HANDLE enumHandle,
UINT32 numEntriesRequested,
FWPM_FILTER0 ***entries,
UINT32 *numEntriesReturned
);
- 输入参数
- engineHandle:防火墙引擎句柄
- enumHandle:过滤器枚举句柄,FwpmFilterCreateEnumHandle0创建
- numEntriesRequested:本次请求过滤器个数
- entries:用于输出的过滤器数组,需要调用FwpmFreeMemory0释放
- numEntriesReturned:本次返回的过滤器个数
- 输出参数
- ERROR_SUCCESS为成功
销毁过滤器枚举器
DWORD FwpmFilterDestroyEnumHandle0(
HANDLE engineHandle,
HANDLE enumHandle
);
- 输入参数
- engineHandle:防火墙引擎句柄
- enumHandle:过滤器枚举句柄,FwpmFilterCreateEnumHandle0创建
- 输出参数
- ERROR_SUCCESS为成功
参考代码
int main()
{
std::cout << "Hello World!\n";
HANDLE engineHandle = NULL;
DWORD result = ERROR_SUCCESS;
FWPM_SESSION0 fwpmSession;
memset(&fwpmSession, 0, sizeof(FWPM_SESSION0));
fwpmSession.flags = FWPM_SESSION_FLAG_DYNAMIC;
result = FwpmEngineOpen0(NULL, RPC_C_AUTHN_DEFAULT, NULL, &fwpmSession,
&engineHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmEngineOpen0 failed;Return value:%d.\n", __FUNCTION__,
result);
return 0;
}
HANDLE enumHandle = NULL;
result = FwpmFilterCreateEnumHandle0(engineHandle, NULL, &enumHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmFilterCreateEnumHandle0, Return value:%d\n", __FUNCTION__,
result);
FwpmEngineClose0(engineHandle);
return 0;
}
UINT32 numEntriesReturned = 0;
do
{
FWPM_FILTER0** fwpmFilterList = NULL;
numEntriesReturned = 0;
result = FwpmFilterEnum0(engineHandle, enumHandle, 1, &fwpmFilterList,
&numEntriesReturned);
if (result != ERROR_SUCCESS || numEntriesReturned == 0)
{
break;
}
std::string filterName =
boost::locale::conv::from_utf(fwpmFilterList[0]->displayData.name, "GBK");
printf("[%s]filter name:%s\t filter count:%d\n", __FUNCTION__,
filterName.c_str(), fwpmFilterList[0]->numFilterConditions);
FwpmFreeMemory0((void**)&fwpmFilterList);
} while (numEntriesReturned > 0);
result = FwpmFilterDestroyEnumHandle0(engineHandle, enumHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmFilterDestroyEnumHandle0, Return value:%d\n", __FUNCTION__,
result);
FwpmEngineClose0(engineHandle);
return 0;
}
result = FwpmEngineClose0(engineHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmEngineClose0 failed; Return value:%d\n", __FUNCTION__,
result);
return 0;
}
printf("[%s]result Success\n", __FUNCTION__);
return 0;
}
执行结果
添加和删除子层
添加子层
DWORD FwpmSubLayerAdd0(
HANDLE engineHandle,
const FWPM_SUBLAYER0 *subLayer,
PSECURITY_DESCRIPTOR sd
);
- 输入参数
- engineHandle:防火墙引擎句柄
- subLayer:防火墙子层参数
- sd:安全描述符,可以为空
- 输出参数
- ERROR_SUCCESS为成功
删除子层
DWORD FwpmSubLayerDeleteByKey0(
HANDLE engineHandle,
const GUID *key
);
- 输入参数
- engineHandle:防火墙引擎
- key:防火墙要删除的GUID
- 输出参数
* ERROR_SUCCESS为成功
参考代码
int main()
{
std::cout << "Hello World!\n";
HANDLE engineHandle = NULL;
DWORD result = ERROR_SUCCESS;
FWPM_SESSION0 fwpmSession;
memset(&fwpmSession, 0, sizeof(FWPM_SESSION0));
fwpmSession.flags = FWPM_SESSION_FLAG_DYNAMIC;
result = FwpmEngineOpen0(NULL, RPC_C_AUTHN_DEFAULT, NULL, &fwpmSession,
&engineHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmEngineOpen0 failed;Return value:%d.\n", __FUNCTION__,
result);
return 0;
}
FWPM_SUBLAYER0 insertSubLayer;
memset(&insertSubLayer, 0, sizeof(FWPM_SUBLAYER0));
insertSubLayer.subLayerKey = SUBLEYER_GUID;
insertSubLayer.displayData.name = (wchar_t*)SUBLEYER_NAME;
insertSubLayer.displayData.description = (wchar_t*)L"demo_sublayer_des";
insertSubLayer.weight = 50;
result = FwpmSubLayerAdd0(engineHandle, &insertSubLayer, NULL);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmSubLayerAdd0, Return value:%d\n", __FUNCTION__, result);
FwpmEngineClose0(engineHandle);
return 0;
}
printf("after
add\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
enumSubLayer(engineHandle);
FwpmSubLayerDeleteByKey0(engineHandle, (const GUID*)&SUBLEYER_GUID);
printf("after
del\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
enumSubLayer(engineHandle);
result = FwpmEngineClose0(engineHandle);
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmEngineClose0 failed; Return value:%d\n", __FUNCTION__,
result);
return 0;
}
printf("[%s]result Success\n", __FUNCTION__);
return 0;
}
执行效果
添加之后
添加过滤器
过滤条件结构体
typedef struct FWPM_FILTER_CONDITION0_ {
GUID fieldKey;
FWP_MATCH_TYPE matchType;
FWP_CONDITION_VALUE0 conditionValue;
} FWPM_FILTER_CONDITION0;
fieldKey:过滤器检测位置的GUID,参数定义与fwpmu.h,举例有如下几个,可以根据这几个值到对应头文件查看
GUID 含义 FWPM_CONDITION_ALE_APP_ID 全路径校验 FWPM_CONDITION_IP_LOCAL_PORT 本地传输端口号 FWPM_CONDITION_IP_REMOTE_PORT 远程传输端口号 FWPM_CONDITION_IP_LOCAL_ADDRESS 本地IP地址 FWPM_CONDITION_IP_REMOTE_ADDRESS 远程IP地址 FWPM_CONDITION_IP_PROTOCOL 协议类型 matchType:过滤器校验方式,常用的如下,其余的可以查FWP_MATCH_TYPE结构体。
TYPE 操作类型 FWP_MATCH_EQUAL 相等 FWP_MATCH_GREATER 大于 FWP_MATCH_LESS 小于 FWP_MATCH_GREATER_OR_EQUAL 大于等于 FWP_MATCH_LESS_OR_EQUAL 小于等于 FWP_MATCH_RANGE 范围内 FWP_MATCH_NOT_EQUAL 不等于 conditionValue:过滤器校验参数
过滤器结构体
typedef struct FWPM_FILTER0_ {
GUID filterKey;
FWPM_DISPLAY_DATA0 displayData;
UINT32 flags;
GUID *providerKey;
FWP_BYTE_BLOB providerData;
GUID layerKey;
GUID subLayerKey;
FWP_VALUE0 weight;
UINT32 numFilterConditions;
FWPM_FILTER_CONDITION0 *filterCondition;
FWPM_ACTION0 action;
union {
UINT64 rawContext;
GUID providerContextKey;
};
GUID *reserved;
UINT64 filterId;
FWP_VALUE0 effectiveWeight;
} FWPM_FILTER0;
部分参数如下
- filterKey:过滤器生效的位置GUID,如FWPM_LAYER_ALE_AUTH_CONNECT_V4,可以查看:Filter Layer Identifiers
- layerKey:层GUID
- subLayerKey:子层GUID
- weight:过滤器权重
- numFilterConditions:本次过滤器的数目
- filterCondition:过滤器数组
- action:过滤方式,FWP_ACTION_BLOCK:阻断,FWP_ACTION_PERMIT:放行。
开始防火墙操作事务
DWORD FwpmTransactionBegin0(
HANDLE engineHandle,
UINT32 flags
);
- 输入参数
- engineHandle:过滤器句柄
- flags:读写标识。0为读写,FWPM_TXN_READ_ONLY为只读
- 输出参数
- ERROR_SUCCESS为成功,其它为错误码
添加过滤器
DWORD FwpmFilterAdd0(
HANDLE engineHandle,
const FWPM_FILTER0 *filter,
PSECURITY_DESCRIPTOR sd,
UINT64 *id
);
- 输入参数
- engineHandle:过滤器句柄
- filter:过滤器参数结构体
- sd:安全句柄,可为空。
- id:输出参数,用于输出过滤器ID
- 输出参数
- ERROR_SUCCESS为成功,其它为错误码
提交防火墙操作事务
DWORD FwpmTransactionCommit0(
HANDLE engineHandle
);
- 输入参数
- engineHandle:过滤器句柄
- 输出参数
- ERROR_SUCCESS为成功,其它为错误码
取消防火墙操作事务
DWORD FwpmTransactionAbort0(
HANDLE engineHandle
);
- 输入参数
- engineHandle:过滤器句柄
- 输出参数
- ERROR_SUCCESS为成功,其它为错误码
参考代码
const wchar_t* application_path = L"C:\\Program Files\\Internet
Explorer\\iexplore.exe";
FWP_BYTE_BLOB* fwpApplicationBlob;
result = FwpmGetAppIdFromFileName0(application_path, &fwpApplicationBlob); // fwpApplicationBlob需要FwpmFreeMemory释放
if (result != ERROR_SUCCESS)
{
printf("[%s]FwpmGetAppIdFromFileName0, Return value:%d\n", __FUNCTION__,
result);
FwpmEngineClose(engineHandle);
return 0;
}
FWPM_FILTER0 fwpmFilter;
FWPM_FILTER_CONDITION0 fwpmConditions[4] = {0};
int conCount = 0;
fwpmConditions[conCount].fieldKey = FWPM_CONDITION_ALE_APP_ID;
fwpmConditions[conCount].matchType = FWP_MATCH_EQUAL;
fwpmConditions[conCount].conditionValue.type = FWP_BYTE_BLOB_TYPE;
fwpmConditions[conCount].conditionValue.byteBlob = fwpApplicationBlob;
conCount++;
memset(&fwpmFilter, 0, sizeof(FWPM_FILTER0));
fwpmFilter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
fwpmFilter.subLayerKey = SUBLEYER_GUID;
fwpmFilter.numFilterConditions = conCount;
fwpmFilter.filterCondition = fwpmConditions;
fwpmFilter.action.type = FWP_ACTION_BLOCK;
fwpmFilter.weight.type = FWP_UINT64;
UINT64 u64Weight = 80;
fwpmFilter.weight.uint64 = &u64Weight;
fwpmFilter.displayData.name = (wchar_t*)L"demo_filter";
fwpmFilter.displayData.description = (wchar_t*)L"demo_filter";
result = FwpmTransactionBegin0(engineHandle, 0);
result = FwpmFilterAdd0(engineHandle, &fwpmFilter, NULL,
&(fwpmFilter.filterId));
result = FwpmTransactionCommit0(engineHandle);
enumFilter(engineHandle);
FwpmFreeMemory0((void**)&fwpApplicationBlob); // 释放
执行结果

版权声明:本文为QQ1113130712原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。

