这可能是最详细的 Windows Debug 详解 了

时间:2024-03-19 19:50:45

Debug概览

Debug是什么?

  • debug是Windows 16位或者32位机器上的一款调试工具。也就是说,在WindowsXP及以前的机器上都有debug,直接Win+X debug就可以调出;在之后的32位机也有;但是在之后的64位机器上不存在,即使有,也无法运行。不必尝试到底能不能运行,绝对不能
  • 相似的,微软的masm也无法在64位版本的系统上运行。
  • 可以通过安装dosbox来虚拟一个DOS环境或者使用WindowsXP(虚拟机即可)的方式来使用debug和masm。

debug的作用是什么?如何打开debug?

  • 顾名思义 - 用来调试的工具。debug有极为丰富的命令支持,灵活、高效。debug的调试不同于IDE的调试 - 虽然都支持下断点的方式,但是debug能够直接查看CPU寄存器的内容,甚至能够在程序运行过程中修改自身代码 - 这是IDE望尘莫及的。
  • 打开debug的方式:Win + X呼出运行窗口,输入cmd,然后输入debug回车就行了。进入debug后,命令提示符会变成“-”,如下图。
    这可能是最详细的 Windows Debug 详解 了
    但是一般来说不使用系统的debug进行实验以防止无意中损坏系统,一般来说使用单独分离出来的debug进行实验,以获得更高的安全性和更完整的功能体验。Debug下载链接在文末,与masm同打包
    调用时在cmd中cd到存放debug.exe的文件夹,输入debug并回车就可以了。或者在当前文件夹编写一个bat,内容为字母cmd,撒谎及运行可以达到同样的效果。

使用DEbug时你必须知道的几点

0.所有数据都是10进制,除非有别的进制的符号修饰(如50h)

1.range 表示范围,不同指令默认段有所不同。均可以适用类似 CS:0100L2的形式表示范围

2.不能使用符号常量和符号地址.(就是说不能用变量和指针)

3.不能使用绝大部分伪指令,但两个最常用的伪指令 DB 和 DW 能被使用,用于直接把字节和字数据置入相应存储单元。如:
DB 1,2,3,4,“ABCD”
DW 1234,5678

Debug用法

参数一览表

命令 含义 用法
A assemble 在内存中直接编写代码
C Compare 比较内存
D Dump 查看内存内容
E Enter 修改内存内容
F Full 填充内存
G Go 执行代码
H Hexarithmetic 以16进制进行数学运算
I Input 从某个端口输入一个16进制并显示
L load 把文件或者绝对扇区内容读入内存
M move 数据传递(不同于汇编的move)
N name 为读写磁盘文件定义文件名
O output 把指定字节发送到制定端口
Q quit 结束debug程序
R Register 寄存器命令
S Search 按照list清单查找内存range范围
T track 追踪命令
U UNassemble 反汇编内存中的指令
W write 把调试过的信息写到磁盘上
? Help 获取帮助信息,即现实所有支持的命令

详解

0.启动Debug的参数

启动形式:Debug [完整路径][文件名][.exe][exe的参数1][exe的参数2]

其中,方括号内的内容为可选值。若载入了一个文件(注意,不一定是exe,也有可能是转储文件),则载入的位置是CS指向的位置,偏移量为0

如果输入文件名 filename,那么 DEBUG 就把所指定的文件装入内存,然后可以输入命令来修改、显示或执行指定文件的内容。如果不输入文件名 filename,那么或使用当前存储器的内容进行工作,或使用命名命令 Name 和装入命令 Load 把需要的文件或者准确的磁盘扇区装入存储器中,然后可以输入命令来修改、显示或执行存储器的内容。

1.汇编指令A(assemble)

  • 作用:键入汇编指令,并把它们汇编成机器代码,相继存放在从指定地址开始的存储区中。
  • 形式:A[address] (A与addr有无空格均可) , A [基址寄存器:][偏移] (有无空格均可)

  • 汇编指令有以下两种格式:

    a ;从上次停下的地方继续输入汇编指令(上次a指令停下的地方)

    a 开始地址 ;从起始位置开始编写汇编代码(举例:A CS:1100 ,即为从cs:1100的地方开始编写汇编代码)

2.比较指令C(compare)

  • 作用:比较两个数据块的内容

  • 格式: C range addr , 其中range为第一个数据块的起始地址加长度(用以构成数据块),如果不写段寄存器,默认DS,第二个只写目标地址,不写段寄存器默认DS

  • 如果找到不相等的字节,则用下列形式显示地址和内容: addr1 byte1 byte2 addr2
    此处,前一半(即 addr1 byte1)说明 range 内不相等单元的位置和内容,后面的一半指的是在 address 中找到的不相等的内容和位置。

  • 举例:

    C 100L20 200
    把 DS:100 开始的存储器的 32 个字节同从 DS:200 开始的 32 个字节进行比较。

    C表示比较指令,100表示起始地址,没有写段所以默认DS

    L表示段长度,20是十六进制,换下来是32字节

3.显示内存指令D(Dump)

  • 作用:显示存储器内容(16进制)
  • 格式:D [addr] 或 D [range] , 有无空格均可。
  • 详细:
    • D DS:1100 ;从DS:1100开始显示
    • D ;从上次停下的位置开始显示
    • D 0100 ; 没有段寄存器,默认DS
    • D [addr]L[size] ;从addr处开始显示size(16进制)个字节的数据,addr含义同1 - 3
    • D [start_addr] [end_addr] ;从start_addr 显示到end_addr

4.修改内存指令E(enter)

  • 作用:修改内存的值

  • 形式:E addr [list]

    • 不存在list时:显示addr的内容,并等待输入一个16进制数以替换之数据段默认DS

    • 存在list时:使用list的内容填充addr之后list长度的内存的内容

    eg:E DS:1000 f3 ‘xyz’ d8 ;使用f3 x y z d8 五个字节的内容替换DS:1000 到 DS:1004的内容

    例如:
    E address
    现在可以开始下列操作:
     输入一个或两个十六进制值的字符去替换字节的内容,然后采取下面操作之一。
     按空格步进到下个地址,并显示其内容。如果希望改变其内容就采取上述第一条操作。
     输入连字符“—”退回到前一个地址,并显示其内容。如果希望改变其内容则采取上述第一条操作。
     为了退回一个以上的字节且不改变当前字节,应输入另一个连字符。
     为了结束 E 命令,按 ENTER 键。
    例如:
    E cs:100
    可以得到如下显示内容:
    04BA:0100 EB._
    为了把 04BA:0100 内容由 EBH 改变成 41H,则输入 41:
    04BA:0100 EB.41
    为了查看下三个单元的内容,按三次空格,屏幕显示出:
    04BA:0100 EB.41 10.00.BC._
    为了把当前单元(04BA:0103)由 BCH 改成 42H,应输入 42:
    04BA:0100 EB.41 10.00.BC.42
    如果要退回并把 10H 改成 6FH,则按两次连字符和输入置换的字节之后,屏幕上显示:
    04BA:0100 EB.41 10.00.BC.42
    04BA:0102 00._
    04BA:0101 10.6F
    按 ENTER 键结束输入命令,将会看到提示符为连字符“—”。

5.内存填充指令F(Fill)

  • 用清单中的内容填充range范围内存
  • 形式: F range list
  • 说明:如果清单中包含的字节数小于地址范围,则重复地使用该清单,直到把所指定范围内的存储器单元填满为止。如果清单中包含的字节数大于地址范围,就忽略不计超过的部分。
  • 例如:
    F4BA:100 L 5 F3‘XYZ’8D
    用指定的 5 个字节填写到内存的 04BA:100 到 04BA:104 单元中。注意,存储清单字符是
    ASCII 字符码,因此 100—104 单元中为 F3 58 59 5A 8D。

6.执行命令G(Go)

  • 作用:执行正在调试的程序。当达到所指定的断点地址处时,就停止执行,并显示寄存器、标志位以及下一条要执行的指令。断点在Track部分。
  • 格式:G[=addr][断点1][断点2][断点n]…
  • 不指定=addr参数时,从CS:IP开始执行

7.十六进制运算指令H (Hexarithmetic)

  • 作用:先把两个十六进制的值相加,然后第一个值减去第二个值。在一行上显示和与差。

  • 格式:格式:H value value

    例如:
    H 0F 8
    17 07
    000F 和 0008 的 16 进制和是 0017,而其差是 0007

8.输入指令I(Input)

  • 从指定的端口输入并显示

  • 格式:I portnum

    例如:

    - I 2F8

    6B
    显示由 02F8 端口读入的一个十六进制字节数(6BH)。

9.载入指令L(load)

  • 作用:把制定的文件或绝对扇区装入内存。

  • 形式1:L [addr][driver][起始扇区][载入的扇区数量]

    例如:
    L 4BA:100 1 OF 6D
    从驱动器 B 的盘上装入数据,并把数据存放在以 4BA:100 开始的内存中。从相对扇区 0FH

    驱动器以 1 2 3等区分

  • 形式2:L 或者 L [addr] ;载入已经由N命令指定的文件。默认CS:100 文件需在当前文件夹下

    N file_test

    L ;载入到CS:100

    L CS:1000 ;载入到指定的内存位置 CS:1000

  • 说明:用单个 Load 命令可装入的最大扇区数是80H。如果出现读盘错,则 DEBUG 显示出错信息。

10.传送指令M(move)

  • 作用:复制指定内存块的内容到另一内存块

  • 形式:M range addr ;复制range的内容到addrrange内存块内容不变

    例如:
    M CS:100 110 500
    把 CS:100 到 CS:110 的 17 个字节的数据,传送到以 DS:500 开始的内存区中。

11.命名指令N(name)

  • 作用:为读写磁盘文件定义文件名
  • 格式:N [name1][name2….]
  • 说明:如果在无文件说明时启动 DEBUG,在用 L 命令装入文件之前,必须使用 Name 命令。

12.输出指令O(output)

  • 作用:向端口发送数据

  • 格式:O portNum byte

    例如:为了把字节值 4F 发送到输出端口 2F8,输入:
    O 2F8 4F

13.退出命令Q(quit)

  • 说明:Q 命令不保存内存中正工作的文件,需要时可用 Write 命令保存文件。

14.寄存器命令R(Register)

  • 用途:

    • 显示并修改一个寄存器的值
    • 显示全部寄存器、标志位、以及将被执行的下条指令。
    • 显示 8 个标志位状态,并带有修改它们之中任一个或全部的选择
  • 格式:R [regname]

    • 其一:显示单个寄存器
      有效寄存器是:AX、BX、CX、DX、SP、BP、SI、DI、DS、ES、SS、CS 和 IP。

    R AX
    系统显示如下:
    AX F1E4
    :_
    现在可以采用下列两个操作中的某一个:
    按 ENTER 键保留未修改的内容。
    输入 1—4 字符的十六进制值来修改 AX 寄存器的内容,例如 FFFH。
    AX F1F4
    :FFF_
    现在按ENTER键把AX寄存器内容改变成0FFFH。

    • 其二:显示所有的寄存器和标志位

    其二:显示所有的寄存器和标志位
    为了显示所有寄存器的内容和标志位(还有下条要执行的指令),输入:
    R
    则系统可能显示如下:
    AX=0E00 BX=00FF CX=0007 DX=01FF
    SP=039D BP=0000 SI=005C DI=0000
    DS=04BA ES=04BA SS=04BA CS=04BA
    IP=011A NV UP DI NG NZ AC PE NC
    04BA:01lA CD21 1NT 21
    头4行显示寄存器十六进制内容和8个标志位状态。最后一行指出下一条要执行的指令地址和它的16进制机器码以及反汇编形式,这是当前CS:IP指向的指令。

    • ③显示标志位有8个标志位,每位用2个字母表示是置“1”状态还是清除状态,详细说明见下表:
    标志位名称 Set(置位) clear(清除)
    溢出 OV NV
    方向(减、加) DN UP
    中断允许 DI DI
    负号(正负) NZ PL
    零(是否) ZR NZ
    辅助进位 AC NA
    奇偶 PE PO
    进位 CY NC

    为了显示所有的标志位,输入命令:
    R F
    如果所有标志位处于置1状态,就显示:
    OV DN EI NGZR AC PE CY

15.检索命令S(Search)

  • 作用:按照给出的内容在一定范围内检索

  • 形式:S range list

  • 说明:以显示被查找到的匹配字符所在的地址来指明全部的匹配。显示没有地址的提示符
    “—”,表示未找到任何匹配字符。

    例如:要想从 CS:100 到 CS:110 地址范围内检索 41H,那么输入:
    S CS:100 110 41
    如果找到两个匹配,则显示也许是:
    04BA:0104
    04BA:010D

16.跟踪命令T(Trace)

  • 用途:从 CS:IP 或者=address(如果指定的话)单元中的指令开始单步执行一条或多条指令。这里的=号必须输入。用 value 指定跟踪多条指令。每条指令执行后,显示所有寄存器的内容、标志位的状态以及下一条要执行的指令。
  • 形式: T [=addr][value]

例如,输入命令:
T
如果 IP 寄存器内容为 011A,而该地址指向的指令是 MOV AH,0EH,这可能显示:
AX=0E00 BX=00FF CX=0007 DX=01FF
SP=039D BP=0000 SI=005C D1=0000
DS=04BA ES=04BA SS=04BA CS=04BA
IP=011C NV UP DI NG NZ NC PE NC
04BA:01lC CD21 INT 21
这是执行 011A 中指令之后显示的结果,并且指出下条要执行的指令是 04BA:011C 单元中的
INT 21。

17.反汇编指令U(UNassemble)

  • 作用:把内存中的机器码转换成汇编语句,并显示指令的地址、机器码以及汇
    编语句
  • 形式:
    • U [range] , 用于反汇编不带指定地址的指令,或反汇编从指定地址开始的指令
    • U [addr] , 用于反汇编从addr开始的指令。反汇编多少由显示方式而定。用 40 列显示时,一次把 16 个字节反汇编;用 80 列显示时,一次把 32 个字节反汇编。,

18.文件转储指令W(Write)

  • 用途:把调试过的信息写到磁盘上。

  • 形式:

    • 1.从指定地址开始把信息写到绝对磁盘扇区上,W address drive sector sector
      从指定的开始相对扇区(第一个 sector)开始写数据,并且连续写,直到写完所要求的扇区数(第二个 sector)为止。这种方式以磁盘扇区的多少为限制,而不是内存内容的多少

    例如,命令:
    W 1FD 1 100 A
    把从 CS:01FD 单元开始的数据写到驱动器 B 的软盘中,由相对扇区 100H(256)开始连续写 0AH(10)个扇区。

    • 2.内存内容转储到文件。 W addr

    此时,写命令把文件写到磁盘上,把从CS:100由参数 address 指定的单元开始的文件按文件说明 filespec 写到磁盘上。此文件的文件说明被格式化在 CS:5C 文件控制块中。当启动 DEBUG 时指定文件说明,或者使用 N 命令,采用这两种方法都可满足这个条件。

    另外,必须把寄存器 BX 和 CX 置成被写的字节数目,它们可能已由 DEBUG 或 Load 命令设置过,也可能被修改过。必须确保 BX 和 CX 寄存器包含正确的值。 不确定对第一种方式是否是必须的

Debug注意事项

可能与之前那个有点重复。这个更详细。

DEBUG支持基本的8086/8088汇编语言语法,DEBUG下的汇编语言有下面一些特点和规则:
① 数值都是十六进制数,并且不加尾缀“H”。
② 不能使用符号常量和符号地址。
③ 不能使用绝大部分伪指令,但两个最常用的伪指令 DB 和 DW 能被使用,用于直接把字节和字数据置入相应存储单元。如:
DB 1,2,3,4,“ABCD”
DW 1234,5678
④ 可以使用属性操作符“PTR”对 DEBUG 不能明确类型的操作数进行说明。如:INC BYTE
PTR [BX]。
⑤ DEBUG 的 A 命令汇编程序能根据转移目标地址的距离自动地汇编出短、近或远的转移
或调用指令。当然,这也能由“SHORT”、“NEAR PTR”或”FAR PTR”对转移目标地址
进行说明来实现。
⑥ 远返回指令的助记符在 DEBUG 中为 RETF。
⑦ 指令前缀助记符必须在相关的指令之前输入,也可以分别放在不同的行。
⑧ 串操作指令只能用其字节型或字型的助记符形式,如:MOVSB、CMPSW 等。
⑨ 可以使用段超越前缀助记符 CS:、DS:、ES:和 SS:。如:
DS:
MOV AL,[BP]