第三方模块远程注入到软件中引发软件异常的若干实战案例分享

目录

1、概述

2、老版本的输入法导致软件CPU频繁跳高(导致软件出现卡顿)的问题

3、QQ拼音输入法注入到安装包进程中,导致安装包主线程卡死问题

3.1、多线程死锁分析

3.2、进一步研究

4、安全软件注入到软件中,注入模块发生了崩溃,直接导致软件发生崩溃

5、安全软件注入到软件中,注入模块发生了内存泄露,直接导致软件内存耗尽后发生闪退

6、最后


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html开源组件及数据库技术(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_2276111.html       有些软件为了实现某些功能需要远程注入到其他软件进程中的,比如输入法和安全软件等,注入到其他进程后,注入模块就运行在被注入的进程空间中了,一旦注入模块发生内存泄漏、崩溃等问题,会直接影响到被注入的进程,引发被注入进程发生异常。本文结合项目中遇到的若干问题,给大家详细介绍一下因为远程注入引发软件异常的几个典型项目实例,以供大家借鉴或参考。

1、概述

       在日常工作中接触比较多的需要注入到其他软件进程的软件主要有输入法和安全软件:

1)输入法:输入法在注入到其他软件进程之后,其他软件进程才能使用输入法输入文字。

2)安全软件:安全软件为了实时监控其他软件的操作与行为,为了实时监控其他软件网络数据的收发,也需要远程注入到其他软件进程中。

用于远程注入的模块,注入到目标进程中后,就驻留在目标进程中了,即运行在目标进程的进程空间中了。一旦注入模块发生异常,会直接影响到被注入的进程,会直接引发被注入的进程发生异常。

      根据之前项目中遇到的多个问题,注入模块对被注入进程的影响,主要有以下几类:

1)输入法注入到软件进程后,可能会导致软件发生明显的卡顿,特别是在输入文字时,这个问题在客户使用低版本的搜狗输入法时遇到过。
2)输入法注入到软件进程后,可能会引发软件发生死锁,这个问题在运行软件安装包程序时遇到过。
3)注入模块在运行过程中遇到异常,发生崩溃,直接导致被注入的软件发生崩溃。因为注入模块就运行在被注入的软件进程中的。
4)注入模块发生内存泄漏,内存泄漏发生在被注入的软件进程中,导致被注入软件发生Out of memory内存耗尽发生闪退。

      下面讲几个在项目中遇到的问题实例,来看看注入模块是怎样影响到我们软件的。

2、老版本的输入法导致软件CPU频繁跳高(导致软件出现卡顿)的问题

       有客户反馈,在其使用我们软件的过程中会时不时出现卡顿问题。让客户打开Windows任务管理器,让其帮忙观察一下软件使用过程中该软件进程的CPU占用情况。

       经观察发现,软件在使用过程中CPU占用比例会时不时地跳高,跳高之后又自动回落。特别是在聊天框中输入时,CPU会跳高。CPU占用变高,一般可能是因为软件中在持续地执行代码导致的,比如程序中发生死循环,一直在不停歇地执行代码。但本例中,CPU会很快自动回落,好像不是死循环导致的,如果是死循环,CPU占用会一直比较高。难道代码中会出现短时间内的死循环?

       于是使用Process Explorer工具查看CPU占用高的线程,然后查看该线程的函数调用堆栈,多次刷新多次查看函数调用堆栈,发现线程中一直有搜狗输入法(IME - Input Method Editor,输入法)相关函数的调用(函数所在模块名中有Ime和Sougou字样,所以判断是搜狗输入法相关模块),所以怀疑这个问题可能和搜索输入法有关。

       软件界面卡顿,应该是软件UI界面卡顿,所以应该是UI主线程有问题。Process Explorer中看到的CPU占用高的线程,应该就是UI主线程。可以用Windbg确认一下,将Windbg附加到软件进程上,使用~命令将进程中的所有线程信息都打印出来,如下所示:

在Windbg中,UI主线层是0号线程,将该0号线程的线程id(进程id为16进制数)与Process Explorer中显示的线程id(进程id为十进制数)比较一下就知道了。至于怎么比较,也可以参看我之前写的文章:

使用Process Explorer/Process Hacker和Windbg高效排查软件高CPU占用问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/134180480       后来让客户查看了一下其安装的搜狗输入法的版本,是一个较老的版本,让他安装最新版本的搜狗输入法,安装后好像就没问题了。所以该问题应该是和输入法有关的

3、QQ拼音输入法注入到安装包进程中,导致安装包主线程卡死问题

       在某客户的电脑上,会时不时出现启动我们的软件安装包后没反应,启动起来后应该显示安装包界面的,但一直看不到安装包界面,到任务管理器中可以看到软件安装包进程,说明程序已经启动了。

       估计是安装包UI界面所在的UI主线程发生卡死了,查看安装包进程的CPU占用很低,所以能排除程序发生死循环的可能。很可能是UI线程与其他线程发生死锁了。

3.1、多线程死锁分析

       导致线程发生卡死,一般有两种原因:

1)代码中发生死循环,导致函数一直没返回,线程卡死;
2)代码一直卡在WaitForSingleObject等待锁的状态,导致函数一直没返回,线程卡死。这是多个线程之间使用锁,发生死锁引发的。

        于是将Windbg启动起来,附加到出问题的安装包进程上,然后使用~0s命令切换到UI主线程(UI主线程是0号线程),然后输入kn命令查看函数调用堆栈,如下所示:

从堆栈中可以看出,当前线程卡在等待锁的WaitForSingleObject函数上,一直没返回。可以多次go,多次查看0号线程的函数调用堆栈,每次都卡在WaitForSingleObject函数上。

       此外,沿着函数调用堆栈向上看,是调用EnterCriticalSection接口去获取临界区对象,触发了WaitForSingleObject函数的调用。说明当前发生死锁的是临界区锁。

       当前确定是UI主线程发生死锁了,那与之关联的死锁线程是哪个呢?安装包程序比较简单,进程中没几个线程,使用~*kn命令将所有线程的函数调用堆栈都打印出来,看到1号线程也卡在获取临界区锁的函数调用上:

那基本可以确定是0号线程和1号线程发生死锁了:

至于是不是这两个线程形成了死锁,需要分析锁的信息,具体分析方法,我在此就不赘述了,可以查看我之前写的文章:

使用Process Explorer/Process Hacker和Windbg高效排查软件高CPU占用问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/134180480       此处也可以用《Windows核心编程》第9章源码中提供了一个叫LockCop的死锁检测工具,当时使用该工具监测结果如下:

该死锁检测工具是调用Windows API函数去检测的,只能检测到部分对象的死锁,无法监测到所有类型的死锁,关于这个工具的详细说明,可以查看《Windows核心编程》第9章(使用等待链遍历API来检测死锁)的内容

       关于多线程及多线程死锁相关内容,可以参考我的文章:

从C++软件调试实战的角度去看多线程编程中的若干细节问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/134358655       从发生死锁的1号线程的调用堆栈来看,看到了QQPinYin的模块名,那说明这个线程是与QQ拼音输入法相关的。这就是说,这个死锁是与QQ拼音相关的,当时建议尝试两个办法,一个是升级QQ拼音输入法的版本,另一个是将QQ拼音输入法换成搜狗输入法。客户采用了后面这个方法,将输入法换成搜狗输入法后就不再出现了。

3.2、进一步研究

        对于0号线程,是调用了API函数SHGetSpecialFolderLocation触发的死锁;对于1号线程,是调用API函数SHGetSpecialFolderPathW触发的死锁。这说明死锁发生在底层的Windows系统库中,不在上层库中。这种情况很少遇到,一般死锁都发生在上层的业务代码中。

       这两个函数在两个线程中调用会发生死锁?于是尝试到微软MSDN上查看这两个函数的说明。看到这两个函数都已经被微软废弃了,如下所示:

建议不要使用这两个函数了,应该使用对应的替代函数。

       为了保证代码的健壮性,我们应该遵从微软官方的说明,不再使用已经废弃的API函数。如果继续使用,可能会产生一些无法预料、未知的结果。

4、安全软件注入到软件中,注入模块发生了崩溃,直接导致软件发生崩溃

      几年前遇到的一个客户问题,他们的Windows系统中安装了VPN软件,注入到我们的进程中,hook了网络通信的相关接口,以监控软件的网络数据包的收发,其中hook的recvfrom接口实现有bug,我们代码中有处调用recvfrom接口的地方传入了两个NULL参数(对于系统API函数recvfrom,传入NULL值是允许的),结果直接导致该注入模块产生了崩溃,进而导致了我们软件的崩溃。

       到MSDN上查看套接字API函数recvfrom的说明,函数的最后两个参数是可选的,可以不传入,直接设置NULL就可以了,如下所示:

       但客户VPN软件注入模块,将系统的recvfrom函数hook成了他们实现的recvfrom函数,在实现他们自己的recvfrom函数时,直接访问了recvfrom最后的两个参数,而我们的代码直接传入了NULL值:


这样在他们的recvfrom内部访问了NULL指针,触发了内存访问违例,导致VPN软件的注入模块发生崩溃,从而导致了我们整个程序的崩溃。

事实上,这个问题的排查难度远比此处文字描述的复杂,崩溃时的函数调用堆栈不完整(看不到套接字函数recvfrom的调用):

崩溃的注入库MinLSP.dll是第三方安全厂商的,我们拿不到该库的pdb文件,可能厂商也没有保存!

当时是使用IDA反汇编工具查看汇编代码,以及使用Windbg的dds命令,找出recvfrom函数调用的!限于篇幅,这个地方就没有完全展开了!

       像这类出在第三方安全软件中的问题,必须要拿出足够的证据,证明问题是出在安全软件上,客户才会认可排查的结论,客户才会找第三方安全软件开发商反馈问题。对于本例中的问题,我们有个临时的规避办法,我们只要传入两个有效的参数即可,当然在对应的代码中,我们并不关心这两个参数在函数调用完成之后的返回值,不再传入两个NULL参数。

5、安全软件注入到软件中,注入模块发生了内存泄露,直接导致软件内存耗尽后发生闪退

       有个客户在某台机器上运行的我们的软件,每次大概运行半个多小时后软件就会出现闪退崩溃,问题基本是必现的。软件运行一段时间后发生闪退崩溃,可能是内存泄漏引起的。有内存泄露的代码在频繁地执行,泄露的内存越来越多,接近或达到用户态虚拟内存的上限(32位程序默认的用户态虚拟内存位2GB),就会导致Out of memory内存耗尽的异常,程序就会发生闪退崩溃。

       于是让客户重新运行软件,按照之前的操作步骤操作,然后在Windows任务管理器中持续地观察软件进程占用的内存情况,看看内存是否在持续地升高。之前我们讲过,Windows任务管理器中看不到进程占用的用户态虚拟内存,需要使用Process Explorer去查看。不过任务管理器中看内存的变化趋势是可以的,也能看到内存在持续增长的。我们推荐使用Process Explorer工具去查看虚拟内存占用。

       经观察,软件中确实存在内存泄露,大概半个小时后内存就耗完了。然后就是使用工具去分析内存泄露的模块及位置了。当时选择Windbg去检测内存泄露,将Windbg附加到目标进程上去监测。至于如何使用Windbg去检测内存泄露,此处就不再赘述了,可以查看我的文章:
使用Windbg定位Windows C++程序中的内存泄漏icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/121295720       经分析,内存泄露发生在某个dll模块中,然后查看该dll模块的路径,发现是客户安装的某个安全软件的路径,即该dll模块是某安全软件中的。安全软件中的模块,怎么会跑到我们的软件进程空间中来的呢?答案只有一个,这个dll库是远程注入到我们的软件进程中的,安全软件正是通过这个注入模块对我们的软件进行监控的。

这个问题应该和客户机器的系统环境有关,如果是软件本身模块有内存泄漏,应该在公司内部测试环境中就发现了,因为半个小时左右就能复现,在公司环境中不用专门长时间拷机就能复现。

       我们给客户的结论是,安全软件的注入模块有内存泄露,需要客户联系安全软件的开发厂商去核实排查一下。但客户有些不认可我们的结论,他们给出的理由是,运行其他软件都没问题,为啥运行我们的软件就有内存泄露呢?后来将发生泄漏模块所属的安全软件卸载掉后,我们的软件运行就没有泄露了,所以基本确定泄露和这个安全软件有关,客户才愿意承认可能是安全软件引起的。然后联系了安全软件厂商,协调了他们的相关开发人员,然后创建了讨论组。

       经排查得知,安全软件在拦截UDP数据包进行分析时有内存泄露,而我们的软件在加入会议后,源源不断的音音视频码流都是使用UDP传输的,所以导致内存一直在持续的泄露,然后内存很快就耗尽,程序发生闪退了。

至于软件是如何实现远程注入的,可以查看《Windows核心编程》一书中的第22章(DLL注入与API拦截)的内容。

6、最后

        本文详细讲述了几个项目中遇到的远程注入对软件产生影响的问题实例,有很强的实战参考价值,希望能给大家提供一定的借鉴或参考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/174981.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Xilinx Zynq-7000系列FPGA任意尺寸图像缩放,提供两套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐FPGA图像处理方案FPGA图像缩放方案 3、设计思路详解HLS 图像缩放介绍 4、工程代码1:图像缩放 HDMI 输出PL 端 FPGA 逻辑设计PS 端 SDK 软件设计 5、工程代码2:图像缩放 LCD 输出PL 端 FPGA 逻辑设计PS 端 SDK 软件设…

uni-app - 日期 · 时间选择器

目录 1.基本介绍 2.案例介绍 ①注意事项: ②效果展示 3.代码展示 ①view部分 ②js部分 ③css样式 1.基本介绍 从底部弹起的滚动选择器。支持五种选择器,通过mode来区分,分别是普通选择器,多列选择器,时间选择器&a…

visionOS空间计算实战开发教程Day 4 初识ImmersiveSpace

细心的读者会发现在在​​Day1​​​和​​Day2​​​的示例中我们使用的都是​​WindowGroup​​。 main struct visionOSDemoApp: App {var body: some Scene {WindowGroup {ContentView()}} } 本节我们来认识在visionOS开发中会经常用到的另一个概念​​ImmersiveSpace​​…

如何看待Unity新收费模式?

Unity新收费模式的变化主要在于将收费重心从功能分级收费转变为资源使用量收费,这个改变已经引起了一定的争议和反响。以下是我个人的看法: 优点: 更公平的收费方式:新的收费模式将更加公平,用户只需按照实际使用的数…

css取消移动端长按元素背景色

在开发微信小程序的时候,发现有的元素长按之后,出现了讨厌人的背景色,这就很奇怪,就想把它去掉,所以这里教一下方法: 在所在元素添加css样式: // 取消长按的背景色-webkit-tap-highlight-color:…

【Linux】Linux中的基本概念

Linux中的基本概念 1. 路径分隔符/2. 当前目录 .3. 返回上级目录 . .目录结构:多叉树 4. 路径5. 路径 { 绝对路径 相对路径 }6. * 通配符 指定路径下的所有文件7. 同级目录下,不允许存在同名文件,或者同名目录8. 命令的本质就是可执行文件9…

TypeError: expected np.ndarray (got Tensor)解决办法

文章目录 一、错误展示二、错误分析三、解决办法四、其余解决办法总结 一、错误展示 二、错误分析 这个错误表示正在尝试将一个PyTorch的Tensor对象作为numpy的ndarray对象来使用。我们需要使用numpy的ndarray而不是PyTorch的Tensor。 三、解决办法 在我的程序中去掉这一行代…

维格表项目进度同步到钉钉群

企业越来越依赖项目管理工具,以确保项目按时完成、成本控制得当、并实现预期的业务目标。但随着项目变得更加复杂,项目经理和团队需要更高效的方法来跟踪和传达项目进度,以确保团队内部保持一致的理解。 传统的项目管理方法,可能缺…

增速大幅下滑?基础L2博弈成本

在高阶智驾(从ALC到NOA)的光环之下,传统入门级基础L2级辅助驾驶赛道也在发生一些微妙的变化。 高工智能汽车研究院监测数据显示,2023年1-9月,基础L2在中国市场(不含进出口)乘用车前装标配交付45…

为了摆脱 Android ,亚马逊开发基于Linux的操作系统

导读亚马逊一直在开发一种新的操作系统 —— 内部代号为 “Vega”,以便在 Fire TV、智能显示器和其他联网设备上取代 Android 系统。 亚马逊一直在开发一种新的操作系统 —— 内部代号为 “Vega”,以便在 Fire TV、智能显示器和其他联网设备上取代 Andr…

Spring Framework IoC依赖注入-按Bean类型注入

Spring Framework 作为一个领先的企业级开发框架,以其强大的依赖注入(Dependency Injection,DI)机制而闻名。DI使得开发者可以更加灵活地管理对象之间的关系,而不必过多关注对象的创建和组装。在Spring Framework中&am…

bitmap基础介绍+holo实现离线UV计算

bitmap 基础介绍bitmaping 数据结构bitmap计算算子集成二阶段分布式计算:RoaringBitmap构造方案分桶方案建序方案 holo官网 离线UV计算创建用户映射表创建聚合结果表更新用户映射表和聚合结果表更新聚合结果表UV、PV查询 基础介绍 RoaringBitmap主要为了解决UV指标…

力扣 2. 两数相加

Problem: 2. 两数相加 思路与算法 Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { this.val val; this…

实验(四):指令部件实验

一、实验内容与目的 实验要求: 利用CP226实验仪上的小键盘将程序输入主存储器EM,通过指令的执行实现微程序控制器的程序控制。 实验目的: 1.掌握模型机的操作码测试过程; 2.掌握模型机微程序控制器的基本结构以及程序控制的基本原…

设计模式-命令模式-笔记

“行为变化”模式 在组件的构建过程中,组件行为的变化经常导致组件本身剧烈的变化。“行为变化”模式组件的行为和组件本身进行解耦,从而支持组件行为的变化,实现两者之间的松耦合。 经典模式:Command、Visitor 动机&#xff0…

跑出竞价的“内卷怪圈”,三季度京东物流依旧“稳操胜券”?

今年国内的物流企业内卷之势丝毫没有减弱,尽管表面上价格战已经告一段落,但各方之间依旧暗流涌动。顺丰、菜鸟接连赴港IPO,极兔成功“上岸”,新一轮的局势似乎正在形成。 近日,京东物流发布了2023年第三季度财报。从财…

Java并发编程第12讲——cancelAcquire()流程详解及acquire方法总结

上篇文章介绍了AQS的设计思想以及独占式获取和释放同步状态的源码分析,但是还不够,一是感觉有点零零散散,二是里面还有很多细节没介绍到——比如cancelAcquire()方法(重点),迫于篇幅原因,今天就…

909-2014-T3

文章目录 1.原题2.算法思想3.关键代码4.完整代码5.运行结果 1.原题 有n个顶点的无向图,使用邻接矩阵作为存储结构。为减少存储空间,使用数组按照行主映射方式仅保存下三角矩阵。请给出映射公式,并编写算法计算给定顶点的度。叙述算法思想并用…

C# - Opencv应用(2) 之矩阵Mat使用[矩阵创建、图像显示、像素读取与赋值]

C# - Opencv应用(2) 之矩阵Mat使用[矩阵创建、图像显示、像素读取与赋值] 矩阵创建图像显示与保存像素读取与赋值新建sample02项目,配置opencv4相关包,新建.cs进行测试 1.矩阵创建 //创建空白矩阵 var dst new Mat()//创建并赋…

动手学深度学习(二)---线性回归

文章目录 1.线性回归从0实现2.线性回归简洁实现【相关方法】torch.normal() 1.线性回归从0实现 从0开始实现整个方法,包括数据流水线、模型、损失函数和小批量随机梯度下降优化器 (1)导入需要的包 % matplotlib inline import random impor…