我想知道如何在内核模式下计算通过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 ,
FWPS_CLASSIFY_OUT0* classifyOut)
{
if (FlagOn(classifyOut->rights, FWPS_RIGHT_ACTION_WRITE))
{
classifyOut->actionType = FWP_ACTION_CONTINUE;
}
ProcessTransportData(inFixedValues, inMetaValues, layerData, classifyOut);
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”。有什么解决方案吗?谢谢