微软WFP例子之msnmntr

在看了微软关于wfp的文档,对微软例子中关于流量监控的例程进行学习,对原本的例子进行了少量修改,修改后出现一些偶然的蓝屏dump KERNEL_SECURITY_CHECK_FAILURE(139)

出现问题的函数是在unload中:
样例代码如下:

void MonitorCoUninitialize(void)
/*
Routine Description

   Uninitializes the callouts module (this module) by ensuring that all
   flow contexts are no longer associated with a flow to ensure that
   our driver is not called after it is unloaded.

Arguments

   None.

Return values

   STATUS_SUCCESS or a specific error code.

Notes


*/
{
   LIST_ENTRY list;
   KLOCK_QUEUE_HANDLE lockHandle;

   // Make sure we don't associate any more contexts to flows.
   MonitorCoDisableMonitoring();

   InitializeListHead(&list);

   KeAcquireInStackQueuedSpinLock(&flowContextListLock, &lockHandle);

   while (!IsListEmpty(&flowContextList))
   {
      FLOW_DATA* flowContext;
      LIST_ENTRY* entry;

      entry = RemoveHeadList(&flowContextList);

      flowContext = CONTAINING_RECORD(entry, FLOW_DATA, listEntry);
      flowContext->deleting = TRUE; // We don't want our flow deletion function
                                    // to try to remove this from the list.

      InsertHeadList(&list, entry);
   }

   KeReleaseInStackQueuedSpinLock(&lockHandle);

   while (!IsListEmpty(&list))
   {
      FLOW_DATA* flowContext;
      LIST_ENTRY* entry;
      NTSTATUS status;

      entry = RemoveHeadList(&list);   解了下dump 发现在这里,

      flowContext = CONTAINING_RECORD(entry, FLOW_DATA, listEntry);

      status = FwpsFlowRemoveContext(flowContext->flowHandle,
                                      FWPS_LAYER_STREAM_V4,
                                      streamId);
      NT_ASSERT(NT_SUCCESS(status));
      _Analysis_assume_(NT_SUCCESS(status));
   }

   MonitorCoUnregisterCallouts();
}

对比了原来的代码,原先是在FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4将PID绑定在FWPS_LAYER_STREAM_V4 现在修改为 将fwpm_layer_auth_connect 绑定在FWPM_LAYER_INBOUND_TRANSPORT_V4 ,其他基本没变化,但是在unload过程中,会概率性的发生蓝屏 KERNEL_SECURITY_CHECK_FAILURE(0x139) 解析了下dump 发现崩溃点 在

entry = RemoveHeadList(&list);  

dump 信息为3 One LIST_ENTRY is damaged 有点像链表被删除两次,
A LIST_ENTRY has been corrupted (i.e. double remove). //看着像重复删除

这里看了下代码,在关联pid时,有个flowcontextlist 链表 ,Context生命周期结束时,系统会自动调用Deletion回调函数,从链表删除并释放内存。驱动卸载时,也就是上述代码。通过指定FwpsFlowRemoveContext,将没有销毁的Context销毁掉。调用FwpsFlowRemoveContext后,删除过程还会出现在Deletion回调函数中(注意)。但是看了代码callout中的deletion回调函数也是有锁的,代码如下:

oid MonitorCoStreamFlowDeletion(
   _In_ UINT16 layerId,
   _In_ UINT32 calloutId,
   _In_ UINT64 flowContext)
{
   KLOCK_QUEUE_HANDLE lockHandle;
   FLOW_DATA* flowData;
   HRESULT result;
   ULONG_PTR flowPtr;


   UNREFERENCED_PARAMETER(layerId);
   UNREFERENCED_PARAMETER(calloutId);

   result = ULongLongToULongPtr(flowContext, &flowPtr);
   ASSERT(result == S_OK);
   _Analysis_assume_(result == S_OK);
   

   flowData = ((FLOW_DATA*)flowPtr);

   //
   // If we're already being deleted from the list then we mustn't try to 
   // remove ourselves here.
   //
   KeAcquireInStackQueuedSpinLock(&flowContextListLock, &lockHandle);
   
   if (!flowData->deleting)
   {
      RemoveEntryList(&flowData->listEntry);
   }
   
   KeReleaseInStackQueuedSpinLock(&lockHandle);

   MonitorCoCleanupFlowContext(flowData);
}

因此,这里看同一时间是无法对共享资源进行重复删除的,这里对代码进行了一些debug ,修改后的代码。在auth_connect获取到的PID进行绑定时。 调用FwpsFlowAssociateContext 会出现status-object-name-exists(已关联)。但是这应该不是影响的原因。在想这里会不会是因为,在auth_connect 关联PID 时,存在关联过的,此时这条 数据,仍然创建Context。2.添加到Context链表。 但是关联状态值为 status-object-name-exists 新插入的context 此时是否是无法再flowdetion回调中进行删除的。所以在想会不会是假如有 第一条 关联成功,第二条出现status-object-name-exists
但是都在flowcontextlist 链表上,但是回调中deletion只会释放第一条的链表节点,但是最后unload 进行手动释放,好像也不会出现dump 。重新按照FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4进行关联,看debug信息 返回值都是success 但是如果应用已经在使用时,此时再启动驱动服务,在看流量信息,发现监控的对应pid的数据包就会有问题。用FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4进行关联pid 好像无法监控到应用先运行时刻的流量信息。
这里请教下,第一,dump出现的原因,现在有个场景就是再unload驱动时,会偶然的出现,有点奇怪出现的原因。第二是如果使用FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4 进行关联pid 怎么可以监控到应用先运行,驱动后启动,应用的流量信息。

出现“status-object-name-exists”的原因可能是因为在关联PID时,已经存在一个或多个已关联的Context,导致新的Context无法被正确地添加到Context链表中。
关于dump出现的原因,可能是由于网络不稳定或者服务器性能问题导致的。建议在使用云服务器时,监控网络流量和服务器性能,以及定期清理无用的数据和缓存,以提高系统的稳定性和可用性。

还有一个感到奇怪的点, 在关联PID至其他的层时,步骤如下:
1、创建Context。2.添加到Context链表。3.关联Context。4.在指定层通过参数UINT64 flowContext获取Context。
在第三步,关联context 才会调用FwpsFlowAssociateContext 此时无论成功还是失败,其实都已经在context链表中了,假如
调用FwpsFlowAssociateContext 出现(status-object-name-exists)返回值,context也已经在链表中了,出现status-object-name-exists这种情况,就好像是在flowcontext链表中,但是Deletion回调函数应该是无法释放内存的,同时 绑定的那一层应该也是无法通过参数UINT64 flowContext获取Context这个参数的。 那么当关联pid 返回值出现status-object-name-exists 好像也没有什么好的处理方法

5.使用Context。6.Context生命周期结束时,系统会自动调用Deletion回调函数,你需要在此从链表删除并释放内存。

7.驱动卸载时,通过执行FwpsFlowRemoveContext,将没有销毁的Context销毁掉。调用FwpsFlowRemoveContext后,删除过程还会出现在Deletion回调函数中(注意)。

wfp sample msnmntr的部署和测试

可以借鉴下
https://blog.csdn.net/dailongjian2008/article/details/80371917

从您提供的代码和说明来看,出现蓝屏崩溃的原因有两点:1. 在MonitoringCoUninitialize函数中,同一FLOW_DATA对象可能被重复删除。尽管flowContextListLock锁可以防止同一时间重复删除,但如果驱动卸载时,刚好Deletion回调函数正在操作该FLOW_DATA,那么Unlock后监控模块的删除操作还会重复执行,导致链表结构损坏和蓝屏。2. 使用FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4进行PID关联,无法捕获应用启动前的流量信息。这是因为该层仅捕获连接建立后的流量,应用启动前的流量并不会触发此层的回调。要解决这两个问题,可以采取以下措施:1. 在MonitoringCoUninitialize中添加判断,避免重复删除FLOW_DATA:

if (flowContext->deleting) {
    // 如果正在Deletion回调中删除,跳过
    continue; 
}
// 执行删除操作...
flowContext->deleting = TRUE;  // 标记为删除中

这样可以避免重复删除同一对象,修复蓝屏问题。2. 不使用FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4层,而应使用更底层的层进行PID关联,例如:- FWPM_LAYER_INBOUND_TRANSPORT_V4:捕获入站连接和数据报文,可以监控应用启动前的流量

  • FWPM_LAYER_OUTBOUND_TRANSPORT_V4:监控出站流量
  • FWPM_LAYER_IPFORWARD_V4: 监控转发流量这些更底层的层可以更全面地监控流量,避免应用启动前的信息遗漏。总的来说,要稳定运行此WFP驱动监控模块,需要:1. 避免对象(如FLOW_DATA)的重复删除操作,造成链表或内存破坏。
  1. 选择合适的WFP层进行PID关联和数据包捕获,要考虑被监控应用的启动时间点,避免遗漏关键流量信息。
  2. 其他措施如锁的合理使用,内存管理等也需要注意,这些都是造成驱动不稳定和蓝屏的常见原因。希望以上分析和建议能帮助您解决WFP驱动开发中的问题。

对于出现蓝屏的问题,可能有多种原因,常见的包括:

  1. 硬件故障:如内存故障、硬盘故障、电源故障等。
  2. 软件驱动故障:如有问题的驱动会导致蓝屏,与系统版本和硬件有关,可能进程了执行操作,如查看硬盘相关日志进行错误排查。
  3. 进程/服务崩溃:进程或服务崩溃可能会导致蓝屏。

鉴于您修改了微软的例程并出现了蓝屏,我认为您需要回滚修改,确保代码可以稳定运行,然后再一步步修改,以找出出现蓝屏的原因。

可以尝试分段调试程序,逐步找出代码的问题所在。同时,查看Windows系统事件日志,将其中的异常信息记录下来,有助于识别问题所在。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
首先,关于蓝屏的问题,出现 KERNEL_SECURITY_CHECK_FAILURE(0x139) 原因可能是由于在 MonitorCoUninitialize 函数中,在释放 flow context 的过程中,链表节点被删除两次导致的。这有可能是由于删除已经被删除的节点导致的。可能需要添加额外的检查,确保链表中的每个节点都只被删除一次。也可以在删除节点之前,先检查该节点是否已经被删除,如果已经被删除,则不进行删除操作。

关于监控应用先运行,驱动后启动的流量信息问题,使用 FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4 进行绑定是无法监控到这种情况的,因为该层的回调函数在应用程序已经建立连接之后才会被调用。如果需要监控应用程序启动之后的所有流量,可以考虑使用 FWPM_LAYER_INBOUND_TRANSPORT_V4 或者 FWPM_LAYER_OUTBOUND_TRANSPORT_V4 进行绑定,这样可以监控到传输层的所有流量。但是,这样会包括一些不需要监控的流量,例如系统内部的流量等。因此,在应用程序启动之后进行监控时,需要对监控的流量进行合理的过滤。

此外,你提到在 auth_connect 获取到的 PID 进行绑定时,调用 FwpsFlowAssociateContext 会出现 status-object-name-exists 错误。这个错误通常是由于在 FwpsFlowAssociateContext 被调用之前已经有另外一个流量的 context 和相应的层关联起来了。一般情况下,可以忽略这个错误,因为这个 context 已经与其他流量关联了,因此不需要再关联一次。但是,在流量进行监控时,可能需要注意这个错误,确保每个流量只与一个 context 相关联。如果一个流量与多个 context 关联,则可能会导致未预期的结果。
如果我的回答解决了您的问题,请采纳!

以下答案由GPT-4.5Plus大模型(语音)与博主A努力中.......共同编写:

根据您的描述,出现蓝屏问题的原因可能是:

  1. 在卸载驱动时,重复删除flow context链表上的节点,导致链表结构损坏,从而触发蓝屏。这个问题的解决方法是在删除节点前检查其deleting标志,避免重复删除同一节点。
  2. 卸载驱动时,flow context链表上存在无法正确删除的节点(status-object-name-exists),最终导致链表结构损坏,触发蓝屏。这个问题可能需要在获取flow context时进行额外检查,确保其能够正确删除。

您的疑问2也比较合理。使用FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4层进行关联,无法监控到应用启动前的流量,是因为这个层仅捕获已经建立的连接,而无法捕获连接建立过程中的报文。

要解决这个问题,可以:

  1. 使用FWPM_LAYER_INBOUND_TRANSPORT_V4或FWPM_LAYER_OUTBOUND_TRANSPORT_V4层进行关联。这两个层可以捕获连接建立阶段的报文,所以可以监控到应用启动前的流量。
  2. 在驱动启动时,通过调用FwpmEngineOpen0获取引擎句柄,然后调用FwpmFlowGetContextByKey0 enumrated所有的已存在flow,针对需要监控的flow调用FwpsFlowAssociateContext0进行关联。这样可以 "补捕" 应用启动前已有的flow,实现流量监控的连续性。

所以,我的建议是:

  1. review flow context删除逻辑,确保不会重复删除或遗漏删除flow context。这可以避免蓝屏问题。
  2. 使用FWPM_LAYER_INBOUND_TRANSPORT_V4或FWPM_LAYER_OUTBOUND_TRANSPORT_V4层进行PID关联,这可以监控到应用启动前的流量。
  3. 在驱动启动时调用FwpmEngineOpen0和FwpmFlowGetContextByKey0 enumrated已存在flow,并通过FwpsFlowAssociateContext0进行关联,补捕应用启动前的流量,实现监控的连续性。
  4. 如果上述方法仍无法解决问题,需要深入分析驱动的流量监控和PID关联逻辑,定位确切的问题根源。