在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]);
}
}