代码之家  ›  专栏  ›  技术社区  ›  daryldxn

Windows筛选平台计算通过TCP连接发送的字节和接收的字节

  •  0
  • daryldxn  · 技术社区  · 1 年前

    我想知道如何在内核模式下计算通过TCP连接发送的字节和接收的字节。 我想到的是在FWPM_LAYER_ALE_ESTABLISHED_FLOW_V4中创建一个callout,以拦截现在发生的每个新TCP连接,然后将ClassifyFn放入LayerData,然后放入streamData,streamData有一个名为dataLength(size_t,8字节)的成员。但我不明白如何区分发送的字节和接收的字节?对于属性连接,只有一个名为dataLength的成员。你有什么建议吗?

    现在我的代码如下所示:

    static NTSTATUS InitializeCallout(PDEVICE_OBJECT deviceObject)
    {
        FWPM_SUBLAYER subLayer = {};
        subLayer.displayData.name = const_cast<wchar_t*>(L"TcpInterception Sub-Layer");
        subLayer.subLayerKey = TCP_INTERCEPTION_SUBLAYER;
    
        NTSTATUS status = FwpmSubLayerAdd(g_engineHandle, &subLayer, nullptr);
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    
        FWPS_CALLOUT0 sCallout =
        {
            TCP_INTERCEPTION_TRANSPORT_V4_CALLOUT,
            0,
            CalloutConnectClassifyFn,
            CalloutNotifyFn,
            nullptr
        };
    
        status = FwpsCalloutRegister0(deviceObject, &sCallout, &g_id);
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    
        FWPM_CALLOUT mCallout = {};
        mCallout.calloutKey = TCP_INTERCEPTION_TRANSPORT_V4_CALLOUT;
        mCallout.applicableLayer = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
        mCallout.displayData.name = const_cast<wchar_t*>(g_displayName);
    
        status = FwpmCalloutAdd(g_engineHandle, &mCallout, nullptr, nullptr);
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    
        FWPM_FILTER_CONDITION filterCondition = {};
        filterCondition.fieldKey = FWPM_CONDITION_IP_PROTOCOL;
        filterCondition.matchType = FWP_MATCH_EQUAL;
        filterCondition.conditionValue.type = FWP_UINT8;
        filterCondition.conditionValue.uint16 = IPPROTO_TCP;
    
        FWPM_FILTER filter = {};
        filter.layerKey = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
        filter.displayData.name = const_cast<wchar_t*>(g_displayName);;
        filter.displayData.description = filter.displayData.name;
    
        filter.action.type = FWP_ACTION_CALLOUT_UNKNOWN;
        filter.action.calloutKey = TCP_INTERCEPTION_TRANSPORT_V4_CALLOUT;
        filter.filterCondition = &filterCondition;
        filter.numFilterConditions = 1;
        filter.subLayerKey = FWPM_SUBLAYER_UNIVERSAL;
        filter.weight.type = FWP_EMPTY;
    
        status = FwpmFilterAdd(g_engineHandle, &filter, NULL, NULL);
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    
        return status;
    }
    
    static void CalloutConnectClassifyFn(
        const FWPS_INCOMING_VALUES0* inFixedValues,
        const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
        void* layerData,
        const FWPS_FILTER0* filter,
        UINT64 /*flowContext*/,
        FWPS_CLASSIFY_OUT0* classifyOut)
    {
        // Allowing the traffic for another filter to make a final decision.
        if (FlagOn(classifyOut->rights, FWPS_RIGHT_ACTION_WRITE))
        {
            classifyOut->actionType = FWP_ACTION_CONTINUE;
        }
    
        ProcessTransportData(inFixedValues, inMetaValues, layerData, classifyOut);
    
        // Callout function should clear the FWPS_RIGHT_ACTION_WRITE flag when it returns FWP_ACTION_BLOCK for the suggested action
        // and if FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT flag is set
        if (FWP_ACTION_BLOCK == classifyOut->actionType || FlagOn(filter->flags, FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT))
        {
            ClearFlag(classifyOut->rights, FWPS_RIGHT_ACTION_WRITE);
        }
    }
    

    在ProcessTransportData中,我将向调试器打印一些关于某些连接的信息:

    static void ProcessTransportData(const FWPS_INCOMING_VALUES0* inFixedValues,
        const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
        void* layerData,
        FWPS_CLASSIFY_OUT0* classifyOut)
    {
        ULONGLONG processId = (ULONGLONG)inMetaValues->processId;
    
        UINT32 localAddress = inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS].value.uint32;
        UINT32 remoteAddress = inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_ADDRESS].value.uint32;
        UINT16 localPort = inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_PORT].value.uint16;
        UINT16 remotePort = inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_PORT].value.uint16;
    
        if (inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION].value.uint32 == FWP_DIRECTION_INBOUND)
        {
            KdPrint(("Inbound connection\n"));
        }
        else if (inFixedValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION].value.uint32 == FWP_DIRECTION_OUTBOUND)
        {
            KdPrint(("Outbound connection\n"));
        }
    
        KdPrint(("Process Id: %I64u\n", processId));
        KdPrint(("Local IP: %d.%d.%d.%d\n", localAddress & 0xFF, (localAddress >> 8) & 0xFF, (localAddress >> 16) & 0xFF, (localAddress >> 24) & 0xFF));
        KdPrint(("Remote IP: %d.%d.%d.%d\n", remoteAddress & 0xFF, (remoteAddress >> 8) & 0xFF, (remoteAddress >> 16) & 0xFF, (remoteAddress >> 24) & 0xFF));
        KdPrint(("Local Port: %d\n", localPort));
        KdPrint(("Remote Port: %d\n", remotePort));
    }
    

    在那里,我假设我可以通过LayerData访问这个dataLength成员,但我仍然不知道如何检索BYTES SENT和BYTES RECEIVED。我在考虑流V4层,但我遇到了另一个困难,那就是为TCPPROTOO_IP添加一个过滤器,但这个层没有字段“IP_PROTOCOL”。有什么解决方案吗?谢谢

    0 回复  |  直到 1 年前
    推荐文章