手把手教你汇编 Debug
关于汇编的第一篇文章:
爱了爱了,这篇寄存器讲的有点意思
Hello大家好,我是程序员cxuan!我们上篇文章了解了一下基本的寄存器,这篇文章我们来进行实际操作一下。
原文链接:手把手教你汇编 Debug
我们以后将会用到很多 Debug 命令,这里我们先来熟悉一下它们。
Debug 是什么
Debug 是 Windows / Dos 操作系统提供的一种功能。使用 Debug 能让我们方便查看 CPU 各种寄存器的值、内存情况,方便我们调试指令、跟踪程序的运行过程。
接下来我们会用到很多 debug 命令,但是使用这些命令的前提是,你需要在电脑上安装一下 debug,Windows/Mac 都可以安装,获取链接我已经给你找出来了。阿,忘记说了,我们这里使用的是 Dos box来模拟汇编的操作环境。
传送门(Mac 和 Windows 都是):https://www.dosbox.com/download.php?main=1
下载完成后打开 DosBox ,打开之后是这样的。
此时我们输入 debug 命令应该提示的是
因为我们还没有进行连接和挂载,此时我们执行
mount c D:\debug
执行这条命令时,你需要现在 D 盘下创建一个 debug 文件夹,然后我们挂载到 debug 下面。
并且执行 C:
切换到 C 盘路径下。
此时我们就可以执行 debug 命令了。
这里需要注意一点,我在 Windows 10 系统下搭建 Debug 环境时,在挂载完成后输入 debug ,还是提示 Illegal command:debug ,此时你需要再下载一个 debug.exe ,贴心的我也把下载地址给你了。
下载地址:https://pan.baidu.com/s/177arSA34plWqV-iyffWpEw#list/path=%2F 密码:3akd
需要下载里面的 debug.exe,然后把它放在你挂载的路径下,这里我挂载的路径时 D 盘下的 debug 文件夹。
放置完成之后,再输入 debug 就可以了。
因为每次打开 Dosbox 都会执行上面这些命令,真的好烦,那怎么办呢?一个简单的办法是在 Dosbox 安装路径下找到
打开之后,在末尾键入
就 OK 了,下次直接打开 Dosbox ,会默认执行这三条命令,至此,就是我搭建 Dosbox 遇到的所有问题了。
Debug 实战
玩儿汇编得学会用 Debug ,Debug 是一种调试程序,通过 Debug 能让我们能够看到内存值,跟踪堆栈情况,看到寄存器所暂存的内容等,同时也能够更好地帮助我们理解汇编代码,所以学会 Debug ,非常重要,这是一种不可或缺的动手能力。
下面我们会用到几种 Debug 命令,这里先简单介绍下。
Debug 命令有很多,不过常用的一般就上面这几个。
好了,现在我们直接进入正题,开始在 Dosbox 上正式进行 Debug 操作,首先打开 Dosbox。
嗯。。。。。。这个界面我们打开很多次了。
那我写个命令呢? 好吧,没演示过,下面就来了!
Debug -r
亲,用 Debug -r 就可以查看和修改 CPU 寄存器内容了呢。
查看寄存器内容。
这里需要注意一下 -r 大小写的问题,Debug -r 是查看寄存器内容。而 -R 则是无效指令。
上图列出来了很多寄存器,你可能觉得无从下手,不要乱,我们先从最基本的开始入手,也就是 CS 和 IP,CS(Code Segment)是代码段寄存器,一般也被称为段基址,可以认为是程序访问的入口,CPU 需要从 CS 中找到从哪个位置开始取指执行,但是我们还不知道要取哪一段,这时候 IP 的作用就体现出来了,IP(Instruction Pointer)就是指令指针寄存器,也叫做偏移地址,它会告诉我们从段基址开始,取哪一段的地址。
可以使用段基址:偏移地址来确定内存中的指定地址。
这里我们只是简单聊一下这两个寄存器的概念,要了解这两个寄存器的具体作用,可以看笔者的上一篇文章
使用 -r 也能够修改寄存器的内容,如下所示
-r 一般的格式是 -r 寄存器,然后系统会进行冒号提示,后面就是你要修改的内容。
Debug -d
使用 -d 指令可以查看内存中的内容。
输出的内存值默认是按照 CS:IP 的地址开始的,由于 CS 的值默认是 073F,而 IP 默认是 0100,所以 -d 的内存值是 073F:0100 。
-d 的格式很多,下面只介绍一下常用的几种格式。
形似 -d 1000:0 这种 -d 段基址 偏移地址的格式可以产生如下输出。
如上图所示,Debug 会列出指定内存单元中的的内容。上图中的每一个 00 都表示 8 位,如果是 4A,那么这八位展开来说就是 0010 1011 。每一行有 16 个 8 位,所以构成了 128 位内存地址。
为什么都是 00 呢,因为内存单元的值没有被改写,说白了就是这块内存区域没有存值,如何改写我们后面回收。
每一行的中间都有一个 -
,这个是为了便于我们阅读来设置的,- 号前后都有 8 个内存单元,这样便于查看。
右侧几个 ...... 表示每个内存单元可显示的 ASCII 码字符,因为内存没有值,所以也没有对应的 ASCII 码。我们可以数一下,每行有 16 个 . ,这表示每一个 00 都对应了一个 ASCII 码。
我们可以使用 -d 1000:9 这种 -d 段基址:起始偏移地址 格式来显示从 1000 的第几位开始。
Debug 从 1000:9 开始,一直到 1000:88,一共是 128 个字节,第一行中的 1000:0 ~ 1000:8 中的内容没有显示。
还可以使用 -d 1000:0 9 这种 -d 段基址:起始偏移地址 结尾偏移地址的格式来输出。
还可以是使用 -d 偏移地址来在不指定段基址的情况下,查看内存值。
Debug -e
上面说的都是查看内存中指定位置或者区域的值,下面我们要来改写一下内存值。
使用 -e
可以改写内存值,比如我们想要改写 1000:0 ~ 1000:f 中的内容,可以使用 -e 1000:0 0 1 2 3 4 5 6 7 8 9 0 a b c d e f 这种方式,如下图所示。
这里需要注意下,在进行 -e 改写的时候,每个值中间都有一个空格,如果没有空格的话,会当做一个内存值来看待。
然后用 -d 1000:0 看到我们刚改写的内存值。
还可以使用提问的方式来逐个修改从某一地址开始的内存单元的内容。
还是用 1000:100 来举例子,输出 -e 1000:100 后按下回车键。
如上图所示,可以看到我们先输入了一次 -e 1000:100 这个指令,然后按下了回车键。
注意,如果这里你按下了回车键,就相当于整个 -e 改写的过程已经完成。
如果你想要继续改写后面内存中的值,你需要按下空格键。
我们改写了 1000:100 之后的内存值,然后使用 -d 1000:100 查看我们改写的内容是否生效。
-e 命令还可以支持写入字符,比如我们可以向 1000:0 这个位置开始写入数值和字符,-e 1000:0 1 'a' 2 'b' e 'c' 。
如上图所示,当我们向内存写入字符 'a' 'b' 'c' 的时候,会自动转换为 ASCII 码进行存储,在最右侧可以找到刚刚写入的字符。
Debug -u
如何向内存中写入一段机器码呢?比如我们想要在内存中写入一段机器码。
我们可以使用 -e 来进行写入,向内存中写入 b8 01 00 b9 02 00 01 c8 这个机器码,如下所示
我们使用 -e 写入之后,使用 -d 查看内存值,可以发现我们刚刚写入的值,但是却看不到机器码,所以机器码该如何看呢?
别急,还有个 -u 命令,这个就是看机器码的,如下图所示,我们使用 -u 命令显示我们写入的机器码。
可以看到 1000:0000 ~ 1000:0006 这个内存地址使我们写入的机器码,-u 这个命令就是将内存单元的内容翻译为汇编指令并显示。
-u 输出的结果分为三部分显示:
- 最左侧是每一条机器指令的地址;
- 中间是机器指令;
- 最右侧是机器指令执行的汇编指令。
1000:0 处存放的是写入的机器码 B8 01 00 组成的机器指令,对应的汇编指令是 MOV AX,0001。
1000:0003 处存放的是写入的机器码 B9 02 00 组成的机器指令,对应的汇编指令是 MOV CX,0002。
1000:0006 处存放的是写入的机器码 C1 C8 所组成的机器指令,对应的汇编指令是 add ax,cx。
Debug -t
上面介绍的一系列指令包括我们上面提到的 Debug -e 机器码都是向内存中进行写入,那么如何执行这些指令呢?
我们可以使用 Debug -t 来执行写入的指令。使用 Debug -t 可以执行由 CS:IP 指向的指令。
既然是 -t 能够执行从 CS:IP 指向的命令,所以我们有必要将 CS:IP 指向 1000:0(因为我们前面将指令写在了 1000:0 处)。
首先我们需要执行 -r cs 1000 ,-r ip 0 把 CS:IP 赋值为 1000:0。
然后执行 -t 指令,下图是已经执行过的指令截图。
可以看到,执行完 -t 指令之后,MOV AX,0001 这条指令被执行,当前 AX 寄存器的内容变为了 0001,这条汇编指令的意思就是把 0001 移动到 AX 寄存器中。
继续执行 -t 之后,我们可以看到寄存器的变化。
Debug -a
毕竟机器指令不是那么好懂,写入很不方便,所以有没有办法能够支持我们直接写入汇编指令呢?还真有,Debug 提供了 -a 这种方式来实现汇编指令的写入。如下图所示
可以看到,我们使用了 -a 命令来对 1000:0 进行写入,分别输入 mov ax,1 mov bx,2 mov cx,3 add ax,bx add ax,cx add ax,ax 指令,然后按回车进行确定执行。
我们使用 -d 1000:0 f 可以看到从偏移地址 0 处开始的第 f 个内存指令(因为最大写入的地址只是 f)。
上图中的 1000:000F 为什么有值呢,因为我们上面已经执行过这个写入了。
另外,使用 -a 可以从一个预设的地址处开始输入指令。
总结
今天和大家聊了一下 Debug 的基本用法,主要包括
- -r 查看、修改寄存器中的内容
- -d 查看内存中的指令
- -e 修改内存中的内容
- -u 可以将内存中的内容解释为机器指令和对应的汇编指令
- -t 执行 CS:IP 处的指令
- -a 以汇编得形式向内存写入内容
汇编指令的选项有很多,上面介绍的这些属于经常用到的指令,这些指令要能够熟练使用。
最后给大家推荐一下我自己的Github ,里面有非常多的硬核文章,绝对会对你有帮助。
手把手教你汇编 Debug的更多相关文章
- UWP Jenkins + NuGet + MSBuild 手把手教你做自动UWP Build 和 App store包
背景 项目上需要做UWP的自动安装包,在以前的公司接触的是TFS来做自动build. 公司要求用Jenkins来做,别笑话我,之前还真不晓得这个东西. 会的同学请看一下指出错误,不会的同学请先自行脑补 ...
- [原创]手把手教你写网络爬虫(4):Scrapy入门
手把手教你写网络爬虫(4) 作者:拓海 摘要:从零开始写爬虫,初学者的速成指南! 封面: 上期我们理性的分析了为什么要学习Scrapy,理由只有一个,那就是免费,一分钱都不用花! 咦?怎么有人扔西红柿 ...
- [原创]手把手教你写网络爬虫(5):PhantomJS实战
手把手教你写网络爬虫(5) 作者:拓海 摘要:从零开始写爬虫,初学者的速成指南! 封面: 大家好!从今天开始,我要与大家一起打造一个属于我们自己的分布式爬虫平台,同时也会对涉及到的技术进行详细介绍.大 ...
- 手把手教你通过Ambari新建Hadoop集群图解案例
手把手教你通过Ambari新建Hadoop集群图解案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 登陆系统之后,会看到Ambari空空如也的欢迎界面,接下来我们就需要介绍如何通 ...
- C#:手把手教你用C#打包应用程序(安装程序卸载程序)
摘要:本文介绍在C#中手把手教你用C#打包应用程序(安装程序卸载程序) 1:新建安装部署项目 打开VS,点击新建项目,选择:其他项目类型->安装与部署->安装向导(安装项目也一样),然后点 ...
- 手把手教你搭建织女星开发板RISC-V开发环境
前言 Windows环境下搭建基于Eclipse + RISC-V gcc编译器的RISC-V开发环境,配合openocd调试软件,可以实现RISC-V内核程序的编译.下载和调试. 准备工作 工欲善其 ...
- 手把手教你使用VUE+SpringMVC+Spring+Mybatis+Maven构建属于你自己的电商系统之vue后台前端框架搭建——猿实战01
猿实战是一个原创系列文章,通过实战的方式,采用前后端分离的技术结合SpringMVC Spring Mybatis,手把手教你撸一个完整的电商系统,跟着教程走下来,变身猿人找到工作不是 ...
- 手把手教你使用IDEA2020创建SpringBoot项目
一.New Project 二.如图选择Spring Initalizr,选择jdk版本,然后点击Next(注意:SpringBoot2开始至少使用JDK1.8) 三.如图根据自己需要修改,然后点击N ...
- 手把手教你实现Android真机远程截屏
先看效果演示 接下来手把手教你实现这样的效果. minicap简介 minicap是一个可以远程获取android屏幕画面的开源库,它在低版本的Android系统上采用截屏的方式获取画面,在Andro ...
随机推荐
- Feed 流系统杂谈
什么是 Feed 流 Feed 流是社交和资讯类应用中常见的一种形态, 比如微博知乎的关注页.微信的订阅号和朋友圈等.Feed 流源于 RSS 订阅, 用户将自己感兴趣的网站的 RSS 地址登记到 R ...
- 微服务架构理论&SpringCloud
一.什么是微服务? 微服务是一种程序架构模式,它提倡将单体应用程序划分成若干的小服务模块,服务之间互相协调.互相配合,为用户提供最终价值.每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制 ...
- 题解 「BZOJ2137」submultiple
题目传送门 题目大意 给出 \(M,k\) ,求出 \[\sum_{x|M}\sigma(x)^k \] 给出 \(P_i\),满足 \(n=\prod_{i=1}^{n}a_i^{P_i}\),其中 ...
- HAOI2012高速公路bzoj2752 (线段树,数学)
题目大意: 给定一个长度为n的链,一共m次操作 对于每次操作 \(C\ l\ r\ x\)表示将第l个点到第r个点之间的所有道路的权值增加v \(Q\ l\ r\)在第l个到第r个点里等概率随机取出两 ...
- 【学习转载】MyBatis源码解析——日志记录
声明:转载自前辈:开心的鱼a1 一 .概述 MyBatis没有提供日志的实现类,需要接入第三方的日志组件,但第三方日志组件都有各自的Log级别,且各不相同,但MyBatis统一提供了trace.deb ...
- Netty 组件分析
EventLoop 事件循环对象 EventLoop 本质是一个单线程执行器(同时维护了一个 Selector),里面有 run 方法处理 Channel 上源源不断的 io 事件. 它的继承关系比较 ...
- Java(6)流程控制语句中分支结构if与switch
作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201528.html 博客主页:https://www.cnblogs.com/testero ...
- gitk
gitk gitk [<options>] [<revision range>] [--] [<path>-] 查看单个文件的变更历史 gitk -- CppPri ...
- Java RMI学习与解读(一)
Java RMI学习与解读(一) 写在前面 本文记录在心情美丽的一个晚上. 嗯.就是心情很美丽. 那为什么晚上还要学习呢? emm... 卷... 卷起来. 全文基本都是根据su18师傅和其他师傅的文 ...
- Java:并发笔记-02
Java:并发笔记-02 说明:这是看了 bilibili 上 黑马程序员 的课程 java并发编程 后做的笔记 3. 共享模型之管程-1 本章内容-1 共享问题 synchronized 线程安全分 ...