驱动开发:内核封装WFP防火墙入门
WFP框架是微软推出来替代TDIHOOK传输层驱动接口网络通信的方案,其默认被设计为分层结构,该框架分别提供了用户态与内核态相同的AIP函数,在两种模式下均可以开发防火墙产品,以下代码我实现了一个简单的驱动过滤防火墙。
WFP 框架分为两大层次模块,用户态基础过滤引擎BFE (BaseFilteringEngine)
,以及内核态过滤引擎 KMFE (KMFilteringEngine)
,基础过滤引擎对上提供C语言调用方式的API以及RPC接口,这些接口都被封装在FWPUCLNT.dll
模块中,开发时可以调用该模块中的导出函数.
- WFP程序工作流程:
- 使用 FwpmEngineOpen() 开启 WFP 引擎,获得WFP使用句柄
- 使用 FwpmTransactionBegin() 设置对网络通信内容的过滤权限 (只读/允许修改)
- 使用 FwpsCalloutRegister(),FwpmCalloutAdd(),FwpmFilterAdd() 选择要过滤的内容,并添加过滤器对象和回调函数.
- 使用 FwpmTransactionCommit() 确认刚才的内容,让刚才添加的回调函数开始生效.
- 使用 FwpmFilterDeleteById(),FwpmCalloutDeleteById(),FwpsCalloutUnregisterById()函数撤销对象和回调函数.
- 使用 FwpmEngineClose() 关闭WFP引擎类句柄.
默认情况下WFP一次需要注册3个回调函数,只有一个是事前回调,另外两个是事后回调,通常情况下我们只关注事前回调即可,此外WFP能过滤很对内容,我们需要指定过滤条件标志来输出我们所需要的数据.
- 一般可设置为
FWPM_LAYER_ALE_AUTH_CONNECT_V4
意思是设置IPV4过滤. - 还需要设置一个GUID值,该值可随意设置,名称为
GUID_ALE_AUTH_CONNECT_CALLOUT_V4
宏.
首先我们通过上方的流程实现一个简单的网络控制驱动,该驱动运行后可对自身机器访问指定地址端口进行控制,例如实现指定应用断网,禁止指定页面被访问等,在配置WFP开发环境时需要在链接器选项卡中的附加依赖项中增加fwpkclnt.lib,uuid.lib
这两个库文件,并且需要使用WDM开发模板,否则编译将不通过。
// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com#define NDIS_SUPPORT_NDIS6 1
#define DEV_NAME L"\\Device\\MY_WFP_DEV_NAME"
#define SYM_NAME L"\\DosDevices\\MY_WFP_SYM_NAME"#include <ntifs.h>
#include <fwpsk.h>
#include <fwpmk.h>
#include <stdio.h>// 过滤器引擎句柄
HANDLE g_hEngine;// 过滤器引擎中的callout的运行时标识符
ULONG32 g_AleConnectCalloutId;// 过滤器的运行时标识符
ULONG64 g_AleConnectFilterId;// 指定唯一UUID值(只要不冲突即可,内容可随意)
GUID GUID_ALE_AUTH_CONNECT_CALLOUT_V4 = { 0x6812fc83, 0x7d3e, 0x499a, 0xa0, 0x12, 0x55, 0xe0, 0xd8, 0x5f, 0x34, 0x8b };// ------------------------------------------------------------------------------
// 头部函数声明
// ------------------------------------------------------------------------------// 注册Callout并设置过滤点
NTSTATUS RegisterCalloutForLayer(IN PDEVICE_OBJECT pDevObj,IN const GUID *layerKey,IN const GUID *calloutKey,IN FWPS_CALLOUT_CLASSIFY_FN classifyFn,IN FWPS_CALLOUT_NOTIFY_FN notifyFn,IN FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN flowDeleteNotifyFn,OUT ULONG32 *calloutId,OUT ULONG64 *filterId,OUT HANDLE *engine);// 注册Callout
NTSTATUS RegisterCallout(PDEVICE_OBJECT pDevObj,IN const GUID *calloutKey,IN FWPS_CALLOUT_CLASSIFY_FN classifyFn,IN FWPS_CALLOUT_NOTIFY_FN notifyFn,IN FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN flowDeleteNotifyFn,OUT ULONG32 *calloutId);// 设置过滤点
NTSTATUS SetFilter(IN const GUID *layerKey,IN const GUID *calloutKey,OUT ULONG64 *filterId,OUT HANDLE *engine);// Callout函数 flowDeleteFn
VOID NTAPI flowDeleteFn(_In_ UINT16 layerId,_In_ UINT32 calloutId,_In_ UINT64 flowContext);// Callout函数 classifyFn
#if (NTDDI_VERSION >= NTDDI_WIN8)
VOID NTAPI classifyFn(_In_ const FWPS_INCOMING_VALUES0* inFixedValues,_In_ const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,_Inout_opt_ void* layerData,_In_opt_ const void* classifyContext,_In_ const FWPS_FILTER2* filter,_In_ UINT64 flowContext,_Inout_ FWPS_CLASSIFY_OUT0* classifyOut);
#elif (NTDDI_VERSION >= NTDDI_WIN7)
VOID NTAPI classifyFn(_In_ const FWPS_INCOMING_VALUES0* inFixedValues,_In_ const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,_Inout_opt_ void* layerData,_In_opt_ const void* classifyContext,_In_ const FWPS_FILTER1* filter,_In_ UINT64 flowContext,_Inout_ FWPS_CLASSIFY_OUT0* classifyOut);
#else
VOID NTAPI classifyFn(_In_ const FWPS_INCOMING_VALUES0* inFixedValues,_In_ const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,_Inout_opt_ void* layerData,_In_ const FWPS_FILTER0* filter,_In_ UINT64 flowContext,_Inout_ FWPS_CLASSIFY_OUT0* classifyOut);
#endif// Callout函数 notifyFn
#if (NTDDI_VERSION >= NTDDI_WIN8)
NTSTATUS NTAPI notifyFn(_In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,_In_ const GUID* filterKey,_Inout_ FWPS_FILTER2* filter);
#elif (NTDDI_VERSION >= NTDDI_WIN7)
NTSTATUS NTAPI notifyFn(_In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,_In_ const GUID* filterKey,_Inout_ FWPS_FILTER1* filter);
#else
NTSTATUS NTAPI notifyFn(_In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,_In_ const GUID* filterKey,_Inout_ FWPS_FILTER0* filter);
#endif// ------------------------------------------------------------------------------
// 函数实现部分
// ------------------------------------------------------------------------------// 协议判断
NTSTATUS ProtocalIdToName(UINT16 protocalId, PCHAR lpszProtocalName)
{NTSTATUS status = STATUS_SUCCESS;switch (protocalId){case 1:{// ICMPRtlCopyMemory(lpszProtocalName, "ICMP", 5);break;}case 2:{// IGMPRtlCopyMemory(lpszProtocalName, "IGMP", 5);break;}case 6:{// TCPRtlCopyMemory(lpszProtocalName, "TCP", 4);break;}case 17:{// UDPRtlCopyMemory(lpszProtocalName, "UDP", 4);break;}case 27:{// RDPRtlCopyMemory(lpszProtocalName, "RDP", 6);break;}default:{// UNKNOWRtlCopyMemory(lpszProtocalName, "UNKNOWN", 8);break;}}return status;
}// 启动WFP
NTSTATUS WfpLoad(PDEVICE_OBJECT pDevObj)
{NTSTATUS status = STATUS_SUCCESS;// 注册Callout并设置过滤点// classifyFn, notifyFn, flowDeleteFn 注册三个回调函数,一个事前回调,两个事后回调status = RegisterCalloutForLayer(pDevObj, &FWPM_LAYER_ALE_AUTH_CONNECT_V4, &GUID_ALE_AUTH_CONNECT_CALLOUT_V4,classifyFn, notifyFn, flowDeleteFn, &g_AleConnectCalloutId, &g_AleConnectFilterId, &g_hEngine);if (!NT_SUCCESS(status)){DbgPrint("注册回调失败 \n");return status;}return status;
}// 卸载WFP
NTSTATUS WfpUnload()
{if (NULL != g_hEngine){// 删除FilterIdFwpmFilterDeleteById(g_hEngine, g_AleConnectFilterId);// 删除CalloutIdFwpmCalloutDeleteById(g_hEngine, g_AleConnectCalloutId);// 清空Filterg_AleConnectFilterId = 0;// 反注册CalloutIdFwpsCalloutUnregisterById(g_AleConnectCalloutId);// 清空CalloutIdg_AleConnectCalloutId = 0;// 关闭引擎FwpmEngineClose(g_hEngine);g_hEngine = NULL;}return STATUS_SUCCESS;
}// 注册Callout并设置过滤点
NTSTATUS RegisterCalloutForLayer(IN PDEVICE_OBJECT pDevObj, IN const GUID *layerKey, IN const GUID *calloutKey, IN FWPS_CALLOUT_CLASSIFY_FN classifyFn, IN FWPS_CALLOUT_NOTIFY_FN notifyFn, IN FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN flowDeleteNotifyFn, OUT ULONG32 *calloutId, OUT ULONG64 *filterId, OUT HANDLE *engine)
{NTSTATUS status = STATUS_SUCCESS;// 注册Calloutstatus = RegisterCallout(pDevObj, calloutKey, classifyFn, notifyFn, flowDeleteNotifyFn, calloutId);if (!NT_SUCCESS(status)){return status;}// 设置过滤点status = SetFilter(layerKey, calloutKey, filterId, engine);if (!NT_SUCCESS(status)){return status;}return status;
}// 注册Callout
NTSTATUS RegisterCallout(PDEVICE_OBJECT pDevObj, IN const GUID *calloutKey, IN FWPS_CALLOUT_CLASSIFY_FN classifyFn, IN FWPS_CALLOUT_NOTIFY_FN notifyFn, IN FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN flowDeleteNotifyFn, OUT ULONG32 *calloutId)
{NTSTATUS status = STATUS_SUCCESS;FWPS_CALLOUT sCallout = { 0 };// 设置CalloutsCallout.calloutKey = *calloutKey;sCallout.classifyFn = classifyFn;sCallout.flowDeleteFn = flowDeleteNotifyFn;sCallout.notifyFn = notifyFn;// 注册Calloutstatus = FwpsCalloutRegister(pDevObj, &sCallout, calloutId);if (!NT_SUCCESS(status)){DbgPrint("注册Callout失败 \n");return status;}return status;
}// 设置过滤点
NTSTATUS SetFilter(IN const GUID *layerKey, IN const GUID *calloutKey, OUT ULONG64 *filterId, OUT HANDLE *engine)
{HANDLE hEngine = NULL;NTSTATUS status = STATUS_SUCCESS;FWPM_SESSION session = { 0 };FWPM_FILTER mFilter = { 0 };FWPM_CALLOUT mCallout = { 0 };FWPM_DISPLAY_DATA mDispData = { 0 };// 创建Sessionsession.flags = FWPM_SESSION_FLAG_DYNAMIC;status = FwpmEngineOpen(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &hEngine);if (!NT_SUCCESS(status)){return status;}// 开始事务status = FwpmTransactionBegin(hEngine, 0);if (!NT_SUCCESS(status)){return status;}// 设置Callout参数mDispData.name = L"MY WFP LyShark";mDispData.description = L"WORLD OF DEMON";mCallout.applicableLayer = *layerKey;mCallout.calloutKey = *calloutKey;mCallout.displayData = mDispData;// 添加Callout到Session中status = FwpmCalloutAdd(hEngine, &mCallout, NULL, NULL);if (!NT_SUCCESS(status)){return status;}// 设置过滤器参数mFilter.action.calloutKey = *calloutKey;mFilter.action.type = FWP_ACTION_CALLOUT_TERMINATING;mFilter.displayData.name = L"MY WFP LyShark";mFilter.displayData.description = L"WORLD OF DEMON";mFilter.layerKey = *layerKey;mFilter.subLayerKey = FWPM_SUBLAYER_UNIVERSAL;mFilter.weight.type = FWP_EMPTY;// 添加过滤器status = FwpmFilterAdd(hEngine, &mFilter, NULL, filterId);if (!NT_SUCCESS(status)){return status;}// 提交事务status = FwpmTransactionCommit(hEngine);if (!NT_SUCCESS(status)){return status;}*engine = hEngine;return status;
}// Callout函数 classifyFn 事前回调函数
VOID NTAPI classifyFn(_In_ const FWPS_INCOMING_VALUES0* inFixedValues, _In_ const FWPS_INCOMING_METADATA_VALUES0* inMetaValues, _Inout_opt_ void* layerData, _In_opt_ const void* classifyContext, _In_ const FWPS_FILTER2* filter, _In_ UINT64 flowContext, _Inout_ FWPS_CLASSIFY_OUT0* classifyOut)
{// 数据包的方向,取值 FWP_DIRECTION_INBOUND = 1 或 FWP_DIRECTION_OUTBOUND = 0WORD wDirection = inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION].value.int8;// 定义本机地址与本机端口ULONG ulLocalIp = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS].value.uint32;UINT16 uLocalPort = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16;// 定义对端地址与对端端口ULONG ulRemoteIp = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS].value.uint32;UINT16 uRemotePort = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16;// 获取当前进程IRQKIRQL kCurrentIrql = KeGetCurrentIrql();// 获取进程IDULONG64 processId = inMetaValues->processId;UCHAR szProcessPath[256] = { 0 };CHAR szProtocalName[256] = { 0 };RtlZeroMemory(szProcessPath, 256);// 获取进程路径for (ULONG i = 0; i < inMetaValues->processPath->size; i++){// 里面是宽字符存储的szProcessPath[i] = inMetaValues->processPath->data[i];}// 获取当前协议类型ProtocalIdToName(inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint16, szProtocalName);// 设置默认规则 允许连接classifyOut->actionType = FWP_ACTION_PERMIT;// 禁止指定进程网络连接if (NULL != wcsstr((PWCHAR)szProcessPath, L"iexplore.exe")){// 设置拒绝规则 拒绝连接classifyOut->actionType = FWP_ACTION_BLOCK;classifyOut->rights = classifyOut->rights & (~FWPS_RIGHT_ACTION_WRITE);classifyOut->flags = classifyOut->flags | FWPS_CLASSIFY_OUT_FLAG_ABSORB;DbgPrint("[LyShark.com] 拦截IE网络链接请求... \n");}// 输出对端地址字符串 并阻断链接char szRemoteAddress[256] = { 0 };char szRemotePort[128] = { 0 };char szLocalAddress[256] = { 0 };char szLocalPort[128] = { 0 };sprintf(szRemoteAddress, "%u.%u.%u.%u", (ulRemoteIp >> 24) & 0xFF, (ulRemoteIp >> 16) & 0xFF, (ulRemoteIp >> 8) & 0xFF, (ulRemoteIp)& 0xFF);sprintf(szRemotePort, "%d", uRemotePort);sprintf(szLocalAddress, "%u.%u.%u.%u", (ulLocalIp >> 24) & 0xFF, (ulLocalIp >> 16) & 0xFF, (ulLocalIp >> 8) & 0xFF, (ulLocalIp)& 0xFF);sprintf(szLocalPort, "%d", uLocalPort);// DbgPrint("本端: %s : %s --> 对端: %s : %s \n", szLocalAddress, szLocalPort, szRemoteAddress, szRemotePort);// 如果对端地址是 8.141.58.64 且对端端口是 443 则拒绝连接if (strcmp(szRemoteAddress, "8.141.58.64") == 0 && strcmp(szRemotePort, "443") == 0){DbgPrint("[LyShark.com] 拦截网站访问请求 --> %s : %s \n", szRemoteAddress, szRemotePort);// 设置拒绝规则 拒绝连接classifyOut->actionType = FWP_ACTION_BLOCK;classifyOut->rights = classifyOut->rights & (~FWPS_RIGHT_ACTION_WRITE);classifyOut->flags = classifyOut->flags | FWPS_CLASSIFY_OUT_FLAG_ABSORB;}else if (strcmp(szRemotePort, "0") == 0){DbgPrint("[LyShark.com] 拦截Ping访问请求 --> %s \n", szRemoteAddress);// 设置拒绝规则 拒绝连接classifyOut->actionType = FWP_ACTION_BLOCK;classifyOut->rights = classifyOut->rights & (~FWPS_RIGHT_ACTION_WRITE);classifyOut->flags = classifyOut->flags | FWPS_CLASSIFY_OUT_FLAG_ABSORB;}// 显示DbgPrint("[LyShark.com] 方向: %d -> 协议类型: %s -> 本端地址: %u.%u.%u.%u:%d -> 对端地址: %u.%u.%u.%u:%d -> IRQL: %d -> 进程ID: %I64d -> 路径: %S \n",wDirection,szProtocalName,(ulLocalIp >> 24) & 0xFF,(ulLocalIp >> 16) & 0xFF,(ulLocalIp >> 8) & 0xFF,(ulLocalIp)& 0xFF,uLocalPort,(ulRemoteIp >> 24) & 0xFF,(ulRemoteIp >> 16) & 0xFF,(ulRemoteIp >> 8) & 0xFF,(ulRemoteIp)& 0xFF,uRemotePort,kCurrentIrql,processId,(PWCHAR)szProcessPath);}// Callout函数 notifyFn 事后回调函数
NTSTATUS NTAPI notifyFn(_In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType, _In_ const GUID* filterKey, _Inout_ FWPS_FILTER2* filter)
{NTSTATUS status = STATUS_SUCCESS;return status;
}// Callout函数 flowDeleteFn 事后回调函数
VOID NTAPI flowDeleteFn(_In_ UINT16 layerId, _In_ UINT32 calloutId, _In_ UINT64 flowContext)
{return;
}// 默认派遣函数
NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{NTSTATUS status = STATUS_SUCCESS;pIrp->IoStatus.Status = status;pIrp->IoStatus.Information = 0;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return status;
}// 创建设备
NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject)
{NTSTATUS status = STATUS_SUCCESS;PDEVICE_OBJECT pDevObj = NULL;UNICODE_STRING ustrDevName, ustrSymName;RtlInitUnicodeString(&ustrDevName, DEV_NAME);RtlInitUnicodeString(&ustrSymName, SYM_NAME);status = IoCreateDevice(pDriverObject, 0, &ustrDevName, FILE_DEVICE_NETWORK, 0, FALSE, &pDevObj);if (!NT_SUCCESS(status)){return status;}status = IoCreateSymbolicLink(&ustrSymName, &ustrDevName);if (!NT_SUCCESS(status)){return status;}return status;
}// 卸载驱动
VOID UnDriver(PDRIVER_OBJECT driver)
{// 删除回调函数和过滤器,关闭引擎WfpUnload();UNICODE_STRING ustrSymName;RtlInitUnicodeString(&ustrSymName, SYM_NAME);IoDeleteSymbolicLink(&ustrSymName);if (driver->DeviceObject){IoDeleteDevice(driver->DeviceObject);}
}// 驱动入口
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{NTSTATUS status = STATUS_SUCCESS;Driver->DriverUnload = UnDriver;for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++){Driver->MajorFunction[i] = DriverDefaultHandle;}// 创建设备CreateDevice(Driver);// 启动WFPWfpLoad(Driver->DeviceObject);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}
上方代码是一个最基本的WFP过滤框架头部函数,声明部分来源于微软的定义此处不做解释,需要注意GUID_ALE_AUTH_CONNECT_CALLOUT_V4
代表的是一个随机UUID
值,该值可以任意定义只要不一致即可,驱动程序运行后会率先执行WfpLoad()
这个函数,该函数内部通过RegisterCalloutForLayer()
注册了一个过滤点,此处我们必须要注意三个回调函数,classifyFn, notifyFn, flowDeleteFn 他们分别的功能时,事前回调,事后回调,事后回调,而WFP框架中我们最需要注意的也就是对这三个函数进行重定义,也就是需要重写函数来实现我们特定的功能。
NTSTATUS RegisterCalloutForLayer
(IN const GUID* layerKey,IN const GUID* calloutKey,IN FWPS_CALLOUT_CLASSIFY_FN classifyFn,IN FWPS_CALLOUT_NOTIFY_FN notifyFn,IN FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN flowDeleteNotifyFn,OUT UINT32* calloutId,OUT UINT64* filterId
}
既然是防火墙那么必然classifyFn
事前更重要一些,如果需要监控网络流量则需要在事前函数中做处理,而如果是监视则可以在事后做处理,既然要在事前进行处理,那么我们就来看看事前是如何处理的流量。
// Callout函数 classifyFn 事前回调函数
VOID NTAPI classifyFn(_In_ const FWPS_INCOMING_VALUES0* inFixedValues, _In_ const FWPS_INCOMING_METADATA_VALUES0* inMetaValues, _Inout_opt_ void* layerData, _In_opt_ const void* classifyContext, _In_ const FWPS_FILTER2* filter, _In_ UINT64 flowContext, _Inout_ FWPS_CLASSIFY_OUT0* classifyOut)
{// 数据包的方向,取值 FWP_DIRECTION_INBOUND = 1 或 FWP_DIRECTION_OUTBOUND = 0WORD wDirection = inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION].value.int8;// 定义本机地址与本机端口ULONG ulLocalIp = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS].value.uint32;UINT16 uLocalPort = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16;// 定义对端地址与对端端口ULONG ulRemoteIp = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS].value.uint32;UINT16 uRemotePort = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16;// 获取当前进程IRQKIRQL kCurrentIrql = KeGetCurrentIrql();// 获取进程IDULONG64 processId = inMetaValues->processId;UCHAR szProcessPath[256] = { 0 };CHAR szProtocalName[256] = { 0 };RtlZeroMemory(szProcessPath, 256);// 获取进程路径for (ULONG i = 0; i < inMetaValues->processPath->size; i++){// 里面是宽字符存储的szProcessPath[i] = inMetaValues->processPath->data[i];}// 获取当前协议类型ProtocalIdToName(inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint16, szProtocalName);// 设置默认规则 允许连接classifyOut->actionType = FWP_ACTION_PERMIT;// 禁止指定进程网络连接if (NULL != wcsstr((PWCHAR)szProcessPath, L"qq.exe")){// 设置拒绝规则 拒绝连接classifyOut->actionType = FWP_ACTION_BLOCK;classifyOut->rights = classifyOut->rights & (~FWPS_RIGHT_ACTION_WRITE);classifyOut->flags = classifyOut->flags | FWPS_CLASSIFY_OUT_FLAG_ABSORB;}// 输出对端地址字符串 并阻断链接char szRemoteAddress[256] = { 0 };char szRemotePort[128] = { 0 };char szLocalAddress[256] = { 0 };char szLocalPort[128] = { 0 };sprintf(szRemoteAddress, "%u.%u.%u.%u", (ulRemoteIp >> 24) & 0xFF, (ulRemoteIp >> 16) & 0xFF, (ulRemoteIp >> 8) & 0xFF, (ulRemoteIp)& 0xFF);sprintf(szRemotePort, "%d", uRemotePort);sprintf(szLocalAddress, "%u.%u.%u.%u", (ulLocalIp >> 24) & 0xFF, (ulLocalIp >> 16) & 0xFF, (ulLocalIp >> 8) & 0xFF, (ulLocalIp)& 0xFF);sprintf(szLocalPort, "%d", uLocalPort);// DbgPrint("本端: %s : %s --> 对端: %s : %s \n", szLocalAddress, szLocalPort, szRemoteAddress, szRemotePort);// 如果对端地址是 8.141.58.64 且对端端口是 443 则拒绝连接if (strcmp(szRemoteAddress, "8.141.58.64") == 0 && strcmp(szRemotePort, "443") == 0){DbgPrint("拦截网站访问请求 --> %s : %s \n", szRemoteAddress, szRemotePort);// 设置拒绝规则 拒绝连接classifyOut->actionType = FWP_ACTION_BLOCK;classifyOut->rights = classifyOut->rights & (~FWPS_RIGHT_ACTION_WRITE);classifyOut->flags = classifyOut->flags | FWPS_CLASSIFY_OUT_FLAG_ABSORB;}else if (strcmp(szRemotePort, "0") == 0){DbgPrint("拦截Ping访问请求 --> %s \n", szRemoteAddress);// 设置拒绝规则 拒绝连接classifyOut->actionType = FWP_ACTION_BLOCK;classifyOut->rights = classifyOut->rights & (~FWPS_RIGHT_ACTION_WRITE);classifyOut->flags = classifyOut->flags | FWPS_CLASSIFY_OUT_FLAG_ABSORB;}/*// 显示DbgPrint("方向: %d -> 协议类型: %s -> 本端地址: %u.%u.%u.%u:%d -> 对端地址: %u.%u.%u.%u:%d -> IRQL: %d -> 进程ID: %I64d -> 路径: %S \n",wDirection,szProtocalName,(ulLocalIp >> 24) & 0xFF,(ulLocalIp >> 16) & 0xFF,(ulLocalIp >> 8) & 0xFF,(ulLocalIp)& 0xFF,uLocalPort,(ulRemoteIp >> 24) & 0xFF,(ulRemoteIp >> 16) & 0xFF,(ulRemoteIp >> 8) & 0xFF,(ulRemoteIp)& 0xFF,uRemotePort,kCurrentIrql,processId,(PWCHAR)szProcessPath);*/
}
当有新的网络数据包路由到事前函数时,程序中会通过如下案例直接得到我们所需要的数据包头,ProtocalIdToName
函数则是一个将特定类型数字转为字符串的转换函数。
// 数据包的方向,取值 FWP_DIRECTION_INBOUND = 1 或 FWP_DIRECTION_OUTBOUND = 0
WORD wDirection = inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION].value.int8;// 定义本机地址与本机端口
ULONG ulLocalIp = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS].value.uint32;
UINT16 uLocalPort = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16;// 定义对端地址与对端端口
ULONG ulRemoteIp = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS].value.uint32;
UINT16 uRemotePort = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16;// 获取当前进程IRQ
KIRQL kCurrentIrql = KeGetCurrentIrql();// 获取进程ID
ULONG64 processId = inMetaValues->processId;
UCHAR szProcessPath[256] = { 0 };
CHAR szProtocalName[256] = { 0 };
RtlZeroMemory(szProcessPath, 256);// 获取进程路径
for (ULONG i = 0; i < inMetaValues->processPath->size; i++)
{// 里面是宽字符存储的szProcessPath[i] = inMetaValues->processPath->data[i];
}// 获取当前协议类型
ProtocalIdToName(inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint16, szProtocalName);
拦截浏览器上网: 防火墙的默认规则我们将其改为放行所有classifyOut->actionType = FWP_ACTION_PERMIT;
,当我们需要拦截特定进程上网时则只需要判断调用原,如果时特定进程则直接设置拒绝网络访问。
// 设置默认规则 允许连接
classifyOut->actionType = FWP_ACTION_PERMIT;// 禁止指定进程网络连接
if (NULL != wcsstr((PWCHAR)szProcessPath, L"iexplore.exe"))
{// 设置拒绝规则 拒绝连接classifyOut->actionType = FWP_ACTION_BLOCK;classifyOut->rights = classifyOut->rights & (~FWPS_RIGHT_ACTION_WRITE);classifyOut->flags = classifyOut->flags | FWPS_CLASSIFY_OUT_FLAG_ABSORB;DbgPrint("[LyShark.com] 拦截IE网络链接请求... \n");
}
当这段驱动程序被加载后,则用户使用IE访问任何页面都将提示无法访问。
拦截指定IP地址: 防火墙的另一个重要功能就是拦截主机自身访问特定网段,此功能只需要增加过滤条件即可实现,如下当用户访问8.141.58.64
这个IP地址是则会被拦截,如果监测到用户时Ping请求则也会被拦截。
// 如果对端地址是 8.141.58.64 且对端端口是 443 则拒绝连接
if (strcmp(szRemoteAddress, "8.141.58.64") == 0 && strcmp(szRemotePort, "443") == 0)
{DbgPrint("拦截网站访问请求 --> %s : %s \n", szRemoteAddress, szRemotePort);// 设置拒绝规则 拒绝连接classifyOut->actionType = FWP_ACTION_BLOCK;classifyOut->rights = classifyOut->rights & (~FWPS_RIGHT_ACTION_WRITE);classifyOut->flags = classifyOut->flags | FWPS_CLASSIFY_OUT_FLAG_ABSORB;
}
else if (strcmp(szRemotePort, "0") == 0)
{DbgPrint("拦截Ping访问请求 --> %s \n", szRemoteAddress);// 设置拒绝规则 拒绝连接classifyOut->actionType = FWP_ACTION_BLOCK;classifyOut->rights = classifyOut->rights & (~FWPS_RIGHT_ACTION_WRITE);classifyOut->flags = classifyOut->flags | FWPS_CLASSIFY_OUT_FLAG_ABSORB;
}
当这段驱动程序被加载后,则用户主机无法访问8.141.58.64
且无法使用ping命令。
抓取底层数据包: 如果仅仅只是想要输出流经自身主机的数据包,则只需要对特定数据包进行解码即可得到原始数据。
// 输出对端地址字符串 并阻断链接
char szRemoteAddress[256] = { 0 };
char szRemotePort[128] = { 0 };char szLocalAddress[256] = { 0 };
char szLocalPort[128] = { 0 };sprintf(szRemoteAddress, "%u.%u.%u.%u", (ulRemoteIp >> 24) & 0xFF, (ulRemoteIp >> 16) & 0xFF, (ulRemoteIp >> 8) & 0xFF, (ulRemoteIp)& 0xFF);
sprintf(szRemotePort, "%d", uRemotePort);sprintf(szLocalAddress, "%u.%u.%u.%u", (ulLocalIp >> 24) & 0xFF, (ulLocalIp >> 16) & 0xFF, (ulLocalIp >> 8) & 0xFF, (ulLocalIp)& 0xFF);
sprintf(szLocalPort, "%d", uLocalPort);// 显示
DbgPrint("[LyShark.com] 方向: %d -> 协议类型: %s -> 本端地址: %u.%u.%u.%u:%d -> 对端地址: %u.%u.%u.%u:%d -> IRQL: %d -> 进程ID: %I64d -> 路径: %S \n",
wDirection,
szProtocalName,
(ulLocalIp >> 24) & 0xFF,
(ulLocalIp >> 16) & 0xFF,
(ulLocalIp >> 8) & 0xFF,
(ulLocalIp)& 0xFF,
uLocalPort,
(ulRemoteIp >> 24) & 0xFF,
(ulRemoteIp >> 16) & 0xFF,
(ulRemoteIp >> 8) & 0xFF,
(ulRemoteIp)& 0xFF,
uRemotePort,
kCurrentIrql,
processId,
(PWCHAR)szProcessPath);
当这段驱动程序被加载后,则用户可看到流经本机的所有数据包。
相关文章:
驱动开发:内核封装WFP防火墙入门
WFP框架是微软推出来替代TDIHOOK传输层驱动接口网络通信的方案,其默认被设计为分层结构,该框架分别提供了用户态与内核态相同的AIP函数,在两种模式下均可以开发防火墙产品,以下代码我实现了一个简单的驱动过滤防火墙。 WFP 框架分…...
python+vue校园快递代取系统的设计与实现3i0v9
开发语言:Python 框架:django/flask Python版本:python3.7.7 数据库:mysql 数据库工具:Navicat 开发软件:PyCharm 本系统名为“基于vue快递代取系统”,系统主要适用于毕业设计,不…...
C 语言详细教程
目录 第一章 C语言基础知识 第二章 数据类型、运算符和表达式 第三章 结构化程序设计 第四章 数组 第五章 函数 第六章 指针 第七章 结构体类型和自定义类型 第八章 编译预处理 第九章 文件 说明:本教程中的代码除一二三个之外,都在https://ligh…...
函数重载与缺省参数
目录 一 缺省参数 缺省参数分半缺省和全缺省。 2,半缺省参数 3,全缺省参数 4.缺省参数的注意事项 二 函数重载 2 .函数重载参数类型不同强调 三 函数名修饰规则 一 缺省参数 1.缺省参数特性(备胎) 缺省参数是指我们定义函数时有给缺省值的参数…...
线程引入的开销
单线程程序既不存在线程调度,也不存在同步开销,而且不需要使用锁来保证数据结构的一致性。在多个线程的调度和协调过程中都需要一定的性能开销:对于为了提升性能而引入的线程来说,并行带来的性能提升必须超过并发导致的开销。 上下…...
学生成绩管理系统
基于springboot vue实现的学生成绩管理系统 主要模块: 1)学生模块:我的成绩、成绩统计、申述管理、修改密码 2)教师模块:任务管理、对学生班级任务安排、班级学生的成绩查看、申述管理 3)管理员模块&…...
什么是关系模型? 关系模型的基本概念
关系模型由IBM公司研究员Edgar Frank Codd于1970年发表的论文中提出,经过多年的发展,已经成为目前最常用、最重要的模型之一。 在关系模型中有一些基本的概念,具体如下。 (1)关系(Relation)。关系一词与数学领域有关,它是集合基…...
shell编程-02-变量作用域
作用域 局部变量:变量只能在函数内部使用 全局变量:变量可以在当前 Shell 进程中使用 环境变量:变量还可以在子进程中使用 局部变量 函数中定义的变量默认是全局变量,在定义时加上local命令,此时该变量就成了局部变…...
C++服务器框架开发6——日志系统LogFormatter/size_t学习
该专栏记录了在学习一个开发项目的过程中遇到的疑惑和问题。 其教学视频见:[C高级教程]从零开始开发服务器框架(sylar) 上一篇:C服务器框架开发5——日志系统LogAppender/IO类“3种stream”/双感叹号 C服务器框架开发6——日志系统logFormatter/size_t学…...
MYSQL实战45讲笔记--深入浅出索引
深入浅出索引 索引的常见模型 索引模型:是哈希表、有序数组和搜索树。 区别: 哈希表是一种以键 - 值(key-value)存储数据的结构,我们只要输入待查找的值即 key,就可以找到其对应的值即 Value。哈希的思…...
SpringCloudAlibaba:分布式事务之Seata学习
目录 一、分布式事务基础 (一)事务 (二)本地事务 (三)分布式事务 二、Seata概述 1.Seata 的架构包含: 2.其工作原理为: 3.如果需要在 Spring Boot 应用中使用 Seata 进行分布式事务管理,主要步骤为…...
【MySQL数据库 | 第四篇】SQL通用语法及分类
目录 🤔SQL通用语法: 😊语句: 😊注释: 🤔SQL语句分类: 😊1.DDL语句: 😊2.DML语句: 😊3.DQL语言: &…...
Liskov替换原则:用了继承,子类就设计对了吗?
前言 上一篇,我们讲了开放封闭原则,想要让系统符合开放封闭原则,最重要的就是我们要构建起相应的扩展模型,所以,我们要面向接口编程。 而大部分的面向接口编程要依赖于继承实现,继承的重要性不如封装和多…...
腾讯云服务器SA3实例AMD处理器CPU网络带宽性能详解
腾讯云AMD服务器SA3实例CPU采用2.55GHz主频的AMD EPYCTM Milan处理器,睿频3.5GHz,搭载最新一代八通道DDR4,内存计算性能稳定,默认网络优化,最高内网收发能力达1900万pps,最高内网带宽可支持100Gbps。腾讯云…...
接口测试常用测试点
接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换,传递和控制管理过程,以及系统间的相互逻辑依赖关系等。 测试的策略: 接口测试也是属于功…...
Unity之OpenXR+XR Interaction Toolkit接入HTC Vive解决手柄无法使用的问题
前言 随着Unity版本的不断进化,VR的接口逐渐统一,现在大部分的VR项目都开始使用OpenXR开发了。基于OpenXR,我们可以快速适配HTC,Pico,Oculus,等等设备。 今天我们要说的问题就是,当我们按照官方的标准流程配置完OpenXR后(参考:Unity之OpenXR+XR Interaction Toolkit…...
AC变DC220V变5V小家电电源芯片-AH8652、AH8669
Q: 什么是AH8652和AH8669电源芯片? A: AH8652和AH8669都是AC变DC的电源芯片,适用于将输入的交流电压(220V)转换为5V直流电压输出,用于小家电的电源模块等应用。 AC变DC220V变5V小家电电源芯片-AH8669 Q: AH8652和AH8669的最大输…...
深度学习笔记之循环神经网络(九)GRU的反向传播过程
深度学习笔记之循环神经网络——GRU的反向传播过程 引言回顾: GRU \text{GRU} GRU的前馈计算过程场景设计 反向传播过程 T \mathcal T T时刻的反向传播过程 T − 1 \mathcal T - 1 T−1时刻的反向传播路径 T − 2 \mathcal T - 2 T−2时刻的反向传播路径 总结 引言 …...
ISFP型人格的性格缺陷和心理问题分析
ISFP人格的特征:性格敏感、为人善良、是具有有创造力的人格类型。他们喜欢追求内心的感受和情感,注重自由、个性和独立。ISFP性人格偏于内向,善于自省,对情绪敏感度高,同理心强。 每种人格类型的都有各自的优势和不足…...
HTML <dir> 标签
HTML5 中不支持 <dir> 标签在 HTML 4 中用于列出目录标题。 实例 目录列表: <dir><li>HTML</li><li>XHTML</li><li>CSS</li> </dir>浏览器支持 IEFirefoxChromeSafariOpera 所有主流浏览器都支持 <…...
leetcode 621. 任务调度器
题目链接:leetcode 621 1.题目 给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表。其中每个字母表示一种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。在任何一个单位时间,CPU 可以完成一个…...
线程任务的取消
如果外部代码能在某个操作正常完成之前将其置入“完成”状态,那么这个操作就可以称为可取消的(Cancellable)。取消某个操作的原因很多: 用户请求取消。用户点击图形界面程序中的“取消”按钮,或者通过管理接口来发出取消请求,例如JMX (Java …...
在线聊天项目
人事管理项目-在线聊天 后端接口实现前端实现 在线聊天是一个为了方便HR进行快速沟通提高工作效率而开发的功能,考虑到一个公司中的HR并不多,并发量不大,因此这里直接使用最基本的WebSocket来完成该功能。 后端接口实现 要使用WebSocket&…...
动态规划-硬币排成线
动态规划-硬币排成线 1 描述2 样例2.1 样例 1:2.2 样例 2:2.3 样例 3: 3 算法解题思路及实现3.1 算法解题分析3.1.1 确定状态3.1.2 转移方程3.1.3 初始条件和边界情况3.1.4 计算顺序 3.2 算法实现3.2.1 动态规划常规实现3.2.2 动态规划滚动数组 该题是lintcode的第394题&#x…...
有效的括号——力扣20
题目描述 思路 1.判断括号的有效性可以使用「栈」这一数据结构来解决 2.遍历给定的字符串 s。当遇到一个左括号时,我们会期望在后续的遍历中,有一个相同类型的右括号将其闭合。由于后遇到的左括号要先闭合,因此我们可以将这个左括号放入栈顶。…...
【轻量级网络】华为诺亚:VanillaNet
文章目录 0. 前言1. 网络结构2. VanillaNet非线性表达能力增强策略2.1 深度训练2.2 扩展激活函数 3. 总结4. 参考 0. 前言 随着人工智能芯片的发展,神经网络推理速度的瓶颈不再是FLOPs或参数量,因为现代GPU可以很容易地进行计算能力较强的并行计算。相比…...
读写ini配置文件(C++)
文章目录 1、为什么要使用ini或者其它(例如xml,json)配置文件?2、ini文件基本介绍3、ini配置文件的格式4、C读写ini配置文件5、 代码示例6、 配置文件的解析库 文章转载于:https://blog.csdn.net/weixin_44517656/article/details/109014236 1、为什么要…...
Python对接亚马逊电商平台SP-API的一些概念理解准备
❝ 除了第三方服务商,其实亚马逊卖家本身也可以通过和SP-API的对接,利用程序来自动化亚马逊店铺销售运营管理中很多环节的工作,简单的应用比如可以利用SP-API的对接,实现亚马逊卖家后台各类报表的定期自动下载以及数据分析整理工…...
[Halcon3D] 主流的3D光学视觉方案及原理
📢博客主页:https://loewen.blog.csdn.net📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢本文由 丶布布原创,首发于 CSDN,转载注明出处🙉📢现…...
Go Web下gin框架使用(二)
〇、gin 路由 Gin是一个用于构建Web应用程序的Go语言框架,它具有简单、快速、灵活的特点。在Gin中,可以使用路由来定义URL和处理程序之间的映射关系。 r : gin.Default()// 访问 /index 这个路由// 获取信息r.GET("/index", func(c *gin.Con…...
电子商务网站建设对毕业设计/域名怎么注册
你的类需要一个构造函数吗?你的数据成员是私有的吗?你的类需要一个无参的构造函数吗?------没有无参构造函数,将无法定义该类的数组是不是每个构造函数初始化所有的数据成员?------------有些数据成员,只有…...
福州网站设计服务/优化网站排名工具
代码层面 IO对象或者数据库的连接对象 使用好后,需要close或clear掉 try{使用Connection或IO等对象} catch(Exception){异常处理} finally{关闭对象}当我们使用好对象时,应该把它设为null,这样可以尽快撤销这个对象上…...
做网站服务器要什么系统/简述什么是seo
原文地址...
wordpress注册邮件验证/新闻软文推广案例
异常 原因 是我浏览器使用的广告拦截插件阻止了请求的发送。我这里使用的广告拦截插件是ADGUARD。 解决 关闭该插件,但为了其他网页能拦截广告,应该过滤掉该页面。 能正常发送了 参考链接:接口请求跳坑: Status (blocked:other)…...
展馆设计施工一体化/外贸建站seo
近日,北京新数科技有限公司旗下核心软件产品ShinData DMP数据库云管理平台、ShinSight Pro监控和性能分析软件在华为云严选商城正式上架。两款产品完成和华为云GaussDB数据库的兼容性认证,为用户数据库管理体系建设提供快速落地的解决方案,助…...
扁平化wordpress主题/成都搜狗seo
Spring Mvc在所有内部日志中使用Commons Logging 默认情况下,Spring Boot会用Logback来记录日志, 假如maven依赖中添加了spring-boot-starter-logging: 那么,我们的Spring Boot应用将自动使用logback作为应用日志框架ÿ…...