我最近在处理一个问题,服务器在几天内耗尽了NonPagedPool。通常,我们只需要使用像PoolMon这样的工具来识别有问题的pool标记,然后使用本文中的方法找到使用该pool标记的驱动程序。然而,让这个案例有趣的是pool标记,而且我们无法使用常规方法识别驱动程序。你一会儿就会明白我的意思了。支持给我提供了服务器处于状态时的内核转储,这就是我发现的。
让我们先看看虚拟内存的使用情况:
2: kd> !vm *** Virtual Memory Usage *** Physical Memory: 851420 ( 3405680 Kb) Page File: \??\C:\pagefile.sys Current: 3584000 Kb Free Space: 3568552 Kb Minimum: 3584000 Kb Maximum: 3584000 Kb Available Pages: 573277 ( 2293108 Kb) ResAvail Pages: 800628 ( 3202512 Kb) Locked IO Pages: 1067 ( 4268 Kb) Free System PTEs: 25102 ( 100408 Kb) Free NP PTEs: 335 ( 1340 Kb) Free Special NP: 0 ( 0 Kb) Modified Pages: 22 ( 88 Kb) Modified PF Pages: 22 ( 88 Kb) NonPagedPool Usage: 31369 ( 125476 Kb) ß Very high NonPagedPool Max: 31986 ( 127944 Kb) ********** Excessive NonPaged Pool Usage ***** PagedPool 0 Usage: 19071 ( 76284 Kb) PagedPool 1 Usage: 735 ( 2940 Kb) PagedPool 2 Usage: 747 ( 2988 Kb) PagedPool 3 Usage: 720 ( 2880 Kb) PagedPool 4 Usage: 746 ( 2984 Kb) PagedPool Usage: 22019 ( 88076 Kb) PagedPool Maximum: 38912 ( 155648 Kb) ********** 3 pool allocations have failed **********
所以我们可以看到NPP的使用率非常高,因为服务器使用的是/3GB开关,默认情况下NPP限制在128MB。我们需要确定哪些池标记与高NPP使用率相关:
2: kd> !poolused /t2 2 Sorting by NonPaged Pool Consumed Pool Used: NonPaged Paged Tag Allocs Used Allocs Used None 246479 50827424 0 0 call to ExAllocatePool MmCm 1198 18462512 0 0 Calls made to MmAllocateContiguousMemory , Binary: nt!mm
很有趣,所以这个有问题的标签是“None”。这意味着这些分配是通过调用函数ExAllocatePool而不是ExAllocatePoolWithTag来完成的。ExAllocatePool已过时,不应再使用。
现在,我需要找出哪个驱动程序在调用这个函数。首先,我需要知道ExAllocatePool住在哪里:
2: kd> x nt!ExAllocatePool e0894d1f nt!ExAllocatePool Next, I need to search all the drivers to see which one is importing this function: 2: kd> !for_each_module s-d @#Base @#End e0894d1f f50b8058 e0894d1f e0828e04 e089b708 e084011b .M..............
看起来可疑地像导入表,让我们看看:
2: kd> dps f50b8058 f50b8058 e0894d1f nt!ExAllocatePool f50b805c e0828e04 nt!_wcsnicmp f50b8060 e089b708 nt!ExFreePoolWithTag f50b8064 e083e30a nt!KeInitializeEvent ...
是的,那是导入表。您还可以通过检查标题(用!dh在模块基址并查找“Import Address Table Directory”)。
如您所见,我们只有一个驱动程序导入ExAllocatePool。让我们看看这是哪个驱动程序:
2: kd> !lmi f50b8058 Loaded Module Info: [f50b8058] Module: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} Base Address: f50b3000 Image Name: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}.sys
为了保护罪犯,我已经从上面显示的模块信息中删除了有罪的标识符。有趣的是,驱动程序名是一个GUID,而这个驱动程序不存在于磁盘上。这是因为驱动程序是在其父程序加载时动态创建的。
将软件包被删除,服务器又恢复了正常。