《C++ 黑客编程揭秘与防范》—第1章1.2节应用程序的调试

简介:

本节书摘来自异步社区《C++ 黑客编程揭秘与防范》一书中的第1章1.2节应用程序的调试,作者冀云,更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.2 应用程序的调试
C++ 黑客编程揭秘与防范
在开发程序的过程中,除了编码以外还需要对程序进行调试,当编写的程序出现问题后,就要对程序进行调试。调试不是仅使用一个printf()或MessageBox()进行简单的输出来观察某个函数的返回值(虽然在调试的时候的确是对返回值观察较多),也不是对某个变量、某一时间的具体值的输出。调试是有专业的调试分析工具的,VC6不但提供代码编辑、代码编译、编译连接等功能,还提供了一个非常好用的调试工具。在编写完代码后,如果程序输出的结果是未知的,或者是没有预测到的,都可以通过调试来对代码的逻辑进行分析,以找到问题的所在。掌握调试的技能,对软件的开发有非常大的帮助。掌握好的调试工具,对于调试者来说,也同样会起到事半功倍的作用。下面通过一个简单的例子了解一下VC6提供的调试功能吧。

1.2.1 编写我们的第一个程序
下面介绍用VC6写一个控制台版的HelloWorld来学习VC6的开发。也许大家认为这个程序很简单,但是请记住,我们的重点是要介绍VC6这个集成开发环境中提供的调试功能。

启动VC6,单击菜单“File”->“New”命令,在弹出的对话框中选择“Projects”选项卡,然后在左边的列表框中选择“Win32 Console Application”选项,在“Project Name:”文本框中填写“HelloWorld”,如图1-4所示。

单击“OK”按钮,出现如图1-5所示窗口。

选择“An empty project”单选项,单击“Finish”按钮,然后在弹出的对话框中单击“OK”按钮。

单击菜单“File”->“New”命令,选择“Files”选项卡,在左边的列表中选择“C++ Source File”选项,在右边的“File”文本框中填写“HelloWorld”,如图1-6所示。


56613a2a8f3e257d3d85cefc3fdaaa47e5ff07e8


3911866047f2661b24e50dd5e26508a2bd57767b


f35c1866b26c237ec67bd6d0957d0461297ad04a

单击“OK”按钮就可以进行代码编辑了。

在代码编辑处录入如下代码:

#include <stdio.h>
int main()
{
  printf("Hello World ! \r\n");
  return 0;
}

按F7键进行编译连接(按Ctrl + F7组合键是只编译不进行连接),按Ctrl + F5组合键进行运行,如图1-7所示。


ddf0239de5faf782a13b1107afe710c2e99b2948

这就是我们值得纪念的第一个程序。这个程序很简单,有C语言基础的读者应该都能看懂,这里就不进行介绍了。如果看不懂,请先找本关于C语言入门的书学习一下。

1.2.2 用VC6调试第一个程序
现在来学习如何使用VC6对第一个程序进行调试。在代码编辑状态下,按下键盘上的F10键,进入调试状态,如图1-8所示。

常用的调试窗口有两个,一个是“Watch”窗口(标注“1”的那个窗口),一个是“Memory”窗口(标注“2”的那个窗口)。打开“Watch”窗口的方法是单击“View”->“Debug Windows”->“Watch”命令(或按Alt + 3组合键)打开。打开“Memory”窗口的方法是单击“View”->“Debug Windows”->“Memory”命令(或按Alt + 6组合键)打开。“Watch”窗口用来监视我们感兴趣的变量,而当我们有时无法通过变量的值进行判断时,就需要借助“Memory”窗口中的值,比如,指针的值来进行判断。

除了这两个窗口以外,还有“Call Stack”、“Register”和“Disassembly”这3个窗口,分别如图1-9、图1-10和图1-11所示。


d585ffe73859cbb8ffa17a16b1fada3b2ac209c9


678887bbe9b7a1bc87ba78d9ab368d99b0f17827


3b180c2f931e3f56896261db168c583c3409af5b


f3b096a597dde945dfd23c0d814f0564d2656adb

“Call Stack”窗口是调用栈窗口,该窗口可以很方便地查看调用关系,很容易通过调用栈来找到上层、上上层的调用者。另外,也可以通过调用栈来定位错误。比如,有时程序会崩溃,但是发生崩溃的地方却在系统提供的代码中,而不在我们编写的代码中,这种错误在通常情况下是我们的程序对于参数的输入有误造成的,我们可以通过调用栈查看是谁调用了该函数,以便进行进一步分析。

“Register”窗口是用来观察寄存器的。有时需要观察返回值或者参数。

“Disassembly”窗口是用来观察C代码对应的反汇编代码的。有时在看C的代码无法解决的问题时,需要查看在底层实现时分析程序的问题。

以上就是VC6下常用的调试窗口,可根据实际情况使用,并不是每次调试都会用到这些窗口。下面再简单介绍一下常用的调试快捷键,以方便今后进行调试时使用。

VC6调试时的常用快捷键如下。

F5键:运行程序。

F9键:设定断点/取消断点。

F10键:单步步过,依次执行每一条代码。

F11键:单步步入,依次执行每一条代码,遇到函数调用时则进入到被调用的函数中。

F7键:停止调试。

在后面的章节中我们会用到这些快捷键来调试程序,让大家在学习的过程中真正地应用起这些调试功能。

1.2.3 专业的应用程序调试工具——OllyDbg
OllyDbg,简称OD,是专业的应用程序调试工具。接触过破解,或者做过外挂开发的读者一定对这款工具不陌生。在这里,简单介绍一下这款工具。

让我们先来看看它的界面吧,如图1-12所示。


b3ee32fa5700b8f4a8e6a0ebac3dd9812730ce6a

OD的大多数情况是在没有源代码的情况下对软件进行调试的。也许没有源代码也就不叫调试了,而叫做动态分析。OD的主界面中有6个主要的窗口,分别是反汇编窗口、寄存器窗口、提示信息窗口、数据窗口(也叫转存窗口)、栈窗口和命令提示窗口。

下面逐个介绍一下各个窗口的作用。

(1)反汇编窗口:这是调试或动态分析时的主要窗口,我们主要是针对软件的功能实现进行分析,因此主要需查看的就是反汇编窗口的内容。

(2)寄存器窗口:该窗口的作用是实时地显示寄存器的变化情况。寄存器也可以反映代码的执行情况。例如,我们常常查看返回值的eax的值。

(3)提示信息窗口:这里往往会显示一些内存地址的值、寄存器的值、调用方的地址等信息。

(4)数据窗口:该窗口主要是用来显示数据的,单击右键可以把数据按照不同的方式进行解析,对于我们分析程序的过程是非常有用的。

(5)栈窗口:该窗口可以用来查看函数调用时参数的值。

(6)命令提示窗口:该窗口是用来输入调试命令的。

OD调试时的常用快捷键如下。

F8键:单步步过,依次执行每一条代码。

F7键:单步步入,依次执行每一条代码,遇到函数调用时则进入到被调用的函数中。

F4键:执行到选中的代码处(前提条件是该条代码在程序的流程中一定会被执行到)。

F2键:断点中断。

F9键:运行程序。

OD的介绍到此为止,在后面的内容中我们会再次提到OD,到那时会有一定的机会练习使用OD。如果有对OD感兴趣的读者,请另行阅读其他书籍。

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

相关文章
|
3月前
|
C++
C++ 根据程序运行的时间和cpu频率来计算在另外的cpu上运行所花的时间
C++ 根据程序运行的时间和cpu频率来计算在另外的cpu上运行所花的时间
47 0
|
15天前
|
Ubuntu Linux Shell
C++ 之 perf+火焰图分析与调试
【11月更文挑战第6天】在遇到一些内存异常的时候,经常这部分的代码是很难去进行分析的,最近了解到Perf这个神器,这里也展开介绍一下如何使用Perf以及如何去画火焰图。
|
29天前
|
存储 并行计算 安全
C++多线程应用
【10月更文挑战第29天】C++ 中的多线程应用广泛,常见场景包括并行计算、网络编程中的并发服务器和图形用户界面(GUI)应用。通过多线程可以显著提升计算速度和响应能力。示例代码展示了如何使用 `pthread` 库创建和管理线程。注意事项包括数据同步与互斥、线程间通信和线程安全的类设计,以确保程序的正确性和稳定性。
|
1月前
|
存储 程序员 编译器
简述 C、C++程序编译的内存分配情况
在C和C++程序编译过程中,内存被划分为几个区域进行分配:代码区存储常量和执行指令;全局/静态变量区存放全局变量及静态变量;栈区管理函数参数、局部变量等;堆区则用于动态分配内存,由程序员控制释放,共同支撑着程序运行时的数据存储与处理需求。
112 21
|
1月前
|
Ubuntu Linux Shell
C++ 之 perf+火焰图分析与调试
【10月更文挑战第8天】在遇到一些内存异常的时候,经常这部分的代码是很难去进行分析的,最近了解到Perf这个神器,这里也展开介绍一下如何使用Perf以及如何去画火焰图。
|
1月前
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
57 2
|
2月前
|
编译器 C++
【C++核心】函数的应用和提高详解
这篇文章详细讲解了C++函数的定义、调用、值传递、常见样式、声明、分文件编写以及函数提高的内容,包括函数默认参数、占位参数、重载等高级用法。
23 3
|
2月前
|
C++
【C++基础】程序流程结构详解
这篇文章详细介绍了C++中程序流程的三种基本结构:顺序结构、选择结构和循环结构,包括if语句、三目运算符、switch语句、while循环、do…while循环、for循环以及跳转语句break、continue和goto的使用和示例。
49 2
|
2月前
|
Ubuntu Linux Shell
C++ 之 perf+火焰图分析与调试
简介 在遇到一些内存异常的时候,经常这部分的代码是很难去进行分析的,最近了解到Perf这个神器,这里也展开介绍一下如何使用Perf以及如何去画火焰图。 1. Perf 基础 1.1 Perf 简介 perf是Linux下的一款性能分析工具,能够进行函数级与指令级的热点查找。利用perf剖析程序性能时,需要指定当前测试的性能时间。性能事件是指在处理器或操作系统中发生的,可能影响到程序性能的硬件事件或软件事件 1.2 Perf的安装 ubuntu 18.04: sudo apt install linux-tools-common linux-tools-4.15.0-106-gen
|
3月前
|
存储 算法 C++
C++ STL应用宝典:高效处理数据的艺术与实战技巧大揭秘!
【8月更文挑战第22天】C++ STL(标准模板库)是一组高效的数据结构与算法集合,极大提升编程效率与代码可读性。它包括容器、迭代器、算法等组件。例如,统计文本中单词频率可用`std::map`和`std::ifstream`实现;对数据排序及找极值则可通过`std::vector`结合`std::sort`、`std::min/max_element`完成;而快速查找字符串则适合使用`std::set`配合其内置的`find`方法。这些示例展示了STL的强大功能,有助于编写简洁高效的代码。
52 2