驱动开发:内核封装WFP防火墙入门

news2024/11/16 5:32:20

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:
	{
		// ICMP
		RtlCopyMemory(lpszProtocalName, "ICMP", 5);
		break;
	}
	case 2:
	{
		// IGMP
		RtlCopyMemory(lpszProtocalName, "IGMP", 5);
		break;
	}
	case 6:
	{
		// TCP
		RtlCopyMemory(lpszProtocalName, "TCP", 4);
		break;
	}
	case 17:
	{
		// UDP
		RtlCopyMemory(lpszProtocalName, "UDP", 4);
		break;
	}
	case 27:
	{
		// RDP
		RtlCopyMemory(lpszProtocalName, "RDP", 6);
		break;
	}
	default:
	{
		// UNKNOW
		RtlCopyMemory(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)
	{
		// 删除FilterId
		FwpmFilterDeleteById(g_hEngine, g_AleConnectFilterId);
		// 删除CalloutId
		FwpmCalloutDeleteById(g_hEngine, g_AleConnectCalloutId);
		// 清空Filter
		g_AleConnectFilterId = 0;
		// 反注册CalloutId
		FwpsCalloutUnregisterById(g_AleConnectCalloutId);
		// 清空CalloutId
		g_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;

	// 注册Callout
	status = 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 };

	// 设置Callout
	sCallout.calloutKey = *calloutKey;
	sCallout.classifyFn = classifyFn;
	sCallout.flowDeleteFn = flowDeleteNotifyFn;
	sCallout.notifyFn = notifyFn;

	// 注册Callout
	status = 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 };

	// 创建Session
	session.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 = 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;

	// 禁止指定进程网络连接
	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);

	// 启动WFP
	WfpLoad(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 = 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;

	// 禁止指定进程网络连接
	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);

当这段驱动程序被加载后,则用户可看到流经本机的所有数据包。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/635003.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

触发器和事件自动化的讲解

触发器和事件自动化 一、触发器 1、触发器的基本概念 触发器是和表相关的一种数据库对象&#xff0c;可以将他看作一种特殊的存储过程&#xff0c;不需要人为调动的存储过程。 关键字&#xff1a;trigger 基本作用&#xff1a;通过对表进行数据的插入、更新或删除等操作来触…

UnityVR--AudioManager--音频管理中心

目录 前言 建立音频配置文件AudioConfig 建立音频管理AudioManager 使用AudioManager播放音效 前言 关于音频组件的简单使用请详见VideoPlayer&AudioSource&#xff0c;不过在一个工程项目中&#xff0c;会有很多的声音文件&#xff0c;播放的时间和条件也不相同&#…

【算法题】2614. 对角线上的质数

题目&#xff1a; 给你一个下标从 0 开始的二维整数数组 nums 。 返回位于 nums 至少一条 对角线 上的最大 质数 。如果任一对角线上均不存在质数&#xff0c;返回 0 。 注意&#xff1a; 如果某个整数大于 1 &#xff0c;且不存在除 1 和自身之外的正整数因子&#xff0c;…

Docker环境下部署Ghost开源内容管理系统

Docker环境下部署Ghost开源内容管理系统 一、Ghost介绍1.1 Ghost简介1.2 Ghost特点 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载Ghost镜像五、部署Ghost开源内容管理系统…

【linux工具备忘录】- tmux

文章目录 安装常用命令会话的进入和退出窗口创建、删除、切换窗口内的子窗口管理(创建/删除/切换)会话的后台托管管理 tmux的配置配置的创建配置重载修改前缀键更多使用说明 tmux的插件管理tpm插件管理器tmux-powerline 一个漂亮的底栏 安装 sudo apt install tmux常用命令 会…

分布式软件架构——RESTful服务

RESTful&#xff08;Representational State Transfer&#xff09; RESTful是一种网络应用程序的设计风格和开发方式&#xff0c;基于HTTP&#xff0c;可以使用XML格式定义或JSON格式定义。RESTFUL适用于移动互联网厂商作为业务接口的场景&#xff0c;实现第三方OTT调用移动网…

shell脚本基础2——条件语句、分支选择、循环语句

文章目录 一、条件语句二、分支选择三、循环语句3.1 for循环3.1.1 语法一3.1.2 语法二 3.2 while循环3.2.1 普通用法3.2.2 whileif判断循环3.2.3 特殊用法 3.3 until循环 四、break和continue4.1 break用法4.2 continue用法 五、自定义脚本退出状态码 一、条件语句 使用 if 语句…

XdsObjects .NET 8.45.1001.0 Crack

XdsObjects 是一个工具包&#xff0c;允许开发人员使用 IHE XDS 和 XDS-I 配置文件开发应用程序&#xff0c;只需花费最少的时间和精力&#xff0c;因为遵守配置文件和 ebXML 规则的所有艰苦工作都由该工具包处理。 它为所有角色提供客户端和服务器支持&#xff0c;包括&#…

【Spring MVC】学会这些你就会利用Spring Boot进行前后端交互了,美滋滋,距离编程世界更近一步了,何乐而不为呢 ? ? ?

前言: 大家好,我是良辰丫,! ! !&#x1f48c;&#x1f48c;&#x1f48c; &#x1f9d1;个人主页&#xff1a;良辰针不戳 &#x1f4d6;所属专栏&#xff1a;javaEE进阶篇之框架学习 &#x1f34e;励志语句&#xff1a;生活也许会让我们遍体鳞伤&#xff0c;但最终这些伤口会成…

【仪器使用操作笔记】 TDS1012示波器基础原理与使用

今日要学习使用的是一台实验室老旧战损版TDS1012示波器&#xff0c;它长这样&#xff1a; 本文会从以下目录的几个方面全方位介绍示波器的一些基础运用&#xff1a; 目录 一、面板按键旋钮介绍&#xff1a; 整体面板介绍&#xff1a; 示波器探头接线与校准接线&#xff1a; …

一文弄懂java中的代理模式

文章目录 简介静态代理动态代理Cglib代理spring中AOP使用代理总结 简介 代理(Proxy)模式是一种结构型设计模式&#xff0c;提供了对目标对象另外的访问方式&#xff1b;即通过代理对象访问目标对象。 这样做的好处是&#xff1a;可以在目标对象实现的基础上&#xff0c;增强额…

Atcoder Beginner Contest 305——D-F题讲解

蒟蒻来讲题&#xff0c;还望大家喜。若哪有问题&#xff0c;大家尽可提&#xff01; Hello, 大家好哇&#xff01;本初中生蒟蒻讲解一下AtCoder Beginner Contest 305这场比赛的D-F题&#xff01; D题 题外话 安利一波自己的洛谷博客&#xff1a;点这里 思路 这道题还是比…

Hazel游戏引擎(010)预编译头

文中若有代码、术语等错误&#xff0c;欢迎指正 文章目录 前言如何实现 前言 此节目的 由于项目中的头文件或者cpp文件都包含着c的头文件&#xff0c;有些重复&#xff0c;可以将它们包含的c头文件放在一个头文件内&#xff0c;这样不仅使代码简洁&#xff0c;而且预编译头可以…

算法刷题-哈希表-两个数组的交集

两个数组的交集 349. 两个数组的交集思路拓展后记其他语言版本相关题目 如果哈希值比较少、特别分散、跨度非常大&#xff0c;使用数组就造成空间的极大浪费&#xff01; 349. 两个数组的交集 力扣题目链接 题意&#xff1a;给定两个数组&#xff0c;编写一个函数来计算它们的…

Java集合框架:ArrayList详解

目录 一、ArrayList简介 二、ArrayList源码介绍&#xff08;动态扩容以及构造方法是如何实现的&#xff09; 1. 扩容机制&#xff1a; 源码&#xff1a; 源码详解&#xff1a; ​编辑 如何扩容&#xff1a; 2. 扩容源码详解&#xff1a; 三、ArrayList的构造方法 四、ArrayL…

【Linux运维】GitLab本地服务器搭建

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍gitlab本地服务器的搭建。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习知识&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更新…

【JVM内存模型】—— 每天一点小知识

&#x1f4a7; J V M 内存模型 \color{#FF1493}{JVM内存模型} JVM内存模型&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞见云的博客&#x1f390; &#x1f433; 《数据结构与算法》专栏的文章图文并茂&#x…

MyBatis-plus(2)

实现逻辑查询: 1)and:其实如果只是想实现and查询&#xff0c;只是需要连续调用对应的方法或者是通过wrapper对象实现两次调用即可 2)and的嵌套:假设现在有这样一条语句 select * from user where username"张三" and (age>26 or userID <19)&#xff0c;这条SQ…

使用django的APP在前端上传excel通过post传给后端读取并打印

文章目录 前言前端后端 前言 备研了&#xff0c;博客许久未更了&#xff0c;但是学期末的大作业&#xff0c;遇到了问题并成功解决了&#xff0c;不得不记录一下。 前端 <form method"post" enctype"multipart/form-data" action"/insurance/up…

Hazel游戏引擎(011)窗口抽象和GLFW创建窗口

文中若有代码、术语等错误&#xff0c;欢迎指正 文章目录 前言步骤GIT添加GLFW子模块及编译Window类其它修改 效果Bug记录 前言 此节目的 为了有窗口效果&#xff0c;但不想使用原生的window32写起&#xff0c;所以用glfw窗口库。 也为了完成008计划事件系统的创建窗口部分 图…