WFP之关联上下文数据以及注意事项

2 篇文章 0 订阅
2 篇文章 0 订阅

在WFP框架中,针对一条流数据在应用层会获取到pid,但是到内核层就无法获取pid.基于此问题,想通过关联上下文的功能进行数据传递或者流标记.(这里写的稍微简单,后面有空再更新详细些的)

一.基本理论

微软官网文档写的比较清楚,但是缺少一些细节以及注意事项,因此新手容易踩坑.这里主要写一下注意事项

二.实现方式

基于官方实例即可

三.注意事项

1.关联后需要删除
2.对于并发流量需要保存handle
3.关联的上下文需要分配内存
4.注意存和取所对应的层id
5.目前只能关联到tcp层,后面研究看是否能关联到更底层,或者对于流打标记
6.最后关闭驱动的时候统一清理全部的handle,否则sys会被异常占用

四.实例代码

//==================================================================== 关联上下文
	//创建关联信息
	flowContextLocal = ENCreateFlowContext(inValues, inMetaValues, &flowHandle);
	if (!flowContextLocal)
	{
		return;
	}

	//关联上下文
	status = FwpsFlowAssociateContext(flowHandle,
		FWPS_LAYER_OUTBOUND_TRANSPORT_V4,
		g_callouts[2].calloutID,
		flowContextLocal);

	if (!NT_SUCCESS(status))
	{
		if (status == STATUS_INVALID_PARAMETER)
		{
			ERROR("[FlowCtx]An invalid parameter was passed to a service or function.");
		}
		else if (status == STATUS_OBJECT_NAME_EXISTS)
		{
			ERROR("[FlowCtx]An attempt was made to create an object and the object name already existed.");
		}
		else {
			ERROR("[FlowCtx]other error");
		}
		return;
	}

	//处理获取关联handle
	KeAcquireSpinLock(pFlowCtxLock, &irql);
	if (ctx->FlowCtxHandleNum >= EN_MAX_FLOW_CTX)
	{
		ctx->FlowCtxHandleNum = ctx->FlowCtxHandleNum - EN_MAX_FLOW_CTX;
	}

	status = FwpsFlowRemoveContext(ctx->FlowCtxHandle[ctx->FlowCtxHandleNum],
		FWPS_LAYER_OUTBOUND_TRANSPORT_V4,
		g_callouts[2].calloutID);

	ctx->FlowCtxHandle[ctx->FlowCtxHandleNum] = inMetaValues->flowHandle;
	ctx->FlowCtxHandleNum++;
	KeReleaseSpinLock(pFlowCtxLock, irql);

	DEBUG("[FlowCtx]flowNum:%d,handle:%d [id:%d] [proto:%d] sAddr:local:%u dAddr:%u.%u.%u.%u:%u"
		, ctx->FlowCtxHandleNum, (UINT32)inMetaValues->flowHandle, processid, remoteProto
		, localPort, NIPQUAD(remoteAddr), remotePort);
	out->actionType = FWP_ACTION_PERMIT;

	if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
	{
		out->rights &= ~FWPS_RIGHT_ACTION_WRITE;
	}
	return;

/*
	Routine Description
		Creates a flow context that is associated with the current flow
	Arguments
		[IN] FWPS_CALLOUT_NOTIFY_TYPE        notifyType  -   Type of notification
		[IN] GUID*                  filterKey   -   Key of the filter that was
													added/deleted/modified.
		[IN] struct FWPS_FILTER_*  filter      -   pointer to the Filter itself.
	Return values
		STATUS_SUCCESS or a specific error code.
	Notes
*/
UINT64 ENCreateFlowContext(
	_In_ const FWPS_INCOMING_VALUES* inFixedValues,
	_In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
	_Out_ UINT64* flowHandle)
{
	FLOW_DATA* flowContext = NULL;
	NTSTATUS       status;
	FWP_BYTE_BLOB* processPath;
	UINT32         index;

	*flowHandle = 0;

	if (!FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_PROCESS_PATH))
	{
		status = STATUS_NOT_FOUND;
		goto cleanup;
	}

	processPath = inMetaValues->processPath;

	status = ENAllocFlowContext(processPath->size, &flowContext);
	if (!NT_SUCCESS(status))
	{
		goto cleanup;
	}

	//  Flow context is always created at the Flow established layer.

	flowContext->deleting = FALSE;
	flowContext->flowHandle = inMetaValues->flowHandle;
	flowContext->processid = inMetaValues->processId;
	*flowHandle = flowContext->flowHandle;

	index = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS;
	flowContext->localAddressV4 = inFixedValues->incomingValue[index].value.uint32;

	index = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT;
	flowContext->localPort = inFixedValues->incomingValue[index].value.uint16;

	index = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS;
	flowContext->remoteAddressV4 = inFixedValues->incomingValue[index].value.uint32;

	index = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT;
	flowContext->remotePort = inFixedValues->incomingValue[index].value.uint16;

	index = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL;
	flowContext->ipProto = inFixedValues->incomingValue[index].value.uint16;

	memcpy(flowContext->processPath, processPath->data, processPath->size);

cleanup:

	if (!NT_SUCCESS(status))
	{
		flowContext = NULL;
	}

	return (UINT64)(uintptr_t)flowContext;
}

NTSTATUS ENAllocFlowContext(
	_In_ SIZE_T processPathSize,
	_Out_ FLOW_DATA** flowContextOut)
{
	NTSTATUS status = STATUS_SUCCESS;
	FLOW_DATA* flowContext = NULL;

	*flowContextOut = NULL;

	flowContext = ExAllocatePoolZero(NonPagedPool,
		sizeof(FLOW_DATA),
		TAG_NAME_CALLOUT);

	if (!flowContext)
	{
		status = STATUS_NO_MEMORY;
		goto cleanup;
	}

	RtlZeroMemory(flowContext,
		sizeof(FLOW_DATA));


	flowContext->processPath = ExAllocatePoolZero(NonPagedPool,
		processPathSize,
		TAG_NAME_CALLOUT);
	if (!flowContext->processPath)
	{
		status = STATUS_NO_MEMORY;
		goto cleanup;

	}

	*flowContextOut = flowContext;

cleanup:
	if (!NT_SUCCESS(status))
	{
		if (flowContext)
		{
			if (flowContext->processPath)
			{
				ExFreePoolWithTag(flowContext->processPath, TAG_NAME_CALLOUT);
			}
			ExFreePoolWithTag(flowContext, TAG_NAME_CALLOUT);
		}
	}

	return status;
}


//清理关联的上下文
void ENCalloutFlowDeleteNotifyFn0(
	UINT16 layerId,
	UINT32 calloutId,
	UINT64 flowContext)
{
	//NTSTATUS status = STATUS_SUCCESS;

	FLOW_DATA* flowctx = (FLOW_DATA*)flowContext;
	if (flowctx)
	{
		始终返回STATUS_UNSUCCESSFUL,且会占用sys,不在这里清理
		/*status = FwpsFlowRemoveContext(flowctx->flowHandle,
			FWPS_LAYER_OUTBOUND_TRANSPORT_V4,
			g_callouts[1].calloutID);
		if (!NT_SUCCESS(status))
		{
			if (status == STATUS_UNSUCCESSFUL)
			{
				ERROR("[FlowCtx][%d]There is no context currently associated with the data flow!!", (UINT32)flowctx->flowHandle);
			}
			else {
				ERROR("[FlowCtx][%d]Remove Flow Context error!!", (UINT32)flowctx->flowHandle);
			}
		}
		else {
			DEBUG("[FlowCtx]Remove Flow Context success");
		}*/

		if (flowctx->processPath)
		{
			ExFreePoolWithTag(flowctx->processPath, TAG_NAME_CALLOUT);
		}
		ExFreePoolWithTag(flowctx, TAG_NAME_CALLOUT);
	}

	return;
}

关闭驱动,清理

NTSTATUS status = STATUS_SUCCESS;
	//始终返回STATUS_UNSUCCESSFUL
	for (UINT32 i = 0; i < ctx->FlowCtxHandleNum; i++)
	{
		if (ctx->FlowCtxHandle[i] == 0)
		{
			continue;
		}
		status = FwpsFlowRemoveContext(ctx->FlowCtxHandle[i],
			FWPS_LAYER_OUTBOUND_TRANSPORT_V4,
			g_callouts[2].calloutID);
		if (!NT_SUCCESS(status))
		{
			if (status == STATUS_UNSUCCESSFUL)
			{
				ERROR("[FlowCtx][%d]There is no context currently associated with the data flow!!", (UINT32)ctx->FlowCtxHandle[i]);
			}
			else {
				ERROR("[FlowCtx][%d]Remove Flow Context error!!", (UINT32)ctx->FlowCtxHandle[i]);
			}
		}
		else {
			DEBUG("[FlowCtx][%d]Remove Flow Context success", (UINT32)ctx->FlowCtxHandle[i]);
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值