前几天有朋友找到我,说他的机器有常数**,但是在任务管理器中找不到哪个进程吃了内存,特别奇怪,截图如下:
在我的分析历程中,都是用户模式的内存泄漏,如上图中的异常迹象已经明确告诉大家,不是用户模式程序吃内存,而是内核模式程序吃内存,例如:
一些驱动操作系统在概率上一般都是由一些第三方程序的内存泄漏引起的,在本文中,我们将讨论如何解决这个问题。
相信很多朋友都知道,用户态程序直接或间接调用virtualalloc方法向操作系统索要内存,包括c的GC堆,其方法签名如下:
lpvoid virtualalloc( [in, optional] lpvoid lpaddress, [in] size_t dwsize, [in] dword flallocationtype, [in] dword flprotect);
那么内核中的驱动程序是如何向操作系统请求内存的呢?一般调用 exallocatepool2 方法获取内存,签名如下:
declspec_restrict pvoid exallocatepool2( pool_flags flags, size_t numberofbytes, ulong tag);
上面有两个参数,我想详细解释一下:
flags 参数一般有两种类型:pool flag non paged 和 pool flag paged,前者表示分配的内存需要永久保留在内存中,不能交换到硬盘上。 后者分配的内存可交换到硬盘。
tag 参数的初衷是为了方便日后洞察内存泄漏,它强行将一块内存绑定到标签(一个 4 字节的 ASCII 字符串)上,然后你就会知道是谁通过这个标签分配了内存。
为了能够泄漏驱动程序,您可以使用 Microsoft 提供的 notmyfault 工具,该工具利用了 MyFaultsys 驱动程序不断为操作系统分配内存。 **为:
打开 MyFault 工具,输入 40ms 的 leakage,并分配到非页面交换池,配置内核状态 dump、* 和截图如下
exallocatepool2(pool_flag_non_paged,40*1024*1024,"leak");
在违规过程中,通过 Process Explorer 可以明显看出 67G RAM,其中有 4 个9G 以非分页形式分发,即由上图中的池标志非分页标签分发,下图截图:
接下来,切换到 MyFault 上的“崩溃”选项卡,并强制操作系统进入蓝屏以生成转储文件。
一旦你得到转储,先通过!VM 在操作系统级别观察虚拟内存的分布。
3: kd> !vm...physical memory: 2069421 ( 8277684 kb)**ailable pages: 445015 ( 1780060 kb)res**ail pages: 707292 ( 2829168 kb)locked io pages: 0 ( 0 kb)free system ptes: 4295052431 (17180209724 kb)..modified pages: 11479 ( 45916 kb)modified pf pages: 11479 ( 45916 kb)modified no write pages: 0 ( 0 kb)nonpagedpool usage: 1219892 ( 4879568 kb)nonpagedpoolnx usage: 24512 ( 98048 kb)nonpagedpool max: 4294967296 (17179869184 kb)pagedpool usage: 32907 ( 131628 kb)pagedpool maximum: 4294967296 (17179869184 kb)..nonpagedpool commit: 1246469 ( 4985876 kb)..sum system commit: 1409562 ( 5638248 kb)total private: 279673 ( 1118692 kb)**sum of individual system commit + process commit exceeds overall commit by 1952 kb ? committed pages: 1688747 ( 6754988 kb)commit limit: 4166573 ( 16666292 kb)
从卦中的非页面池使用指标可以看出,当前非页面池占用 48G RAM,总内存页数 121W。
下一步是深入挖掘非页面交换池,看看分配了什么标签,可以使用!poolused 2 命令。
3: kd> !poolused 2...sorting by nonpaged pool consumed nonpaged paged tag allocs used allocs used leak 119 4991221760 0 0 unknown pooltag 'leak', please update pooltag.txt cont 238 14499840 0 0 unknown pooltag 'cont', please update pooltag.txt ketr 16410 8117664 0 0 unknown pooltag 'ketr', please update pooltag.txt etwb 196 7565568 2 131072 etw buffer , binary: nt!etw 2872 6 5660864 0 0 unknown pooltag '2872', please update pooltag.txt 287r 1026 4183040 0 0 unknown pooltag '287r', please update pooltag.txt file 9734 3877408 0 0 file objects thre 1257 3217920 0 0 thread objects , binary: nt!ps etwr 12141 2672640 0 0 etw km regentry , binary: nt!etw...
从卦象数据来看,有一个神秘的tag=leak内存分配,分配了119次,总大小为499g。哈哈,这实际上是我刚刚通过我的故障完成的 40ms 内存分配。
下一个问题是:哪个驱动程序对这次泄漏负责?最简单的方法是在每个驱动程序的内存空间中进行内存搜索,看看谁有泄漏的 ASC 硬代码,对,有了这个想法,使用 LM 查看其中的 sys。
3: kd> lmstart end module nameffffc25c`891b0000 ffffc25c`89480000 win32kbase (deferred) ffffc25c`8a190000 ffffc25c`8a545000 win32kfull (deferred) .fffff807`22600000 fffff807`23646000 nt (pdb symbols) fffff807`23c00000 fffff807`23d16000 clipsp (deferred) fffff807`47f30000 fffff807`47f4b000 monitor (deferred) fffff807`47f50000 fffff807`47f59000 myfault (deferred) .unloaded modules:fffff807`3c6e0000 fffff807`3c6ec000 360sensor64.sysfffff807`31550000 fffff807`31560000 dump_storport.sysfffff807`315a0000 fffff807`315d3000 dump_storahci.sysfffff807`31000000 fffff807`3101e000 dump_dumpfve.sysfffff807`26b80000 fffff807`26bac000 luafv.sysfffff807`26b20000 fffff807`26b30000 dump_storport.sysfffff807`26b70000 fffff807`26ba3000 dump_storahci.sysfffff807`26bd0000 fffff807`26bee000 dump_dumpfve.sysfffff807`28130000 fffff807`2814c000 dam.sys fffff807`24200000 fffff807`2420a000 360elam64.sysfffff807`25230000 fffff807`25241000 hwpolicy.sys
接下来就是写一个脚本,在每个 sys 的 start end 间隔内做一个 s search,我不会放过这个脚本,它很简单,它最终出现在 myfault 中在 sys 中成功找到硬编码的泄漏,如下所示:
3: kd> lmvm myfaultbrowse full module liststart end module namefffff807`47f50000 fffff807`47f59000 myfault (deferred) image path: \c:\windows\system32\drivers\myfault.sys image name: myfault.sys browse all global symbols functions data timestamp: fri sep 30 00:17:31 2022 (6335c51b) checksum: 00010ced imagesize: 00009000 translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4 information from resource tables: 3: kd> ?fffff807`47f59000 - fffff807`47f50000evaluate expression: 36864 = 00000000`000090003: kd> s -a fffff807`47f50000 l?0x9000 "leak"fffff807`47f51559 4c 65 61 6b 0f 42 c1 41-8d 49 fd 8b d0 ff 15 0c leak.b.a.i...fffff807`47f515c7 4c 65 61 6b 0f 42 c1 33-c9 8b d0 ff 15 a0 1a 00 leak.b.3...
在以往的dump分析中是用户态程序的泄漏,内核模式堆的泄漏是第一次分析,不是朋友提供的这个机会,真的是没有缘分!在dump分析的过程中,我们也让大家看到了windbg有多强大!