记一次 .NET某收银软件 非托管泄露分析
一:背景
1. 讲故事
在我的分析之旅中,遇到过很多程序的故障和杀毒软件扯上了关系,有杀毒软件导致的程序卡死,有杀毒软件导致的程序崩溃,这一篇又出现了一个杀毒软件导致的程序非托管内存泄露,真的是分析多了什么鬼都能撞上。
前几天有位朋友找到过,我他们的程序内存在慢慢的泄露,最后程序会出现崩溃,不知道是什么导致的,让我帮忙看一下怎么回事,简单分析后发现是非托管泄露,让朋友开启了ust并在内存超出预期时抓了一个dump下来,接下来就是分析了。
二:WinDbg 分析
1. 到底是哪里的泄露
相信一直追这个系统的朋友应该知道怎么判断,很简单, 看下 MEM_COMMIT 和 HEAP 指标即可,使用 !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 : DISABLEDHeap 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 LFHExternal 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 LFHExternal 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: 00001000ust - Create user mode stack trace database
开启之后 win32api 的 HeapAlloc 方法的内部中会到注册表中看一下是否有 ust 值,如果有就会记录分配的调用栈,这样就知道是谁创建的,抓取dump后可以用windbg的 !gflag 命令看下是否开启成功,参考输出如下:
0:000> !gflag
Current NtGlobalFlag contents: 0x00001000ust - Create user mode stack trace database
接下来对 Heap=15710000 进行一个 block 分组,看下是否有一些有价值的信息。
0:000> !heap -stat -h 15710000heap @ 15710000
group-by: TOTSIZE max-display: 20size #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 @ 15710000HEAP_ENTRY Size Prev Flags UserPtr UserSize - state1571f948 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 2d7HEAP_ENTRY Size Prev Flags UserPtr UserSize - state15665550 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 3ec4c1b8address 3ec4c1b8 found in_HEAP @ 15710000HEAP_ENTRY Size Prev Flags UserPtr UserSize - state3ec4c1b8 005d 0000 [00] 3ec4c1d0 002cb - (busy)771dd969 ntdll!RtlAllocateHeap+0x00000274153e7439 prthook!MyShowWindow+0x0001d1f9153e543c prthook!MyShowWindow+0x0001b1fc153476ab prthook+0x000276ab0:000> !heap -p -a 39e3ce20address 39e3ce20 found in_HEAP @ 15710000HEAP_ENTRY Size Prev Flags UserPtr UserSize - state39e3ce20 0061 0000 [00] 39e3ce38 002d7 - (busy)771dd969 ntdll!RtlAllocateHeap+0x00000274153e7439 prthook!MyShowWindow+0x0001d1f9153e543c prthook!MyShowWindow+0x0001b1fc153476ab 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.dllLoaded symbol image file: prthook.dllImage path: C:\Windows\SysWOW64\prthook.dllImage name: prthook.dllBrowse all global symbols functions dataTimestamp: Thu Jun 22 17:16:53 2017 (594B8B05)CheckSum: 001F4972ImageSize: 002BC000File version: 16.17.6.22Product version: 16.17.6.22File flags: 0 (Mask 3F)File OS: 40004 NT Win32File type: 2.0 DllFile date: 00000000.00000000Translations: 0804.04b0Information from resource tables:CompanyName: Beijing VRV Software Co.,LtdProductName: edpInternalName: prthookOriginalFilename: prthook.dll_DBProductVersion: 16, 17, 6, 22FileVersion: 16, 17, 6, 22FileDescription: prthook_DBLegalCopyright: Copyright (C) 2016 Beijing VRV Software Co.,LtdComments: 中英文版
从卦中数据看,prthook.dll 所属公司为 Beijing VRV Software Co.,Ltd,无语的是把这个第三方的dll放在Windows的系统目录 C:\Windows\SysWOW64 下,容易让人觉得有点 鸠占鹊巢,接下来查一下百度,发现是 北信源 的,截图如下:

有了这些信息,告诉朋友让客户把这个安全软件卸载掉就可以了。
三:总结
程序的故障如果不是我们的代码造成的,你想通过排查代码找出问题是不可能的事情,追过这个系列的朋友应该深有体会,常见的外在因素有:
- 杀毒软件
- 电磁辐射
- 显卡问题
相关文章:
记一次 .NET某收银软件 非托管泄露分析
一:背景 1. 讲故事 在我的分析之旅中,遇到过很多程序的故障和杀毒软件扯上了关系,有杀毒软件导致的程序卡死,有杀毒软件导致的程序崩溃,这一篇又出现了一个杀毒软件导致的程序非托管内存泄露,真的是分析多…...
C++力扣题目131--分割回文串
131. 分割回文串 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。 回文串 是正着读和反着读都一样的字符串。 示例 1: 输入:s "aab" 输出:[["a&qu…...
vue脚手架
● vue是单⻚⾯应⽤程序 ● 什么是路由 ○ 后端路由 ■ 对于普通的⽹站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源 ○ 前端路由 ■ 对于单⻚⾯应⽤程序来说,主要通过URL中的hash ( # 号) 来实现不同⻚⾯之间的切换…...
Monorepo-uniapp 构建分享
Monorepo uniapp 构建灵感:刚好要做一个项目,于是想到升级一下之前自己写的一个vue3tspiniauno的模版框架,其实那个框架也不错;只是感觉还差点东西,我已经用那个小框架写了两三个项目;轻巧实用。为什么选…...
django后台登录:Forbidden (403) CSRF verification failed. Request aborted.
如果您在尝试登录Django后台时遇到了CSRF验证失败的错误,这通常意味着您的浏览器未能提交正确的CSRF令牌,或者Django后端未能验证该令牌。遵循以下步骤来解决这个问题: 清除浏览器Cookies和缓存: 有时候,浏览器的Cooki…...
【Python数据可视化】matplotlib之绘制常用图形:折线图、柱状图(条形图)、饼图和直方图
文章传送门 Python 数据可视化matplotlib之绘制常用图形:折线图、柱状图(条形图)、饼图和直方图matplotlib之设置坐标:添加坐标轴名字、设置坐标范围、设置主次刻度、坐标轴文字旋转并标出坐标值matplotlib之增加图形内容&#x…...
Python从入门到精通秘籍五
Python速成,每日持续更新,知识点超详细,涵盖所有Python重难点知识及其对应代码,利用碎片化时间,实现Python从入门到精通的飞跃!!! 一、Python的函数基本定义语法 当定义一个函数时,我们使用关键字def,后跟函数名称和一对圆括号。在圆括号内,可以指定任意数量的参数…...
MySQL 基于 GTID 主从复制
GTID 定义 GTID 是 MySQL 事务标识,为每一个提交的事务都生成一个标识,并且是全局唯一的,这个特性是从 MySQL5.6 引进的。 组成 GTID 是由 UUID TID,UUID 是MySQL的唯一标识,每个MySQL实例之间都是不同的。TID是代表…...
Linux操作系统基础
目录 计算机存储结构 冯.诺依曼结构 操作系统 在前几期我们学写了linux中常见的一些指令,本期我们将正式进行linux操作系统的学习。 计算机存储结构 要学习linux操作系统,我们就得先进行计算机存储结构的学习,要进行计算机存储结构的学…...
docker 批量更改镜像标签
docker 批量更改镜像标签 批量更改镜像标签批量删除镜像 批量更改镜像标签 docker images | grep "registry.aliyuncs.com\/google_containers" | sed s/registry.aliyuncs.com\/google_containers/registry.k8s.io/ | awk {print "docker tag "$3" …...
js 校验 大于等于0小于等于100
如果你想要在JavaScript中校验一个数值是否在0到100之间(包括0和100),你可以使用以下的函数: function validateRange(value) {return value > 0 && value < 100; }你可以使用这个函数来检查一个值是否在指定的范围…...
前端面试题-webpack
1.webpack是什么? 模块打包工具,用于将前端资源,如JavaScript、css、图片等打包成可以在浏览器运行的静态资源。可以将多个模块打包成一个或多个bundle。 主要功能: 模块化:可以将多个模块打包成一个或多个bundle&…...
What is `WebMvcConfigurer` does?
WebMvcConfigurer 用于自定义和扩展SpringMVC的功能配置。 比如:可以配置如视图解析器、静态资源处理、消息转换器、拦截器等MVC相关的组件。 实现 WebMvcConfigurer 接口,并使用 Configuration 注解标记,使其成为一个配置类 Configuration …...
安全强化学习笔记
这里写自定义目录标题 参考资料 Safe Reinforcement Learning环境算法CPO 2017 ICMLPCPO 2019 ICLRFOCOPS 2020 NIPSCRPO 2021 ICMLCUP 2022 NIPS TRPO 如何看懂TRPO里所有的数学推导细节? - 小小何先生的回答 - 知乎 参考资料 Safe Reinforcement Learning 安全/约束强化学…...
POI-tl 知识整理:整理1 -> 利用模板向word中写入数据
1 文本传值 Testpublic void testText() throws Exception {XWPFTemplate template XWPFTemplate.compile("D:\\Idea-projects\\POI_word\\templates.docx");Map<String, Object> map new HashMap<>();map.put("title", "Hi, girl"…...
PDF结构详解
文章目录 介绍前言高保真的文件什么是PDF?PDF的一些优点版本摘要谁在使用PDF?有用的免费软件谁应该阅读 构建一个简单PDF文件基本PDF语法File StructureDocument ContentPage Content 构建简单PDF文件头目录,交叉引用表和文件尾主要对象图形内…...
Three.js 镜面反射Reflector 为MeshStandardMaterial增加Reflector能力
效果效果官方案例 区别:官方的案例更像一个镜子 没有纹理等属性 也没有透明度修改 根据源码进行修改为 MeshStandardMaterial实现反射 使用案例 createReflector() {const plane this.helper.create.plane(2, 2);this.helper.add(plane.mesh);plane.mesh.rotat…...
UE4使用技巧
打开蓝图编辑器时不是打开一个新窗口,而是作为主窗口 适用于全部的打开新窗口的操作 蓝图编译时自动保存 开始游戏后立即捕获鼠标...
行为型设计模式—职责链模式
职责链模式:从名字可以拆分为 职责 和 链。即能为请求创建一条由多个处理器组成的链路,每个处理器各自负责自己的职责,相互之间没有耦合,完成自己任务后请求对象即传递到链路的下一个处理器进行处理。 如果在写好的执行函数里加上…...
EndNote快速上手
前言:用EndNote主要就是为了方便管理文章引用的文献,所以本篇就是针对EndNote在文章中引用文献需要的技巧,然后本文用的是EndNoteX9。 EndNote快速上手 创建文献资料库创建文献分组导入文献手动输入文件导入在线搜索 修改文献信息去重文献删除…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...
给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...
9-Oracle 23 ai Vector Search 特性 知识准备
很多小伙伴是不是参加了 免费认证课程(限时至2025/5/15) Oracle AI Vector Search 1Z0-184-25考试,都顺利拿到certified了没。 各行各业的AI 大模型的到来,传统的数据库中的SQL还能不能打,结构化和非结构的话数据如何和…...
嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...
