当前位置: 首页 > news >正文

使用反汇编工具IDA查看发生异常的汇编代码的上下文去辅助分析C++软件异常

目录

1、概述

2、如何使用IDA打开并查看二进制文件的汇编代码

3、在IDA中找到发生崩溃的那条汇编指令的位置

3.1、如何在IDA中找到发生异常的那条汇编指令

3.2、示例

4、阅读汇编代码上下文需要掌握一定的基础汇编知识

5、最后


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章正在更新中...)https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_11931267.html       在分析C++软件异常崩溃时,可能需要使用IDA工具去查看exe或dll二进制文件的汇编代码去辅助定位问题。今天我们就来讨论一下使用IDA工具去查看汇编代码相关细节问题。

1、概述

       我们使用Windbg打开dump文件分析异常时,会先去查看发生崩溃的汇编指令及相关寄存器中的值,然后查看异常所在线程的函数调用堆栈,必要时查看函数调用堆栈中的函数中的局部变量或者C++类对象中的数据成员变量的值去辅助分析。

       但在少部分场景下,通过上述分析并不能最终定位问题,需要使用IDA去查看汇编代码的上下文,结合C++源代码去做进一步分析的。比如下面的两个场景就需要去查看汇编代码上下文去辅助分析:

1)Windbg中显示的函数调用堆栈中的C++代码行号,和最新的代码对不上了

       发生异常崩溃的软件版本可能是几个月或者几年之前的,Windbg中显示的行号是很早之前的cpp文件代码了,最新的cpp文件代码相对这个出问题的版本做了很多修改,所以行号和最新的代码完全对不上了。这时候就需要使用IDA去查看发生异常的模块的汇编代码上下文了,看看到底是那一行代码引起的,一般还是要和最新的代码对比着看,看看最新的代码中哪一行代码。

2)Windbg中指示的发生崩溃的C++代码行上有多个函数调用,很难直接判断是哪个函数调用出问题了

        Windbg中指示的发生崩溃的C++代码行上有多个函数调用(比如if语句中有多个条件的组合判断),很难直接判断是哪个函数调用出问题了,可以查看汇编代码去确定到底是哪个函数调用出的问题,比如如下的if条件判断语句:

if (pContainer->IsVisible() && GetTargetImplPtr()->IsReady() && pDataProcImpl->IsBuildFinish)
{// 代码省略
}

       关于使用IDA查看汇编代码去辅助排查C++软件异常的详细理论说明,可以参见之前写的一篇文章:
使用IDA查看汇编代码上下文去辅助排查C++软件异常问题https://blog.csdn.net/chenlycly/article/details/128942626https://blog.csdn.net/chenlycly/article/details/128942626

2、如何使用IDA打开并查看二进制文件的汇编代码

       IDA安装完成后,双击启动程序,会弹出如下的提示框:

点击“New”即新建一个对象。紧接着弹出让选择要打开的文件:

可以找到目标文件的路径,打开目标文件即可。也可以点击取消,然后直接将文件拖到IDA中。打开文件时会让选择加载文件的方式:

对于Windows版本的二进制号文件,使用的都是PE文件格式,选择默认的PE方式即可。

       接下来会弹出是否要加载pdb文件的提示框:

选择Yes。此处需要注意一下,我们需要事先将pdb文件放置到目标二进制文件的同一级目录中,这样IDA在打开二进制文件时就会搜索到对应的pdb文件并加载pdb文件。有了pdb文件中符号,IDA打开的汇编代码中就会显示具体函数名和变量标识,以及大量注释信息。

       打开二进制文件后,默认显示的Graph view视图模式(显示各个代码模块的关系),如下:

需要点击右键,在弹出的右键菜单中点击Text view视图模式,切换到汇编源码模式。

       我们可以跳转到指定的函数中,点击菜单栏的Jump-->Jump o function:

弹出包含当前模块所有函数的列表,点击窗口下方的Search按钮:

直接输入要查看的目标函数的名称,搜索到目标函数后双击条目,即会跳转到目标函数的汇编代码处:

也可以按下快捷键g,直接跳转到指定地址的汇编代码行:

3、在IDA中找到发生崩溃的那条汇编指令的位置

       在Windbg中可以看到发生异常的那条汇编指令,以及这条汇编指令所在的模块,然后找到模块对应的二进制文件,用IDA打开二进制文件,就可以查看模块的汇编代码了。

3.1、如何在IDA中找到发生异常的那条汇编指令

       Windbg中可以看到发生异常汇编指令的地址(代码段地址),通过该指令的地址,可以到IDA打开的汇编代码中找到对应的位置,然后查看该位置的汇编指令的上下文,对照着C++源码,就可以进一步地去分析问题了。

       Windbg中显示的发生异常的汇编指令的地址,是主程序运行起来之后的实际地址,和IDA中显示的静态默认地址是不同的。主程序启动时,会先将其依赖的各个dll模块加载到进程空间中,给各个模块分配代码段地址,这样每个模块中的汇编指令就有了运行时的实际代码段地址了。
这个地方需要区分一下代码段地址和数据段地址:

代码中定义的变量的内存是在数据段内存上分配的,变量的内存地址都是数据段的地址。二进制代码(汇编代码)指令的地址,是代码段地址。

       发生异常的汇编指令在实际运行的地址,虽然和IDA中显示的静态默认地址是不同的,但该条汇编指令相对于所在模块的位置是固定的,即汇编指令相对于所在模块的地址偏移始终是固定的。可以在Windbg中计算出发生异常的那条汇编指令相对所在模块偏移,然后将这个偏移加上IDA中显示的模块默认起始地址,就得出该条汇编指令在IDA中的地址了,然后Go到这个地址,就可以看到发生崩溃的那条汇编指令了。

3.2、示例

       下面我们通过一个具体的实例来讲解如何在IDA打开的模块汇编代码中找到发生异常的那条汇编指令。我故意写了一段会引发异常的测试代码如下:

SHELLEXECUTEINFO* pInfo = NULL;CString strTip;
strTip.Format(_T("cbSize: %d"), pInfo->cbSize );::MessageBox( NULL, strTip, _T("提示"), MB_OK);

代码中定义了一个结构体指针变量pInfo,初始化为空(NULL),然后没有给该指针赋一个有效的结构体地址,直接用这个空指针去访问结构体中的成员cbSize,所以访问了一个地址很小的内存,所以触发了内存访问违例。

       程序运行上述代码时会产生崩溃,生成dump文件。用Windbg打开dump文件,并在Windbg中配置程序的pdb文件路径,打开后即看到发生异常崩溃的那条汇编指令及当时各个寄存器中的值,并看到发生的异常Code码及异常类型,如下所示:

首先,从上图可以看出,发生的是Access violation内存访问违例的异常。然后看到发生异常的那条汇编指令mov ecx,dword ptr [eax](指令的地址为0x00eb3787),并且这条指令位于TestDlg模块的函数CTestDlgDlg::OnBnClickedButton1中。

       接下来我们就来演示一下如何在IDA中找到发生异常的这条汇编指令的位置。发生异常的汇编指令位于TestDlg模块中,于是用IDA打开TestDlg.exe二进制文件,看到该模块的汇编代码。我们先计算出发生异常的汇编指令相对其所在模块的偏移。发生异常的汇编指令的地址为0x00eb3787,用lm命令查看其所在模块TestDlg的起始地址(代码段地址),如下:

TestDlg模块的起始地址为0x00ea0000,所以发生异常的那条汇编指令相对所在模块TestDlg起始地址的偏移为:

0x00eb3787 - 0x00ea0000

然后我们到IDA中,将鼠标拉到汇编代码的最上面,看IDA显示的TestDlg模块静态默认起始地址,如下:

TestDlg模块静态默认起始地址为0x400000,该模块中所有汇编指令的地址都是在此基础值上展开的。所以,发生异常的那条汇编指令在IDA中显示的地址为:

0x00eb3787 - 0x00ea0000 + 0x00400000 = 0x00413787

然后按下g快捷键,在弹出的搜索框中输入413787,点击确定,就Go到发生异常的那条汇编指令的位置了,如下:

这样我们就能查看这条发生异常的汇编指令的上下文,结合IDA中的注释及C++源码,就能对问题进行进一步分析了。

4、阅读汇编代码上下文需要掌握一定的基础汇编知识

       要去阅读汇编代码的上下文,是需要掌握一定的汇编基础知识的,比如了解一些常用寄存器的用途、熟悉一些常用的汇编指令、了解函数调用时的栈分布、了解C++虚函数调用的汇编代码实现(虚函数调用时的二次寻址)等。这里简单的提一下常用寄存器的用途:

在X86汇编指令中,EAX主要用于存放函数调用的返回值;在调用C++成员函数时会使用ECX寄存器用来传递C++对象地址;ESI是源地址寄存器,EDI是目的地址寄存器,主要用于内存拷贝的串操作指令中,比如memcpy的汇编实现中。

       关于分析C++软件异常需要掌握的基础汇编知识,这里就不再赘述了,可以参见我之前写的文章:

分析C++软件异常需要掌握的汇编知识汇总https://blog.csdn.net/chenlycly/article/details/124758670https://blog.csdn.net/chenlycly/article/details/124758670

5、最后

       直接去阅读汇编代码难度是比较大的,除非有很强的汇编语言功底与反汇编的能力。在实际工作中,我们一般是将汇编代码,与C++代码对照着阅读,同时结合着汇编代码上下文中的注释去辅助查看,这比单纯地去直接阅读汇编代码要容易很多。此外,编译器在Release下会对代码进行大量的优化,被优化的C++代码很难和优化后生成的汇编代码完全一一对应起来,这点需要注意一下。

       我们在分析C++软件异常问题时,只是简单地使用IDA工具,用IDA打开exe或dll二进制文件查看文件中的汇编代码(IDA会将二进制文件中的二进制机器码反汇编出汇编代码),以辅助分析问题。本文并没有详细讲述IDA工具的功能,感兴趣的朋友,可以去阅读一下IDA经典书籍《IDA Pro权威指南》。

二进制机器码,汇编代码等价于二进制机器码,汇编代码是二进制机器码的助记符,汇编代码的可读性很强。在CPU中执行的是二进制机器码,等同于执行的就是汇编代码,通过查看汇编代码可以看出程序的具体执行细节。

相关文章:

使用反汇编工具IDA查看发生异常的汇编代码的上下文去辅助分析C++软件异常

目录 1、概述 2、如何使用IDA打开并查看二进制文件的汇编代码 3、在IDA中找到发生崩溃的那条汇编指令的位置 3.1、如何在IDA中找到发生异常的那条汇编指令 3.2、示例 4、阅读汇编代码上下文需要掌握一定的基础汇编知识 5、最后 VC常用功能开发汇总(专栏文章列…...

怎么合并多个视频?简单视频合并方法分享

合并多个视频可以将它们组合成一个更长的视频,这对于需要播放多个短视频的情况非常有用。此外,合并视频还可以使视频编辑过程更加高效,因为不必将多个独立的视频文件分别处理。最后,合并视频可以减少文件数量,从而使整…...

webpack基础知识九:如何提高webpack的构建速度?

一、背景 随着我们的项目涉及到页面越来越多,功能和业务代码也会随着越多,相应的 webpack 的构建时间也会越来越久 构建时间与我们日常开发效率密切相关,当我们本地开发启动 devServer 或者 build 的时候,如果时间过长&#xff…...

批量改名字序号和前缀

echo off setlocal enabledelayedexpansion set count10 for /f %%i in (dir /b *.jpg,*.png,*.bmp,*.jpeg,*.gif) do ( set /a count1 echo %%i 前缀_!count! rename %%i 前缀_!count!.png ) REM …...

基于Spring Boot的医院预约挂号网站设计与实现(Java+spring boot+MySQL)

获取源码或者论文请私信博主 演示视频: 基于Spring Boot的医院预约挂号网站设计与实现(Javaspring bootMySQL) 使用技术: 前端:html css javascript jQuery ajax thymeleaf 微信小程序 后端:Java spring…...

Linux命令200例:join将两个文件按照指定的键连接起来分析

🏆作者简介,黑夜开发者,全栈领域新星创作者✌。CSDN专家博主,阿里云社区专家博主,2023年6月csdn上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 &…...

谈谈网络安全

目录 1.概念 2.发展现状 3.主要问题 1.概念 网络安全是指保护计算机网络和其中的数据免受未经授权访问、损坏、窃取或破坏的过程和技术。网络安全涉及预防和检测潜在的威胁和漏洞,并采取措施保护网络的机密性、完整性和可用性。 网络安全的概念包括以下几个方面&am…...

机器学习深度学习——文本预处理

👨‍🎓作者简介:一位即将上大四,正专攻机器学习的保研er 🌌上期文章:机器学习&&深度学习——序列模型(NLP启动!) 📚订阅专栏:机器学习&am…...

Qt实现可伸缩的侧边工具栏(鼠标悬浮控制伸缩栏)

Qt实现可伸缩的侧边工具栏 一直在网上找,发现大多的实现方案都是用一个按钮,按下控制侧边栏的伸缩,但是我想要实现鼠标悬浮在侧边栏的时候就伸出,移开就收缩的功能,也没找到好的参考,所以决定自己实现一个…...

【Spring Boot】拦截器与统一功能处理

博主简介:想进大厂的打工人博主主页:xyk:所属专栏: JavaEE进阶 上一篇文章我们讲解了Spring AOP是一个基于面向切面编程的框架,用于将某方面具体问题集中处理,通过代理对象来进行传递,但使用原生Spring AOP实现统一的…...

RabbitMQ的6种工作模式

RabbitMQ的6种工作模式 官方文档: http://www.rabbitmq.com/ https://www.rabbitmq.com/getstarted.html RabbitMQ 常见的 6 种工作模式: 1、simple简单模式 1)、消息产生后将消息放入队列。 2)、消息的消费者监听消息队列,如果队列中…...

MFC第二十六天 CRgn类简介与开发、封装CMemoryDC类并应用开发

文章目录 CRgn类简介与开发CRgn类简介CRgn类区域管理开发CRgn类区域管理与不规则形状的选取 封装CMemoryDC类并应用开发CMemoryDC.h封装CMemoryDC开发游戏透明动画CFlashDlg.hCFlashDlg.cpp 封装CMemoryDC开发游戏动画 附录四大窗口CDC派生类 CRgn类简介与开发 CRgn类简介 CR…...

解决VScode远程服务器时opencv和matplotlib无法直接显示图像的问题

解决VScode远程服务器时opencv和matplotlib无法直接显示图像的问题 1、本方案默认本地已经安装了VScode与MobaXterm2、在服务器端3、在本地端安装MobaXterm4、测试5、opencv显示测试(测试过程中需保持MobaXterm开启的状态)6、 matplotlib显示测试&#x…...

支付模块功能实现(小兔鲜儿)【Vue3】

支付 渲染基础数据 支付页有俩个关键数据,一个是要支付的钱数,一个是倒计时数据(超时不支付商品释放) 准备接口 import request from /utils/httpexport const getOrderAPI (id) > {return request({url: /member/order/$…...

php meilisearch demo

# 创建一个meilisearch 使用完自动销毁 docker run -itd --rm -p 7700:7700 getmeili/meilisearch:v1.3docker-compose 参数 version: "3" networks:flyserver:driver: bridge services:search:image: getmeili/meilisearch:v1.3restart: alwaysenvironment:- MEILI…...

芒格之道——查理·芒格股东会讲话1987-2022

你越是认真生活,你的生活就会越美好! 这里将读书过程划线的内容摘抄在这里,方便自己回顾。 书分为两部分,我先读了后半部分,而且是从后往前读,到了前半部分,我是从前往后读。书还挺贵&#xff…...

如何运营手游联运平台游戏?

运营手游联运平台游戏需要综合考虑多个方面,包括游戏选择、合作伙伴、市场推广、用户运营等。以下是运营手游联运平台游戏的一些建议: 游戏选择:选择优质的手游,确保游戏的品质和内容能够吸引玩家,满足市场需求。 合…...

vscode连接远程Linux服务器

文章目录 一、环境安装1.1 下载vscode1.2 下载vscode-sever 二、ssh链接2.1 安装Remote-SSH2.2 设置vscode ssh2.3 设置免密登录2.3.1 本地生成公私钥2.3.2 服务器端添加公钥 三、安装插件3.1 vscode安装插件3.1.1 在线安装插件3.1.2.1 下载插件3.1.2.2 安装插件 3.2 vscode-se…...

numpy 转换成 cupy 利用GPU执行 错误

ModuleNotFoundError: No module named cupy._core. routines_sorting 提示缺少包 使用 pyinstaller -D views.py --nocons 可以正常打包出来 但是运行出现报错 说明这个打包工具 忽略了很多 隐式导入的包 解决方法很简单 hiddenimports [fastrlock, fastrlock.rlock, cu…...

力扣:55. 跳跃游戏(Python3)

题目: 给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标。 来源:力扣(LeetCode) 链接:力扣 示例&#xf…...

Unity 编辑器资源导入处理函数 OnPreprocessAudio :深入解析与实用案例

Unity 编辑器资源导入处理函数 OnPreprocessAudio 用法 点击封面跳转下载页面 简介 在 Unity 中,资源导入是一个非常重要的环节,它决定了资源在项目中的使用方式和效果。Unity 提供了一系列的资源导入处理函数,其中之一就是 OnPreprocessAud…...

mongodb-win32-x86_64-2008plus-3.4.24-signed.msi

Microsoft Windows [版本 6.1.7601] 版权所有 (c) 2009 Microsoft Corporation。保留所有权利。C:\Users\Administrator>cd C:\MongoDB\Server\3.4\binC:\MongoDB\Server\3.4\bin>C:\MongoDB\Server\3.4\bin>mongod --help Options:General options:-h [ --help ] …...

java的反射

在java语言中,反射机制是指对于处在运行状态的类,都能够获取到这个类的所有属性和方法。对于任意一个对象,都能够调用它的任意一个方法以及访问它的属性;这种通过动态获取类或对象的属性以及方法从而完成调用功能被称为java语言的…...

MySQL — InnoDB 锁

文章目录 锁共享锁和排他锁意向锁记录锁间隙锁临键锁插入意向锁自增锁 锁 加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行操作前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了一定的控制,在该事务…...

首批获得金融级行业云平台认证,天翼云深耕行业云

云计算下半场看什么? 无疑是金融、政务、制造等传统政企用户的上云与用云。随着数字经济发展和产业数字化的提速,上云已是政企用户推动其数字化转型不断深入的重要抓手,成为不可阻挡的趋势。 与互联网用户相比,政企用户上云极为…...

浅谈Python解释器的组成

Python解释器是一个复杂的软件,它可以解释和执行Python代码。以下是Python解释器的主要组成部分: 源代码词法分析器(Lexical Analyzer): 这部分的任务是将输入的Python源代码分解成称为"tokens"的基础元素。例如&#x…...

服务限流治理

一、基础概念 1.什么是服务限流? 限流在日常生活中也很常见,比如节假日你去一个旅游景点,为了不把景点撑爆,管理部门通常会在外面设置拦截,限制景点的进入人数(等有人出来之后,再放新的人进去…...

机器学习笔记 - 使用CLIP在没有数据的情况下创建图像分类器

想象一下,如果我们现在需要对人们是否戴眼镜进行分类,但您没有数据或资源来训练自定义模型。该怎么办?这里我们了解如何使用预先训练的 CLIP 模型来创建自定义分类器,而无需任何培训。这种方法称为零样本图像分类,它可以对原始 CLIP 模型训练期间未明确看到的类别图像进行…...

42.利用 牛顿迭代法解非线性高维方程组(matlab程序)

1.简述 若向量记号为X,方程组就可以写成F(X)0的形式。 我们知道,对于一元函数的牛顿迭代法求根公式 类似的,对于多元函数求根公式 其中X是向量,是非线性方程组对应的雅可比矩阵。 具体求解的时候,我们可以先通过绘图命令绘制图形…...

我在leetcode用动态规划炒股

事情是这样的,突然兴起的我在letcode刷题 121. 买卖股票的最佳时机122. 买卖股票的最佳时机 II123. 买卖股票的最佳时机 III 以上三题。 1. 121. 买卖股票的最佳时机 1.1. 暴力遍历,两次遍历 1.1.1. 算法代码 public class Solution {public int Ma…...