使用PE信息查看工具和Dependency Walker工具排查因为库版本不对导致程序启动报错问题

本文主要是介绍使用PE信息查看工具和Dependency Walker工具排查因为库版本不对导致程序启动报错问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1、问题说明

2、问题分析思路

3、问题分析过程

3.1、使用Dependency Walker打开软件主程序,查看库与库的依赖关系,查看出问题的库

3.2、使用PE工具查看dll库的时间戳

3.3、解决办法

4、最后


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       安装了新版本的安装包之后,启动程序时会报错,导致程序启动失败。这是日常工作中比较常见的一类问题,本文详细讲述如何使用PE信息查看工具和Dependency Walker工具去分析这类问题的完整过程,给大家提供一个借鉴或参考。

1、问题说明

       测试同事安装新版本的安装包之后,一启动程序就会报错,弹出如下的报错提示框:

导致程序启动失败。提示无法在xxsysctrldll.dll库中找不到InitMtDsc接口,这是一类比较常见的问题,一般都是因为主程序中有dll库的版本不一致引起的。比如A.dll依赖了B.dll库,出现接口找不到的问题,可能的原因有:

1)B.dll中的function接口不存在或者已经被删除了。比如老版本的A.dll和新版本的B.dll混在一起使用,老版本A.dll调用了function接口,但该接口在新版本的B.dll中已经删除或者已经更改名称了,所以会出现找不到接口的问题。比如新版本的A.dll和老版本的B.dll混在一起使用,新版本的A.dll调用了新版本的B.dll中新增的接口,但当前软件打包的还是老版本的B.dll,所以程序运行时在老版本B.dll中找不到接口。
2)B.dll中的function接口参数修改了。C++中支持函数重载(函数名称一样,但参数不一样),在编译时默认情况下会对函数名称进行改编,在生成的函数符号中融入了参数信息,比如上面截图中的 ?lnitMtDsc@@YAXGH@Z。

在B.dll中的function接口还在,但是参数修改了,函数符号发生了变化,所以找不到了。 


       在这里,给大家重点推荐一下我的几个热门畅销专栏:

专栏1:(该专栏订阅量接近350个,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!)

C++软件调试与异常排查从入门到精通系列文章汇总icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据近几年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法,详细讲述了C++软件的调试方法与手段,以图文并茂的方式给出具体的实战问题分析实例,带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

专栏中的文章均是通过项目实战总结出来的(通过项目实战积累了大量的异常排查素材和案例),有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2: 

C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域的多个方面的内容,同时给出C/C++及网络方面的常见笔试面试题,并详细讲述Visual Studio常用调试手段与技巧!

专栏3: 

开源组件及数据库技术icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html

以多年的开发实战为基础,分享一些开源组件及数据库技术! 


2、问题分析思路

       对于上述这类问题,基本就是库的版本不一致导致的,具体是哪个库的版本有问题,我们使用PE信息查看工具和Dependency Walker工具就能快速排查出来。

       先使用Dependency Walker打开exe主程序,查看库与库的依赖关系,比如:

确定问题出在哪些个库中,同时可以进一步的确定是找不到库,还是调用的接口在目标dll库中找不到,亦或是要调用的接口在目标dll库中修改了参数。

       然后使用PE信息查看工具打开出问题的dll库文件,查看库文件的时间戳,比如:

即库文件(二进制文件)的编译生成时间,这样我们就能确定到底是哪个库的版本不对了。

       另外,在这个分析过程中,我们可能需要在svn或git上查看库文件的发布记录,和相关模块开发维护团队确认库与库之间的版本对应关系。

3、问题分析过程

3.1、使用Dependency Walker打开软件主程序,查看库与库的依赖关系,查看出问题的库

       首先我们使用Dependency Walker打开软件的exe主程序,查看库与库之间的依赖关系,看看问题具体出在哪些库中。

       Dependency Walker打开exe主程序后,会以树状结构将exe主程序依赖的库以及这些库依赖的其他库展示出来。默认情况下,会自动将树中的节点全部展开。

注意一下,当前最新的Dependency Walker还是2016年的,当运行在Win10等新的系统中时,打开文件可能会比较慢,甚至要等好几分钟才能打开完成。要稍微耐心等待一下。

       在展开的树中,节点太多,除了软件的业务库,还包含大量的Windows系统库,为了方便查看,我们可以将系统库的节点给折叠起来。这就要求我们要识别出来哪些库是系统库,比如常见的user32.dll、ntdll.dll、kernel32.dll,还有以API-MS-WIN开头的系统库:

这对于经常搞Windows软件开发的人很简单,但对于新手或者不熟悉Windows软件开发的人来说,可能很难分辨

      在Dependency Walker中,如果库找不到或者库中的接口有问题,问题节点前面会显示特别的异常图标:

1)在运行的机器中找不到某个库,会在该库的节点前显示一个黄色的问号图标,如下所示:

这可能是打包软件时,没有将程序依赖的库打包进安装包中。比如忘记将一个新增的dll库打包到安装包中、没有将运行时库打包到安装包中。注意,不同版本的Visual Studio使用的运行时库名称是不一样的,比如Visual Studio 2010的运行时库是msvcr100.dll和msvcp100.dll,Visual Studio 2017的运行时库是msvcp140.dll、vcruntime140.dll和ucrtbase.dll(不再有msvcr140.dll、新增了vcruntime140.dll和ucrtbase.dll)。
使用Visual Studio编译出来的程序,在打安装包时都需要把对应版本的运行时库打包进去。关于不同Visual Studio版本对应的运行时库的详细说明,可以参见我的文章:

使用Dependency Walker和Process Explorer排查程序启动时缺少ucrtbase.dll等运行时库以及报0xC000007B错误icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131505299此外,很多系统库节点前面也会显示一个黄色的问号图标,这些系统库一般可以忽略掉,不用管。
2)在某个库中找不到调用的接口,会在对应的接口行前面显示一个红色的图标如下所示:

可能这个接口在库中已经不存在了(被删除了),也可能是接口的参数修改了,生成的函数符号变了。

        在本案例中,最开始启动程序报错的截图如下:

从这个截图可以看出,问题与xxsysctrldll.dll库有关。用Dependency Walker打开exe主程序后,显示出问题的两个库的截图如下所示:

首先看到xxsysctrldll.dll依赖了xxdscdll.dll,之所以依赖,肯定是xxsysctrldll.dll库中调用了xxdscdll.dll库中的接口。然后我们看到xxdscdll.dll节点前面有淡红色的异常图标,所以我们点击xxdscdll.dll节点,此时右边实现两块信息,上面PI部分是依赖该库的xxsysctrldll.dll从该库中引入了哪些接口,即xxsysctrldll.dll库中调用了xxdscdll.dll库中的那些接口;下面的E部分,是当前xxdscdll.dll库有哪些导出接口。

关于导出导入,对于dll动态库本身,接口是导出的,是要提供给其他库调用的;对于使用到该库的其他库,需要引入当前库的接口,然后调用这些接口的。一般可以使用#import导入dll库对应的.lib库,比如#pragma comment( lib, "winmm.lib" ) ,这个是在编译链接时会用到,如果找不到调用的接口符号,则会编译报错。接口的运行调用则时发生在程序运行阶段的。

       看到导入列表中的接口?InitMtDsc@@YAXGH@Z(这是经过编译器名称改编后的函数名称,带了参数信息)所在行前面显示了红色的图标,应该是该接口符号,在当前的xxdscdll.dll中没有。可以翻看下方的xxdscdll.dll的导出函数列表,看看xxdscdll.dll有没有导出InitMtDsc接口。在xxdscdll.dll导出接口的列表中确实找到了InitMtDsc接口,但包含了参数信息的改编后的名称是不一样的,即?InitMtDsc@@YAXG@Z,所以应该是该接口的参数修改了。

       目前可以确定是xxdscdll.dll与xxsysctrldll.dll两个库不匹配,但具体是哪个库有问题,还是看这两个库的时间戳(库的编译生成时间)

3.2、使用PE工具查看dll库的时间戳

       此时我还要使用到PeViewer PE信息查看工具。打开PeViewer工具,点击打开按钮,找到xxdscdll.dll与xxsysctrldll.dll文件的路径,打开文件查看到文件的时间戳:(点击左侧列表中的头部 -> NT头 -> 文件头右侧就会显示文件的时间戳)

从上图中可以看到,xxdscdll.dll库的时间戳为2023/12/07[04:29:53],xxsysctrldll.dll库的时间戳为2023/12/15[15:29:37]。 

我这边经常使用的PE信息查看工具叫PeViewer,以前排查问题时,用该工具打开64位二进制文件发生了闪退。后来在网上搜到了MiTeC EXE Explorer工具,这个工具兼容性比较好,打开64位二进制文件没有问题。大家后面遇到问题时,可以使用更强大的MiTeC EXE Explorer。

       最近底层的组件有多个模块有改动,12月15日有发布新库过来,查看了svn上的发布记录:

发布说明中提及到的发布模块中有提到xxdscdll模块和xxsysctrldll模块,但实际上并没有发布库文件xxdscdll.dll,xxsysctrldll.dll库文件发布过来了。所以结合上面的PE工具查看的时间戳,xxsysctrldll.dll是最新版本,但xxdscdll.dll是老版本

       那明明发布说明中指出要发布xxdscdll模块过来,为啥没发布成功呢?先到文件服务器上查看编译日志,看看是不是xxdscdll模块代码编译失败了。经查看,xxdscdll模块编译没有错误的,文件有生成的。于是找了一下配置管理员,他查看了一下发布模块配置,发现了问题:

在配置发布模块xxdsc的名称时,错误地将xxdscdll.dll写成了xxdssdll.dll(将dsc写成dss),导致了自动执行发布脚本时没有拷贝xxdscdll.dll到指定产品的代码流上。

3.3、解决办法

       所以在该问题场景中,新版本的xxsysctrldll.dll使用了老版本的xxdscdll.dll,新版本的xxsysctrldll.dll调用了新版本的xxdscdll.dll中的InitMtDsc接口,在新版本的xxdscdll.dll中修改了InitMtDsc接口的参数,即新版本的xxdscdll.dll调用了修改参数后的InitMtDsc接口,所以在老版本的xxdscdll.dll中找不到修改参数后的InitMtDsc接口,所以程序启动时弹出了文章最开始说到的错误提示框:

解决办法很简单,只需要将漏发的xxdscdll.dll文件发布过来就好了。

4、最后

       本案例中详细介绍了如何使用PE信息查看工具与Dependency Walker去排查程序启动报错的问题,希望能给大家提供一定的借鉴或参考。

这篇关于使用PE信息查看工具和Dependency Walker工具排查因为库版本不对导致程序启动报错问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/529285

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

springboot3打包成war包,用tomcat8启动

1、在pom中,将打包类型改为war <packaging>war</packaging> 2、pom中排除SpringBoot内置的Tomcat容器并添加Tomcat依赖,用于编译和测试,         *依赖时一定设置 scope 为 provided (相当于 tomcat 依赖只在本地运行和测试的时候有效,         打包的时候会排除这个依赖)<scope>provided