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

news2024/10/6 2:21:20

目录

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/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/124758670

5、最后

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

备战秋招011(20230807)

文章目录 前言一、今天学习了什么?二、算法----》单调栈1、介绍2、题目 总结 前言 提示:这里为每天自己的学习内容心情总结; Learn By Doing,Now or Never,Writing is organized thinking. 今天拿到了上周面试的结果…

选读SQL经典实例笔记19_Any和All

1. Any 1.1. 任意一个 1.2. 选修了任意一门课程的学生 1.2.1. 找出选修了至少一门课程的学生 1.3. 比任何火车都快的飞机 1.3.1. 找出比所有火车都快的飞机 2. All 2.1. 全部 2.2. 吃所有蔬菜的人 2.2.1. 没有任何一种蔬菜他们不吃 3. 问题12 3.1. 选修了全部课程的…

scikit-plot 使用笔记

scikit-plot是基于sklearn和Matplotlib的库,主要的功能是对训练好的模型进行可视化。 安装: pip install scikit-plot 功能1:评估指标可视化 scikitplot.metrics.plot_confusion_matrix快速展示模型预测结果和标签计算得到的混淆矩阵。 im…

ForkJoinPool详解

一、归并排序 1、简介 先把一个庞大的数组进行递归分解,把拆分的数组排好序,之后把拆分排好序的数组进行有序的合并,必须住的问题就是,递归拆分的阈值,比如当数组长度拆分到10000时候就不拆了,不能无限制…

TPU编程竞赛系列 | 创客北京2023·算能AI+边缘计算专项赛开始啦!

为助力北京市高精尖产业发展,构建大中小企业相互依存、相互促进的企业发展生态,打造北京市有影响力的双创服务品牌赛事,“创客北京”大赛组委会联合算能举办AI边缘计算方向专项赛。 1.赛题任务 本赛题基于“AI边缘计算”方向,针对…

21、springboot的宽松绑定及属性处理类的构造注入

springboot的宽松绑定及属性处理类的构造注入 ★ 如何使用属性处理类所读取的属性 属性处理类最终变成了Spring容器中的一个Bean组件,因此接下来Spring即可将该Bean组件注入任意其他组件。 这种做法的好处是:可以将大量的配置信息封装一个对象——所以…

利用openTCS实现车辆调度系统(三)车辆适配器解读,封装自己的适配器

适配器的官方解释:openTCS 支持自定义车辆驱动程序的集成,这些驱动程序实现特定于车辆的通信协议,从而在内核和车辆之间进行调解。 由于其功能,车辆驾驶员也称为通信适配器。 openTCS适配器。欢迎随时沟通 1、源码下载 github下…

arcgis宗地或者地块四至权利人信息提取教程

ARCGIS怎样将图斑四邻的名称及方位加入其属性表 以前曾发表过一篇《 如何把相邻图斑的属性添加在某个字段中》的个人心得,有些会员提出了进一步的要求,不但要相邻图斑的名称,还要求有方位,下面讲一下自己的做法。 基本思路是:连接相邻图斑质心,根据连线的角度确定相邻图斑…

动态规划(二)

一、线性DP 1.1数字三角形 #include<iostream> #include<algorithm>using namespace std;const int N 510,INF 1e9;int n; int a[N][N]; int f[N][N];int main() {scanf("%d",&n);for(int i 1;i < n;i ){for(int j 1;j < i; j )scanf(&qu…

【2.3】Java微服务:sentinel服务哨兵

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a; Java微服务 ✨特色专栏&#xff1a; 知识分享 &am…

Spring 事务失效的八种场景

1. 抛出检查异常导致事务不能正确回滚 Service public class Service1 {Autowiredprivate AccountMapper accountMapper;Transactionalpublic void transfer(int from, int to, int amount) throws FileNotFoundException {int fromBalance accountMapper.findBalanceBy(from…

Butterfly 安装文档(一) 快速开始

安装 在你的Hexo根目录里面 git clone -b master https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly 应用主题 修改 Hexo 根目录下的 _config.yml&#xff0c;把主题改为 butterfly theme: butterfly 安装插件 如果你没有 pug 以及 stylus 的渲染…

字符串查找匹配算法

概述 字符串匹配&#xff08;查找&#xff09;是字符串的一种基本操作&#xff1a;给定带匹配查询的文本串S和目标子串T&#xff0c;T也叫做模式串。在文本S中找到一个和模式T相符的子字符串&#xff0c;并返回该子字符串在文本中的位置。 暴力匹配 Brute Force Algorithm&a…

20天突破英语四级高频词汇——第②天

2&#xfeff;0天突破英语四级高频词汇~第2天加油(ง •_•)ง&#x1f4aa; &#x1f433;博主&#xff1a;命运之光 &#x1f308;专栏&#xff1a;英语四级高频词汇速记 &#x1f30c;博主的其他文章&#xff1a;点击进入博主的主页 目录 2&#xfeff;0天突破英语四级高…

LouvainMethod分布式运行的升级之路

1、背景介绍 Louvain是大规模图谱的谱聚类算法&#xff0c;引入模块度的概念分二阶段进行聚类&#xff0c;直到收敛为止。分布式的代码可以在如下网址进行下载。 GitHub - Sotera/spark-distributed-louvain-modularity: Spark / graphX implementation of the distri…

SQL server 与 MySQL count函数、以及sum、avg 是否包含 为null的值

sql server 与 mysql count 作用一样。 count 计算指定字段出现的个数&#xff0c; 不是计算 null的值 获取表的条数 count(n) n:常数 count(1),count&#xff08;0&#xff09;等 count(*) count(字段) 其中字段为null 不会统计在内。 avg(字段)、sum(字段) 跟count(字段)…

数字孪生技术的实用价值体现在哪?

随着科技的不断进步&#xff0c;数字孪生技术已成为引领未来发展的重要驱动力。数字孪生是将现实世界与数字世界紧密结合的技术&#xff0c;通过创建虚拟的物理模型&#xff0c;实时模拟和分析真实世界中的物体和过程&#xff0c;让数字孪生在各个领域都展现出了巨大的潜力&…

通用Mapper的四个常见注解

四个常见注解 1、Table 作用&#xff1a;建立实体类和数据库表之间的对应关系。 默认规则&#xff1a;实体类类名首字母小写作为表名&#xff0c;如 Employee -> employee 表 用法&#xff1a;在 Table 注解的 name 属性中指定目标数据库的表名&#xff1b; 案例&#…

vscode extension 怎么区分dev prod

开发模式注入环境变量 使用vsode 提供的api

【返回时间字段问题--消息转换器】

文章目录 前言一、第一种方式一、第二种方式&#xff08;推荐 ) 前言 一、第一种方式 1). 方式一 在属性上加上注解&#xff0c;对日期进行格式化 但这种方式&#xff0c;需要在每个时间属性上都要加上该注解&#xff0c;使用较麻烦&#xff0c;不能全局处理。 一、第二种方…