一:背景

1. 讲故事

在我的分析之旅中,遇到过很多程序的故障和杀毒软件扯上了关系,有杀毒软件导致的程序卡死,有杀毒软件导致的程序崩溃,这一篇又出现了一个杀毒软件导致的程序非托管内存泄露,真的是分析多了什么鬼都能撞上。

前几天有位朋友找到过,我他们的程序内存在慢慢的泄露,最后程序会出现崩溃,不知道是什么导致的,让我帮忙看一下怎么回事,简单分析后发现是非托管泄露,让朋友开启了ust并在内存超出预期时抓了一个dump下来,接下来就是分析了。

二:WinDbg 分析

1. 到底是哪里的泄露

相信一直追这个系统的朋友应该知道怎么判断,很简单, 看下 MEM_COMMITHEAP 指标即可,使用 !address -summary 命令输出如下:


0:000> !address -summary --- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Heap 678 93bd0000 ( 2.308 GB) 65.39% 57.71%
<unknown> 2610 3005d000 ( 768.363 MB) 21.26% 18.76%
Free 515 1e133000 ( 481.199 MB) 11.75%
Image 1526 118f8000 ( 280.969 MB) 7.77% 6.86%
Other 19 804e000 ( 128.305 MB) 3.55% 3.13%
Stack 390 4900000 ( 73.000 MB) 2.02% 1.78%
TEB 73 49000 ( 292.000 kB) 0.01% 0.01%
PEB 1 1000 ( 4.000 kB) 0.00% 0.00% --- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_COMMIT 4477 c51f9000 ( 3.080 GB) 87.25% 77.00%
MEM_FREE 515 1e133000 ( 481.199 MB) 11.75%
MEM_RESERVE 820 1ccc4000 ( 460.766 MB) 12.75% 11.25% --- Largest Region by Usage ----------- Base Address -------- Region Size ----------
Heap 38be0000 fd0000 ( 15.812 MB)
<unknown> cc6000 7fd9000 ( 127.848 MB)
Free f7590000 88bf000 ( 136.746 MB)
Image 5ab2c000 e41000 ( 14.254 MB)
Other 8cee000 7fb0000 ( 127.688 MB)
Stack 14610000 fd000 (1012.000 kB)
TEB ffe51000 1000 ( 4.000 kB)
PEB fffde000 1000 ( 4.000 kB)

从卦中看,3G的提交内存,Heap 吃了 2.3G,也就表明是 NTHEAP 的泄露,这是一块非托管内存区域,一般都是 C/C++ 语言用 malloc 或者 new 分配的内存,接下来深挖下 NTHEAP 即可,使用 !heap -s 命令。


0:000> !heap -s
SEGMENT HEAP ERROR: failed to initialize the extention
NtGlobalFlag enables following debugging aids for new heaps:
stack back traces
LFH Key : 0x7c31b93c
Termination on corruption : DISABLED
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-----------------------------------------------------------------------------
00200000 08000002 178304 138172 178304 42165 1747 56 0 34 LFH
External fragmentation 30 % (1747 free blocks)
006c0000 08001002 1088 224 1088 18 8 2 0 0 LFH
00590000 08041002 256 4 256 2 1 1 0 0
006a0000 08001002 3136 1184 3136 153 82 3 0 0 LFH
External fragmentation 12 % (82 free blocks)
00570000 08001002 1088 224 1088 18 8 2 0 0 LFH
...
15710000 08001002 2185152 2179432 2185152 442 1323 139 0 0 LFH
...

从卦中信息看, 15710000 吃了2.18G,也就表明它是吃内存的主力,这里简单说一下,00200000 是默认的进程堆,除了这个之外都是用非托管代码调用 Win32API 的 HeapCreate 方法创建出来的,接下来就得看下是什么代码创建的。

2. 到底是谁创建的

要想知道是谁创建的,一定要在注册表中开启 ust 选项,大家可以了解下 gflags.exe 工具,参考如下:


PS C:\Users\Administrator\Desktop> gflags /i Example_17_1_7.exe +ust
Current Registry Settings for Example_17_1_7.exe executable are: 00001000
ust - Create user mode stack trace database

开启之后 win32api 的 HeapAlloc 方法的内部中会到注册表中看一下是否有 ust 值,如果有就会记录分配的调用栈,这样就知道是谁创建的,抓取dump后可以用windbg的 !gflag 命令看下是否开启成功,参考输出如下:


0:000> !gflag
Current NtGlobalFlag contents: 0x00001000
ust - Create user mode stack trace database

接下来对 Heap=15710000 进行一个 block 分组,看下是否有一些有价值的信息。


0:000> !heap -stat -h 15710000
heap @ 15710000
group-by: TOTSIZE max-display: 20
size #blocks total ( %) (percent of total busy bytes)
2cb dea4 - 26dd40c (9.58)
2d7 c778 - 23675c8 (8.72)
d0 26d64 - 1f8e140 (7.78)
7c5 2c50 - 1584990 (5.30)
cb 14449 - 10125e3 (3.96)
83c 16c2 - bb6578 (2.89)
cf9 bc4 - 98a1a4 (2.35)
1f51 3da - 789dfa (1.86)
...

从卦中数据看没有哪个size占用的特别高,接下来就依次从高往低看,发现都是和 prthook 有关,参考输出如下:


0:000> !heap -flt s 2cb
_HEAP @ 15710000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
1571f948 005d 0000 [00] 1571f960 002cb - (busy)
15649d70 005d 005d [00] 15649d88 002cb - (busy)
...
3ec4b900 005d 005d [00] 3ec4b918 002cb - (busy)
3ec4bbe8 005d 005d [00] 3ec4bc00 002cb - (busy)
3ec4bed0 005d 005d [00] 3ec4bee8 002cb - (busy)
3ec4c1b8 005d 005d [00] 3ec4c1d0 002cb - (busy)
... 0:000> !heap -flt s 2d7
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
15665550 005e 0000 [00] 15665568 002d7 - (busy)
1566b930 005e 005e [00] 1566b948 002d7 - (busy)
1566df98 005e 005e [00] 1566dfb0 002d7 - (busy)
1566e288 005e 005e [00] 1566e2a0 002d7 - (busy)
...
39e3acc8 0061 0061 [00] 39e3ace0 002d7 - (busy)
39e3c508 0061 0061 [00] 39e3c520 002d7 - (busy)
39e3c810 0061 0061 [00] 39e3c828 002d7 - (busy)
39e3cb18 0061 0061 [00] 39e3cb30 002d7 - (busy)
39e3ce20 0061 0061 [00] 39e3ce38 002d7 - (busy) 0:000> !heap -p -a 3ec4c1b8
address 3ec4c1b8 found in
_HEAP @ 15710000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
3ec4c1b8 005d 0000 [00] 3ec4c1d0 002cb - (busy)
771dd969 ntdll!RtlAllocateHeap+0x00000274
153e7439 prthook!MyShowWindow+0x0001d1f9
153e543c prthook!MyShowWindow+0x0001b1fc
153476ab prthook+0x000276ab 0:000> !heap -p -a 39e3ce20
address 39e3ce20 found in
_HEAP @ 15710000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
39e3ce20 0061 0000 [00] 39e3ce38 002d7 - (busy)
771dd969 ntdll!RtlAllocateHeap+0x00000274
153e7439 prthook!MyShowWindow+0x0001d1f9
153e543c prthook!MyShowWindow+0x0001b1fc
153476ab prthook+0x000276ab

3. prthook 到底为何方神圣

从前一节的卦中数据看,貌似 prthook 在不断的弹框,在弹框中用 ntdll!RtlAllocateHeap 分配了非托管内存,那 prthook 到底是个啥呢?可以用 lmvm 看下。


0:000> lmvm prthook
Browse full module list
start end module name
15320000 155dc000 prthook (export symbols) prthook.dll
Loaded symbol image file: prthook.dll
Image path: C:\Windows\SysWOW64\prthook.dll
Image name: prthook.dll
Browse all global symbols functions data
Timestamp: Thu Jun 22 17:16:53 2017 (594B8B05)
CheckSum: 001F4972
ImageSize: 002BC000
File version: 16.17.6.22
Product version: 16.17.6.22
File flags: 0 (Mask 3F)
File OS: 40004 NT Win32
File type: 2.0 Dll
File date: 00000000.00000000
Translations: 0804.04b0
Information from resource tables:
CompanyName: Beijing VRV Software Co.,Ltd
ProductName: edp
InternalName: prthook
OriginalFilename: prthook.dll_DB
ProductVersion: 16, 17, 6, 22
FileVersion: 16, 17, 6, 22
FileDescription: prthook_DB
LegalCopyright: Copyright (C) 2016 Beijing VRV Software Co.,Ltd
Comments: 中英文版

从卦中数据看,prthook.dll 所属公司为 Beijing VRV Software Co.,Ltd,无语的是把这个第三方的dll放在Windows的系统目录 C:\Windows\SysWOW64 下,容易让人觉得有点 鸠占鹊巢,接下来查一下百度,发现是 北信源 的,截图如下:

有了这些信息,告诉朋友让客户把这个安全软件卸载掉就可以了。

三:总结

程序的故障如果不是我们的代码造成的,你想通过排查代码找出问题是不可能的事情,追过这个系列的朋友应该深有体会,常见的外在因素有:

  • 杀毒软件
  • 电磁辐射
  • 显卡问题

记一次 .NET某收银软件 非托管泄露分析的更多相关文章

  1. 记一次 .NET 某工控视觉软件 非托管泄漏分析

    一:背景 1.讲故事 最近分享了好几篇关于 非托管内存泄漏 的文章,有时候就是这么神奇,来求助的都是这类型的dump,一饮一啄,莫非前定.让我被迫加深对 NT堆, 页堆 的理解,这一篇就给大家再带来一 ...

  2. 思迅/泰格/科脉/收银软件/商超软件数据库修复解决断电造成损坏的mdb\dat文件SQL数据库 置疑 修复 恢复

    拥有专业管理软件数据库修复技术工程师,专业提供管家婆.美萍.思迅.科脉等管理软件技术服务,电脑维修\重装系统技 术服务.无法登陆打不开等出错问题处理(连接失败,请输入正确的服务器名,SQL Serve ...

  3. [Python设计模式] 第2章 商场收银软件——策略模式

    github地址: https://github.com/cheesezh/python_design_patterns 题目 设计一个控制台程序, 模拟商场收银软件,根据客户购买商品的单价和数量,计 ...

  4. 记一次 .NET 某智慧水厂API 非托管内存泄漏分析

    一:背景 1. 讲故事 七月底的时候有位朋友在wx上找到我,说他的程序内存占用8G,托管才占用1.5G,询问剩下的内存哪里去了?截图如下: 从求助内容看,这位朋友真的太客气了,动不动就谈钱,真伤感情, ...

  5. 记一次 .NET 某电子厂OA系统 非托管内存泄露分析

    一:背景 1.讲故事 这周有个朋友找到我,说他的程序出现了内存缓慢增长,没有回头的趋势,让我帮忙看下到底怎么回事,据朋友说这个问题已经困扰他快一周了,还是没能找到最终的问题,看样子这个问题比较刁钻,不 ...

  6. 读《大话设计模式》——应用工厂模式的"商场收银系统"(WinForm)

    要做的是一个商场收银软件,营业员根据客户购买商品单价和数量,向客户收费.两个文本框,输入单价和数量,再用个列表框来记录商品的合计,最终用一个按钮来算出总额就可以了,还需要一个重置按钮来重新开始. 核心 ...

  7. 互联网+下PDA移动智能手持POS超市收银开单软件

    是一套专为中小超市.专卖店设计的收银管理软件,广泛应用于中小超市(百货商店).化妆品店.婴幼儿用品店.玩具店.保健品店.茶叶店. 电器.文具图书.手机通讯器材店等行业的中小型店面店铺.该系统具有完善的 ...

  8. Atitit.收银系统模块架构attilax 总结

    Atitit.收银系统模块架构attilax 总结 1. 常规收银系统模块结构1 1.1. 商品管理1 1.2. 会员系统1 1.3. 报表系统1 1.4. 会员卡系统1 1.5. 库存管理1 2.  ...

  9. 基于C#的超市收银管理系统

    基于C#的超市收银管理系统 前序 一直在忙学习Qt有关的知识,非常有幸这学期学习了C#.让我也感觉到了一丝欣慰,欣慰的是感觉好上手啊,学了几天顿时懂了.好多控件的使用方法好类似,尽管平时上课没有怎么认 ...

  10. PDA 收银系统PDA手持打印扫描枪 销售开单 收银 扫描打印一体机

    在零售方面也有很好的应用.如在一些高端品牌零售店,营业员可以随身导购,一站式完成了商品销售和收银,很是受消费者追捧,符合了企业对客户体验以及行业领先的追求. PDA收银系统是一款多功能可以取代专业收银 ...

随机推荐

  1. RPM软件包:Red HatPackage Manager,RPM

    RPM软件包是按照GPL条款发行在各个linux版本上使用. 用途 可以安装.删除.升级.刷新和管理RPM软件包 通过RPM软件包管理能知道软件包包含哪些文件,也能知道系统中的某个文件属于哪个RPM软 ...

  2. SonarQube系列-通过配置扫描分析范围,聚焦关键问题

    在许多情况下,你可能不希望分析项目中每个源文件的各个方面.例如,项目可能包含生成的代码.库中的源代码或有意复制的代码.在这种情况下,跳过这些文件分析的部分或全部方面是有意义的,从而消除干扰并将焦点缩小 ...

  3. Skywalking APM监控系列(二、Mysql、Linux服务器与前端JS接入Skywalking监听)

    前言 上篇我们介绍了Skywalking的基本概念与如何接入.Net Core项目,感兴趣可以去看看: Skywalking APM监控系列(一丶.NET5.0+接入Skywalking监听) 本篇我 ...

  4. umich cv-3-1

    UMICH CV Neural Network 对于传统的线性分类器,分类效果并不好,所以这节引入了一个两层的神经网络,来帮助我们进行图像分类 可以看出它的结构十分简单,x作为输入层,经过max(0, ...

  5. 《最新出炉》系列初窥篇-Python+Playwright自动化测试-21-处理鼠标拖拽-番外篇

    1.简介 前边宏哥拖拽有提到那个反爬虫机制,加了各种参数,以及加载js脚本文件还是有问题,偶尔宏哥好像发现了解决问题的办法,看到了黎明的曙光,宏哥就说试一下看看行不行,万一实现了.结果宏哥试了结果真的 ...

  6. 欧拉序求LCA

    使用欧拉序 st 表 O(1) 求 LCA 欧拉序 st 表求 LCA 一开始是从某篇题解里看到的,后来百度了一下就会了( 这是一种预处理 O(nlogn) ,查询 O(1) 的优秀算法. 什么是欧拉 ...

  7. 解决IDEA中.properties文件中文变问号(???)的问题(已解决)

    问题背景 构建SpringBoot项目时,项目结构中有一个application.properties文件.这个项目是Spring Boot一个特有的配置文件.内容如下(我写了一些日志的配置): 写到 ...

  8. 微服务系列-使用WebFlux的WebClient进行Spring Boot 微服务通信示例

    公众号「架构成长指南」,专注于生产实践.云原生.分布式系统.大数据技术分享. 概述 在之前的教程中,我们看到了使用 RestTemplate 的 Spring Boot 微服务通信示例. 从 5.0 ...

  9. Python学习 —— 内置数据类型

    写在前面 接上文<Python学习 -- 初步认知>,有需要请自取:Python学习 -- 初步认知 在这篇文章中,我们一起深入了解Python中常用的内置数据类型.Python是一种功能 ...

  10. 在Vue中使用Mock.js虚拟接口数据实例详解

    在Vue项目中使用Mock.js可以方便地模拟接口数据,用于前端开发和测试.Mock.js是一个生成随机数据的库,可以帮助我们快速构建虚拟接口数据.在本文中,我将通过一个实例来详细讲解在Vue中使用M ...