在看了微软关于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:捕获入站连接和数据报文,可以监控应用启动前的流量
对于出现蓝屏的问题,可能有多种原因,常见的包括:
鉴于您修改了微软的例程并出现了蓝屏,我认为您需要回滚修改,确保代码可以稳定运行,然后再一步步修改,以找出出现蓝屏的原因。
可以尝试分段调试程序,逐步找出代码的问题所在。同时,查看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努力中.......共同编写:
根据您的描述,出现蓝屏问题的原因可能是:
您的疑问2也比较合理。使用FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4层进行关联,无法监控到应用启动前的流量,是因为这个层仅捕获已经建立的连接,而无法捕获连接建立过程中的报文。
要解决这个问题,可以:
所以,我的建议是: