当前位置: 首页 > news >正文

驱动开发:内核封装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传输层驱动接口网络通信的方案&#xff0c;其默认被设计为分层结构&#xff0c;该框架分别提供了用户态与内核态相同的AIP函数&#xff0c;在两种模式下均可以开发防火墙产品&#xff0c;以下代码我实现了一个简单的驱动过滤防火墙。 WFP 框架分…...

python+vue校园快递代取系统的设计与实现3i0v9

开发语言&#xff1a;Python 框架&#xff1a;django/flask Python版本&#xff1a;python3.7.7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyCharm 本系统名为“基于vue快递代取系统”&#xff0c;系统主要适用于毕业设计&#xff0c;不…...

C 语言详细教程

目录 第一章 C语言基础知识 第二章 数据类型、运算符和表达式 第三章 结构化程序设计 第四章 数组 第五章 函数 第六章 指针 第七章 结构体类型和自定义类型 第八章 编译预处理 第九章 文件 说明&#xff1a;本教程中的代码除一二三个之外&#xff0c;都在https://ligh…...

函数重载与缺省参数

目录 一 缺省参数 缺省参数分半缺省和全缺省。 2&#xff0c;半缺省参数 3&#xff0c;全缺省参数 4.缺省参数的注意事项 二 函数重载 2 .函数重载参数类型不同强调 三 函数名修饰规则 一 缺省参数 1.缺省参数特性(备胎) 缺省参数是指我们定义函数时有给缺省值的参数&#xf…...

线程引入的开销

单线程程序既不存在线程调度&#xff0c;也不存在同步开销&#xff0c;而且不需要使用锁来保证数据结构的一致性。在多个线程的调度和协调过程中都需要一定的性能开销&#xff1a;对于为了提升性能而引入的线程来说&#xff0c;并行带来的性能提升必须超过并发导致的开销。 上下…...

学生成绩管理系统

基于springboot vue实现的学生成绩管理系统 主要模块&#xff1a; 1&#xff09;学生模块&#xff1a;我的成绩、成绩统计、申述管理、修改密码 2&#xff09;教师模块&#xff1a;任务管理、对学生班级任务安排、班级学生的成绩查看、申述管理 3&#xff09;管理员模块&…...

什么是关系模型? 关系模型的基本概念

关系模型由IBM公司研究员Edgar Frank Codd于1970年发表的论文中提出&#xff0c;经过多年的发展&#xff0c;已经成为目前最常用、最重要的模型之一。 在关系模型中有一些基本的概念&#xff0c;具体如下。 (1)关系(Relation)。关系一词与数学领域有关&#xff0c;它是集合基…...

shell编程-02-变量作用域

作用域 局部变量&#xff1a;变量只能在函数内部使用 全局变量&#xff1a;变量可以在当前 Shell 进程中使用 环境变量&#xff1a;变量还可以在子进程中使用 局部变量 函数中定义的变量默认是全局变量&#xff0c;在定义时加上local命令&#xff0c;此时该变量就成了局部变…...

C++服务器框架开发6——日志系统LogFormatter/size_t学习

该专栏记录了在学习一个开发项目的过程中遇到的疑惑和问题。 其教学视频见&#xff1a;[C高级教程]从零开始开发服务器框架(sylar) 上一篇&#xff1a;C服务器框架开发5——日志系统LogAppender/IO类“3种stream”/双感叹号 C服务器框架开发6——日志系统logFormatter/size_t学…...

MYSQL实战45讲笔记--深入浅出索引

深入浅出索引 索引的常见模型 索引模型&#xff1a;是哈希表、有序数组和搜索树。 区别&#xff1a; 哈希表是一种以键 - 值&#xff08;key-value&#xff09;存储数据的结构&#xff0c;我们只要输入待查找的值即 key&#xff0c;就可以找到其对应的值即 Value。哈希的思…...

SpringCloudAlibaba:分布式事务之Seata学习

目录 一、分布式事务基础 &#xff08;一&#xff09;事务 &#xff08;二&#xff09;本地事务 &#xff08;三&#xff09;分布式事务 二、Seata概述 1.Seata 的架构包含: 2.其工作原理为: 3.如果需要在 Spring Boot 应用中使用 Seata 进行分布式事务管理,主要步骤为…...

【MySQL数据库 | 第四篇】SQL通用语法及分类

目录 &#x1f914;SQL通用语法&#xff1a; &#x1f60a;语句&#xff1a; &#x1f60a;注释&#xff1a; &#x1f914;SQL语句分类&#xff1a; &#x1f60a;1.DDL语句&#xff1a; &#x1f60a;2.DML语句&#xff1a; &#x1f60a;3.DQL语言&#xff1a; &…...

Liskov替换原则:用了继承,子类就设计对了吗?

前言 上一篇&#xff0c;我们讲了开放封闭原则&#xff0c;想要让系统符合开放封闭原则&#xff0c;最重要的就是我们要构建起相应的扩展模型&#xff0c;所以&#xff0c;我们要面向接口编程。 而大部分的面向接口编程要依赖于继承实现&#xff0c;继承的重要性不如封装和多…...

腾讯云服务器SA3实例AMD处理器CPU网络带宽性能详解

腾讯云AMD服务器SA3实例CPU采用2.55GHz主频的AMD EPYCTM Milan处理器&#xff0c;睿频3.5GHz&#xff0c;搭载最新一代八通道DDR4&#xff0c;内存计算性能稳定&#xff0c;默认网络优化&#xff0c;最高内网收发能力达1900万pps&#xff0c;最高内网带宽可支持100Gbps。腾讯云…...

接口测试常用测试点

接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系等。 测试的策略&#xff1a; 接口测试也是属于功…...

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的电源芯片&#xff0c;适用于将输入的交流电压&#xff08;220V&#xff09;转换为5V直流电压输出&#xff0c;用于小家电的电源模块等应用。 AC变DC220V变5V小家电电源芯片-AH8669 Q: AH8652和AH8669的最大输…...

深度学习笔记之循环神经网络(九)GRU的反向传播过程

深度学习笔记之循环神经网络——GRU的反向传播过程 引言回顾&#xff1a; GRU \text{GRU} GRU的前馈计算过程场景设计 反向传播过程 T \mathcal T T时刻的反向传播过程 T − 1 \mathcal T - 1 T−1时刻的反向传播路径 T − 2 \mathcal T - 2 T−2时刻的反向传播路径 总结 引言 …...

ISFP型人格的性格缺陷和心理问题分析

ISFP人格的特征&#xff1a;性格敏感、为人善良、是具有有创造力的人格类型。他们喜欢追求内心的感受和情感&#xff0c;注重自由、个性和独立。ISFP性人格偏于内向&#xff0c;善于自省&#xff0c;对情绪敏感度高&#xff0c;同理心强。 每种人格类型的都有各自的优势和不足…...

HTML <dir> 标签

HTML5 中不支持 <dir> 标签在 HTML 4 中用于列出目录标题。 实例 目录列表&#xff1a; <dir><li>HTML</li><li>XHTML</li><li>CSS</li> </dir>浏览器支持 IEFirefoxChromeSafariOpera 所有主流浏览器都支持 <…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...