日度归档:2011年3月27日

cmd对话框中Debug指令学习

cmd对话框中Debug指令学习
一、DEBUG的主要指令:

点击开始–>点运行–>在运行对话框中输入cmd–>在输入debug


1、显示存储单元的指令D(DUMP)格式为:_D或_D

例如按指定范围显示存储单元内容的方法为:
-d100 120
18E4:0100 c7 06 04 02 38 01 c7 06-06 02 00 02 c7 06 08 02 G…8.G…..G…
18E$:0110 02 02 bb 04 02 e8 02 00-CD 20 50 51 56 57 8B 37 ..;..h..M PQVW.7
18E4:0120 8B

其中0100至0120是DEBUG显示的单元内容,左边用十六进位表示每个位元群组,右边用ASCII字元表示每个位元群组,. 表示不可显示的字元。这里没有指定段位址,D指令自动显示DS段的内容。如果只指定首位址则显示从首位址开始的80个位元群组的内容。如果完全没有指定位址则显示上一个D指令显示的最后一个单元后的内容。


2、修改存储单元内容的指令有两种。

☆输入指令E(ENTER)有两种格式如下:
第一种格式可以用给定的内容表来替代指定范围的存储单元内容。指令格式为:
-E address
例如:-E DS:100 F3’XYZ’8D
其中F3,’X’,’Y’,’Z’和各占一个位元群组,该指令可以用这五个位元群组来替代存储单元DS:0100到0104的原先的內容。

第二种格式则是采用逐个单元相继修改的方法。指令格式为:
-E address
例如:-E DS:100
则可能显示为:
18E4:0100 89.-
如果需要把该单元的内容修改为78,则使用者可以直接键入78,再按”空格”键可接著显示下一個單元的內容,如下:
18E4:0100 89.78 1B.-
这样使用者可以不断修改相继单元的内容直到用ENTER键结束该指令为止。

☆填写指令F(FILL)其格式为:
-F range list
例如:-F 4BA:0100 5 F3’XYZ’8D
使04BA:0100~0104单元内含特殊的五个位元群组的内容。若果list中的位元群组数超过特殊的范围,则忽略超过的项;若果list的位元群组数小於特殊的范围,则重复使用list填入,直到填满特殊的所有单元為止。


3、检查和修改寄存器内容的指令R(register)它有三种格式如下:

☆显示CPU内所有寄存器内容和标志位状态其格式为:
-R
例如:-r
AX=0000 BX=0000 CX=010A DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=18E4 ES=18E4 SS=18E4 CS=18E4 IP=0100 NV UP DI PL NZ NA PO NC
18E4:0100 C70604023801 MOV WORD PTR [0204],0138 DS:0204=0000

☆显示和修改某个寄存器内容其格式为:
-R register name
例如:键入-R AX
系统将响应如下:
AX F1F4

即AX寄存器的目前内容为F1F4,如不修改则按ENTER键、否则可键入欲修改的内容,如:
-R bx
BX 0369
:059F
则把BX寄存器的内容修改为059F。

☆显示和修改标志位状态指令格式为:
-RF系统将响应,如:
OV DN EI NG ZR AC PE CY-
此时如不修改其内容可按ENTER键,否则可键入欲修改的内容如:
OV DN EI NG ZR AC PE CY-PONZDINV
即可,可见键入的顺序可以是任意的。


4、执行指令G其格式为:

-G[=address1][address2[address3…]]
其中位址1指定了执行的起始位址,如不指定则从目前的CS:IP开始执行。后面的位址均为断点位址,当指令执行到断点时,就停止执行并显示目前所有寄存器及标志位的内容,和下一笔将要执行的指令。


5、追踪指令T(Trace)有两种格式:

☆逐條指令追蹤:
-T [=address]
从指定位址起执行一条指令后停下来,显示所有寄存器内容及标志位的值。如未指定位址则从目前的CS:IP开始执行。

☆多条指令追踪:
-T [=address]
从指定位址起执行n条指令后停下来,n由value指定。


6、汇编指令A(Assemble)其格式为:

-A
该指令容许键入汇编语系语句,并能把它们汇编成机器代码,相继地存放在从指定位址开始的存储区中。必须注意:DEBUG把键入的数字均看成十六进位数,所以如要键入十进位数,则其后应加以说明,如100D。


7、反汇编指令U(Unassemble)有两种格式。

☆从指定位址开始反汇编32个位元群组其格式为:
-U
例如:
-u100
18E4:0100 C70604023801 MOV WORD PTR[0204],0138
18E4:0106 C70606020002 MOV WORD PTR[0206],0200
18E4:010C C70606020202 MOV WORD PTR[0208],0202
18E4:0112 BBO4O2 MOV BX,0204
18E4:0115 E80200 CALL 011A
18E4:0118 CD20 INT 20
18E4:011A 50 PUSH AX
18E4:011B 51 PUSH CX
18E4:011C 56 PUSH SI
18E4:011D 57 PUSH DI
18E4:011E 8B37 MOV SI,
若果位址被省略,则从上一个U指令的最后一条指令的下一个单元开始显示32个位元群组。

☆对指定范围内的存储单元进行反汇编,格式为:
-U
例如:
-u100 10c
18E4:0100 C70604023801 MOV WORD PTR[0204],0138
18E4:0106 C70606020002 MOV WORD PTR[0206],0200
18E4:010C C70606020202 MOV WORD PTR[0208],0202

-u100 112
18E4:0100 C70604023801 MOV WORD PTR[0204],0138
18E4:0106 C70606020002 MOV WORD PTR[0206],0200
18E4:010C C70606020202 MOV WORD PTR[0208],0202
可见这两种格式是等效的。


8、命名指令N(Name)其格式为:

-N filespecs
指令把两个档案标识符格式化在CS:5CH和CS:6CH的两个档案控制块中以便在其后用L或W指令把档案装入存盘。filespecs的格式可以是:
[d:] filename[.ext]
例如:
-N myprog
-L
可把档案myprog装入存储器。


9、装入指令(Load)有两种功能。

☆把磁碟上指定扇区范围的内容装入到存储器从指定位址开始的区域中。其格式为:
-L[address[drive sector sector]

☆装入指定档案其格式为:
-L
此指令装入已在CS:5CH中格式化了档案控制块所特殊的档案。如未指定位址则装入
CS:0100开始的存储区中。


10、写指令W(Write)有两种功能。

☆把资料写入磁碟的指定扇区。其格式为:
-W address drive sector sector
☆把资料写入特殊的档案中。其格式为:
-W
此指令把特殊的存储区中的资料写入由CS:5CH处的档案控制块所特殊的档案中。如未指定位址则资料从CS:0100开始。要写入档案的位元群组数应先放入BX和CX中。


11、离开DEBUG指令Q(Quit)其格式为:
-Q
它离开DEBUG、返回DOS。本指令并无存盘功能,如需存盘应先使用W指令。

==========================================================================
问题:初学者问一个低级问题,执行debug-a后如果有一行输入错误,如何变更这一行?

回答:加入进行如下输入

D:\PWIN95\Desktop>debug
-a
2129:0100movax,200
2129:0103movbx,200
2129:0106movcx,200
2129:0109

此时发现movbx,200一句错误,应为movbx,20可以敲Enter返回”-“状态然后输入:
-a103
2129:0103movbx,20
如果是多或是少若干行不必重新输入、可以用M指令移动后面的程式来去掉或是增加程式空間。


问题:如何除错和汇编你的第一个PC x86汇编语系程式呢?

回答:以下这些简单的解释可以让一个汇编语系新手使用DEBUG

00) 在使用时如何快速获得debug的使用帮助呢?
01) 让我们开始工作吧例如:显示BIOS的日期。
02) 在你的电脑的COMMANG.COM档案里搜寻”IBM”这几个字元。
03) 一位十六进位数的运算。
04) 检查x86寄存器内容。
05) 我们来编写我们的第一个用机械语系编写的程式-列印一个字元。
06) 我们现在用汇编语系指令来做和例5一样的事情。
07) 现在,我们不但要编写一个汇写程式式,而且我们还要把它存盘。
08) 现在,我们试一试检视一个已经编好的程式。
09) 你可以用DEBUG的计算功能计算程式的长度。
10) 另一种显示在萤幕上字串的方法。
11) 让我们试一试反覆输出。
12) 我们现在把两个程式连线起来。
13) 让我们逐步执行这个刚刚修补的程式。
14) 如果一开始的指令不是跳转指令那麼可能就要用这种方法了。

以下所有的指令都是可以执行在WIN98/ME/2000/XP/2003的MS-DOS或CMD模式下的。进入MS-DOS或CMD的模式有:

[开始][程式][MS-DOS模式]
[开始][运行][开启]CMD[确定]
或是你可以按两下它:
C:WindowsCommand.com


00) 在使用时,如何快速获得debug的使用帮助呢?

以下PROMPT>表示目录提示符:一般为:C:WINDOWSCOMMAND

PROMPT> DEBUG /?<按Enterpress the enter key now>
怎样?出错了吧。显示如下:
C:WINDOWS>DEBUG/?
Runs Debug, a program testing and editing tool.
DEBUG [[drive:]filename [testfile-parameters]]
[drive:]filename Specifies the file you want to test.
testfile-parameters Specifies command-line information required by
the file you want to test.
After Debug starts, type ? to display a list of debugging commands.
因为错了所以它给你显示一些提示。留意到最后一句了吗?

现在我们再来试一试:

PROMPT> DEBUG<按Enter> (注意, DEBUG程式的指令是在一条横线”-“后出现的。)-?<在出现的横线后面输入?再Enter>(下面的内容是按字母顺序排序的)(注意:Note: Don’t type the dash or comments — just the ?)

显示如下但是没有中文的哦中文是我加上去的:
汇编assemble A
比较compare C range address
倾倒dump D
进入enter E address
填充fill F range list
进行go G [=address]
十六进位hex H value1 value2
输入input I port
装载load L
移动move M range address
命名name N
输出output O port byte
进行proceed P [=address]
离开quit Q
纪录register R
搜寻search S range list
描述trace T [=address]
反汇编unassemble U
寫write W
分配延伸记忆体allocate expanded memory XA [#pages]
释放延伸记忆体deallocate expanded memory XD
map expanded memory pages XM
display expanded memory status XS
-q<按Enter> (这是离开DEBUG回到DOS状态This quits out of debug, returning to the DOS prompt)

(Tested examples below walk the user thru the following debug examples:在下面的例子里读者必须明白以下几条DEBUG指令。)

-D 显示一定范围记忆体的内容Display the contents of an area of memory
-Q 离开DEBUG程式Quit the debug program
-S 搜寻Search for whatever
-H 十六进位的运算Hex arithmatic
-R 显示或是改变一个或是多个寄存器的内容Display or change the contents of one or more registers
-E 输入资料进入记忆体,在一个详细的位址里Enter data into memory, beginning at a specific location
-G 执行现在在记忆体里的程式。Go run the executable program in memory
-U 反汇编,把我们不认识的机械代码变为我们可以认识汇编语系符号Unassemble machine code into symbolic code
-T 描述一條指令的用法。Trace the contents of one instruction
-P 进行或是执行一个关联的指令Proceed, or execute a set of related instructions
-A 编译,把汇编指令变为机械代码Assemble symbolic instructions into machine code
-N 命名一個程式Name a program
-W 把一个已经命名的程式写进磁碟Write the named program onto disk
-L 把程式装载进记忆体Load the named program back into memory


01) 让我们开始工作吧例如:显示BIOS的日期。

(以下PROMPT>表示目录提示符:一般为C:WINDOWSCOMMAND)
PROMPT> DEBUG<按Enter>
-D FFFF:0006 L 8<按Enter>(显示 FFFFh, 偏移位址 6h, 长度 8 bytes)
在小弟的电脑上这里显示为 “1/10/96.”译者的电脑显示” FFFF:0000 37 2F-30 36 2F 30 30 00 7/06/00.”相信小弟的电脑里也是用这种格式显示的。这里显示出来的是使用者BIOS的日期,有兴趣的话可以重新开机看看,注意开机时的显示。
-Q<按Enter> (离开DEBUG)
思考:当只按DEBUG的时候,编辑的是什麼?为什麼可以找到BIOS的日期?(译者认为可能是记忆体的真实物理位址。)


02) 在你的电脑的COMMANG.COM档案里搜寻”IBM”这几个字元。

下面的”C:Win95″是根据每不电脑不同的。像译者的电脑里就是”C:WINDOWS”
PROMPT> DEBUG C:Win95Command.com<按Enter>
-S 0 L FFFF “IBM”<按Enter>(从0开始搜寻”IBM”,搜寻FFFFh多个单元格)
-Q<按Enter> (离开DEBUG)

以下是译者做的:

C:WINDOWS>DEBUG C:WINDOWSCOMMAND.COM
-S 0 L FFFF “IBM”
-S 0 L FFFF “COMMAND”
12A7:008D
12A7:04F7
12A7:3870
12A7:38BE
12A7:38DD
-S 0 L FFFF “PATH”
12A7:38AD
12A7:CCB7
12A7:CF55
-S 0 L FFFF “COMSPEC”
12A7:38D4
12A7:3A4D
12A7:CCC4
-Q
C:WINDOWS>

(注意:搜寻是要区分大小写的)
(你可以看到上面是没有找到”IBM”的, 可以试一试”PATH” , “COMSPEC” , “COMMAND”)
(注意: 这种方法用在寻找加密资料和已被移除的资料等方面时是十分有用的)


03) 一位十六进位数的运算:

PROMPT> DEBUG<按Enter>
-H 9 1<按Enter> (加减两个十六进位的数,9h+1h=Ah & 9h-1h=8h)
结果是显示: 000A 0008
-Q<按Enter>(离开DEBUG)
C:WINDOWS>debug
-h 9 1
000A 0008
-q
C:WINDOWS>


04) 检查x86寄存器内容。

PROMPT> DEBUG<按Enter>
-R<按Enter>(显示x86寄存器内容)
-Q<按Enter>(离开DEBUG)
C:WINDOWS>debug
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC
127C:0100 043C ADD AL,3C
-Q

下面是对寄存器的简单介绍:

资料存储器:
在本类中,一般讲的AH就是AX的前八位,AL就是AX的后八位,后面的以此类推。AX Accumulator;作为累加器,所以它是算术运算的主要寄存器。另外所有的I/O指令都使用这一寄存器与外部装置传输讯息。BX Base register;可以作为通用寄存器使用,此外在计算存储器位址时,它经常用作基位址寄存器。CX Counting register;可以作为通用寄存器使用,此外在循环(LOOP)和串处理指令中作隐含的计数器。DX Data register;可以作为通用寄存器使用,一般在作双字长运算时,把DX和AX群群组合在一起存放一个双字长数,DX用来存放高位字。此外,对某些I/O动作,DX可用来存放I/O的连线埠位址。

指标及变址寄存器:
BP Base pointers register ;机制指标寄存器。
SI Source index register ;堆栈指标寄存器。
DI Destiny index register ;目的变址寄存器。
SP Battery pointer register ;堆栈指标寄存器。

段寄存器:
CS Code segment register ;代码段寄存器,存放正在执行的程式指令。
DS Data segment register ;资料段寄存器,存放目前执行程式所用的资料。
SS Battery segment register ;堆栈段寄存器,定义了堆栈所在区域。
ES Extra segment register ;附加段寄存器,存放附加的资料是一个辅助性的资料区,控制寄存器。
IP Next instruction pointer register;指令指标寄存器,它用来存放代码段中的偏移位址,在程式执行的过程中,它始终指向下一笔指令的首位址,它与CS寄存器联用确定下一笔指令的物理位址。
F Flag register;标志寄存器 “NV UP EI PL NZ NA PO NC”就是了,也有人称之为PSW Program Status Wold程式状态寄存器 。

这里有一点必须讲明白的现在在,其实从奔腾开始这些寄存器(除了所有段寄存器,标志寄存器)都是32位的。并且加多了两个16位段寄存器FS,GS。dos下面看到这些寄存器是16位的。要看32位寄存器可以使用soft-ice。对於FS,GS的作用我也不是很清楚,希望有高手指点,谢谢。)


05) 我们来编写我们的第一个用机械语系编写的程式-列印一个字元。

(这里用机械语系的主要原因是考虑到有一些使用者不懂汇编指令,现在就要让他有一个认识电脑程式实质是一些数字)

PROMPT> DEBUG<按Enter>
-E 100<按Enter> (在偏移位址為100的地方輸入機械指令程式)
B4<按空格>02<按空格> (在AX寄存器的前八位存入02)
B2<按空格>41<按空格> (在DX寄存器的后八位存入41h,41h就是大写A的ASCII码,身边有ASCII表的朋友可以对著表改改数字试一试)
CD<按空格>21<按空格> (当AH=02时这是DOS显示输出的中断号)
CD<按空格>20<按Enter> (离开DOS)
-G<按Enter> (程式执行,并在萤幕上显示出”A”)
程式执行完以后你将看到”Program terminated normally”(程式标准结束了).
-U 100<按Enter> (我们把它反汇编,就是把机械指令变为汇编语系指令)

107F:0100 B402 MOV AH,02
:0102 B2 MOV DL,41
:0104 CD21 INT 21
:0106 CD20 INT 20
(下面会有一堆无用的东西)
(对了你的段位址可能与我的段位址CS=107F不同哦)

-R<按Enter>(让我们来看看寄存器的值; IP==100h, AX==0000h, DX==0000h)
好极了我们看到电脑又做好了准备下一次执行程式了。
-T<按Enter>(执行第一步动作… IP=>102h, AX=>0200h,指令指标寄存器指向下一笔指令,AX的值被改变。)
-T<按Enter>(执行第二步动作… IP=>104h, , DX=>0041h,指令指标寄存器指向下一笔指令,DX的值被改变。)
-P<按Enter>(继续执行 INT 21,IP=>106h, AX=>02h,)
-P<按Enter>(继续执行INT 20)
-Q<按Enter>(离开DEBUG)

(注意:你必须小心使用”T”.因为若果你在程式完结以后继续执行这条指令,因为我们无法知下面的指令是什麼,所以我们也无法预知它可能带来的后果)

C:WINDOWS>DEBUG
-E 100
127C:0100 B4.B4 02.02 B2.B2 41.41 CD.CD 21.21 CD.CD 20.20
-G
A
Program terminated normally
-U 100
127C:0100 B402 MOV AH,02
127C:0102 B241 MOV DL,41
127C:0104 CD21 INT 21
127C:0106 CD20 INT 20
127C:0108 C706F1E30900 MOV WORD PTR [E3F1],0009
127C:010E EB59 JMP 0169
127C:0110 57 PUSH DI
127C:0111 BFF1E3 MOV DI,E3F1
127C:0114 8BDF MOV BX,DI
127C:0116 06 PUSH ES
127C:0117 0E PUSH CS
127C:0118 07 POP ES
127C:0119 32D2 XOR DL,DL
127C:011B EB34 JMP 0151
127C:011D 006B12 ADD [BP+DI+12],CH
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC
127C:0100 B402 MOV AH,02
-T
AX=0200 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0102 NV UP EI PL NZ NA PO NC
127C:0102 B241 MOV DL,41
-T
AX=0200 BX=0000 CX=0000 DX=0041 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0104 NV UP EI PL NZ NA PO NC
127C:0104 CD21 INT 21
-P
A
AX=0241 BX=0000 CX=0000 DX=0041 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0106 NV UP EI PL NZ NA PO NC
127C:0106 CD20 INT 20
-P
Program terminated normally
-Q
C:WINDOWS>


06) 我们现在用汇编语系指令来做和例5一样的事情。

PROMPT>DEBUG<按Enter>
-A 100<按Enter>(在偏移位址为100的地方输入汇编语系程式)
MOV AH,02<按Enter>(选用DOS的02号功能呼叫,显示输出)
MOV DL,<按Enter>(在DX寄存器的后八位存入41h,41h就是大写A的ASCII码,身边有ASCII表的朋友可以对著表改改数字试一试)
INT 21<按Enter>(当AH=02时这是DOS显示输出的中断号,显示”A”)
INT 20<按Enter>(离开DOS)
<按Enter>(结束汇编语系写程式状态,回到DEBUG指令状态)
-G =100<按Enter>(执行程式,其实可以不要”=100″因为一般预设启始位置是100)
-Q<按Enter>(离开DEBUG)

C:WINDOWS>DEBUG
-A 100
127C:0100 MOV AH,02
127C:0102 MOV DL,41
127C:0104 INT 21
127C:0106 INT 20
127C:0108
-G
A
Program terminated normally
-Q
07) 现在我们不但要编写一个汇写程式式而且我们还要把它存盘。

(下面这个程式就要比原来的程式复杂一点了-显示输出:”ABC”)

PROMPT> DEBUG<按Enter>(执行DEBUG程式;系统预设启始IP寄存器值为100h)
-A 100<按Enter>(用汇编语系编写一个程式,启始位址是100h)
MOV AH,02<按Enter>(选取DOS的02号功能呼叫, 显示输出)
MOV DL,<按Enter>(在DX寄存器的后八位存入41h,41h就是大写A的ASCII码)
INT 21<按Enter>(当AH=02时这是DOS显示输出的中断号,显示”A”)
MOV DL,42<按Enter>(在DX寄存器的后八位存入41h,41h就是大写B的ASCII码)
INT 21<按Enter>(当AH=02时这是DOS显示输出的中断号,显示”B”)
MOV DL,43<按Enter>(在DX寄存器的后八位存入41h,41h就是大写C的ASCII码)
INT 21<按Enter>(当AH=02时这是DOS显示输出的中断号,显示”C”)
INT 20<按Enter>(程式结束,离开DEBUG)
<按Enter>(结束汇编指令输入,回到DEBUG指令输入)
-R BX<按Enter>(检视寄存器BX的值)
:0000<按Enter>(设定BX为0000h,这是程式的结尾位址是BX:CX)
(注意,只要BX = 0000, 档案的大小就小於 < 64 Kb.)
-R CX<按Enter>(设定CX为Fh,这是程式的长度:16位)
:0010<按Enter>(现在我们可以把这个16位元群组的程式写入硬碟了)
-N printabc.com<按Enter>(将要存盘的程式命名)
-W<按Enter>(把这十六位元群组写到档案里面)
-Q<按Enter>(离开DEBUG)
PROMPT> DIR printabc.com<按Enter>
这里将会报告这个档案的大小是16位元群组(10h 位元群组)
PROMPT> printabc.com<按Enter>
会马上在萤幕上列印出”ABC”

C:WINDOWS>DEBUG
-A 100
127C:0100 MOV AH,02
127C:0102 MOV DL,41
127C:0104 INT 21
127C:0106 MOV DL,42
127C:0108 INT 21
127C:010A MOV DL,43
127C:010C INT 21
127C:010E INT 20
127C:0110
-R
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC
127C:0100 B402 MOV AH,02
-R BX
BX 0000
:
-R CX
CX 0000
:0010
-N PRINTABC.COM
-W
Writing 00010 bytes
-Q
C:WINDOWS>DIR PRINTABC.COM
Volume in drive C has no label
Volume Serial Number is 28FB-70BA
Directory of C:WINDOWS
PRINTABC COM 16 03-21-01 11:02 PRINTABC.COM
1 file(s) 16 bytes
0 dir(s) 557,711,360 bytes free
C:WINDOWS>PRINTABC
ABC
C:WINDOWS>

这里可以有人告诉我为什麼要存入是BX:CX代表程式长度吗?


08) 现在我们试一试检视一个已经编好的程式:

PROMPT> DEBUG<按Enter>(执行DEBUG程式在CS:IP = CS:0100h)
-N printabc.com<按Enter>(告诉电脑你想装载的程式名)
-L<按Enter>(装载那个名字的程式进入记忆体)
-U 100 L 10<按Enter>(从偏移位址100开始反汇编16位位元群组)
-R<按Enter>(现在看看寄存器里面的内容)
注意:DEBUG本身是没有自动纪录档案大小的。
-G (执行被命名的程式,列印”ABC”)
(你将看到”ABC”,然后是”Program terminated normally”)

C:WINDOWS>DEBUG
-N PRINTABC.COM
-L
-U 100 L 10
12A4:0100 B402 MOV AH,02
12A4:0102 B241 MOV DL,41
12A4:0104 CD21 INT 21
12A4:0106 B242 MOV DL,42
12A4:0108 CD21 INT 21
12A4:010A B243 MOV DL,43
12A4:010C CD21 INT 21
12A4:010E CD20 INT 20
-R
AX=0000 BX=0000 CX=0010 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=12A4 ES=12A4 SS=12A4 CS=12A4 IP=0100 NV UP EI PL NZ NA PO NC
12A4:0100 B402 MOV AH,02
-G
ABC
Program terminated normally


09)你可以用DEBUG的计算功能计算程式的长度。

一开始的时候你的程式起始位址是在0100h:
107F:0100 MOV AH,02 <—–这就是 100h
你的程式的最后一行在010Eh:
107F:010E INT 20 <–最后一行
然后,最后一条指令的下一行的位址是0110h:
107F:0110 <–這就是110h
所以,从0110h里减去100h我们得到得长度是10h 位元群组.
PROMPT> DEBUG<按Enter>
-H 110 100<按Enter>(这条指令将运算110h+100h和110h-100h)
0210 0010<按Enter>(汇报 110h-100h=0010h; 16-byte 程式长度16位)
-Q<按Enter>(离开DEBUG)
C:WINDOWS>debug
-H 110 100
0210 0010
-Q
10)另一种显示在萤幕上字串的方法。

注意:在你输入资料的时候,按”-“键将会可以让你回退一格。

PROMPT> DEBUG<按Enter>
-E 200<按Enter> (从偏移位址200开始。输入”Hello,World”)
48<按空格>65<按空格> (输入48h (H)和65h (e))
6C<按空格>6C<按空格> (输入6Ch (l)和6Ch (l))
6F<按空格>2C<按空格> (输入6Fh (o)和2Ch (,))
57<按空格>6F<按空格> (输入57h (W)和6Fh (o))
72<按空格>6C<按空格> (输入72h ?和6Ch (l))
64<按空格>24<按空格> (输入64h (d)和24h ($))
<按Enter> (“Hello,World” 已经输入完毕)
-D 200<按Enter> (显示你刚刚输入的内容:
48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 … HELLO,WORLD$…)
-A 100<按Enter> (用汇编语系写一个新程式在IP-100h处开始)
MOV AH,09<按Enter> (选取DOS的09号功能呼叫,显示字串)
MOV DX,0200<按Enter> (把输出位址(200h),放进寄存器)
INT 21<按Enter> (执行DOS功能呼叫,显示”Hello,World”)
INT 20<按Enter> (离开程式回到DOS状态)
<按Enter> (结束汇编语系输入,回到DEBUG输入状态)
-G<按Enter> (从 CS:IP开始执行程式, 就是从107F:0100h开始执行程式)
现在我们可以把这个程式储存进一硬盘:
-D 100<按Enter> (纪录:程式的起始点在100h)
-D 200<按Enter> (纪录:程式资料单元的结束点是在020Bh)
-H 20B 100<按Enter> (运算 20Bh-100h=10Bh;程式長度267位元群組)
-R BX<按Enter> (检查BX寄存器的值)
:0000<按Enter> (设定BX为0000h,程式的长度是BX:CX,实际上你可以把BX和CX写到一起,即实际长度为:0000010Bh,这样些的目的是使你可以计算更大的程式的长度)
-R CX<按Enter> (设定CX 为010Bh, 这就是这个程式的长度了)
:010B<按Enter> (现在你可以把这个108位元群组的程式写入硬碟了)
-N printhw.com<按Enter> (将要写入硬碟的程式命名)
-W<按Enter> (把这10Bh 即267个位元群组写入档案)
-Q<按Enter> (离开DEBUG)
PROMPT> DIR printhw.com<按Enter>
将会汇报程式的长度是267位元群组(10Bh位元群組)。
PROMPT> printhw.com<按Enter>
执行这个程式这将会在萤幕上显示出”Hello,World”:

C:WINDOWS>DEBUG
-E 200
127C:0200 2C.48 D5.65 BA.6C FF.6C FF.6F B8.2C 00.57 AE.6F
127C:0208 CD.72 2F.6C 3C.64 00.24 C3.
-D 200
127C:0200 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 C3 A0 ED E3 Hello,World$
127C:0210 0A C0 74 09 56 57 E8 84-21 5F 5E 73 0A B9 04 01 ..t.VW..!_^s
127C:0220 FC 56 57 F3 A4 5F 5E C3-50 56 33 C9 33 DB AC E8 .VW.._^.PV3.
127C:0230 C3 23 74 19 3C 0D 74 15-F6 C7 20 75 06 3A 06 1E .#t.<.t… u
127C:0240 D4 74 0A 41 3C 22 75 E6-80 F7 20 EB E1 5E 58 C3 .t.A<“u… .
127C:0250 A1 F3 D8 8B 36 F5 D8 C6-06 37 DA 00 C6 06 33 DA ….6….7..
127C:0260 00 8B 36 F5 D8 8B 0E F3-D8 8B D6 E3 42 51 56 5B ..6………
127C:0270 2B DE 59 03 CB 8B D6 C6-06 D7 DC 00 E3 31 49 AC +.Y………
-A 100
127C:0100 MOV AH,09
127C:0102 MOV DX,0200
127C:0105 INT 21
127C:0107 INT 20
127C:0109
-G
Hello,World
Program terminated normally
-D200
127C:0200 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 C3 A0 ED E3 Hello,World$
127C:0210 0A C0 74 09 56 57 E8 84-21 5F 5E 73 0A B9 04 01 ..t.VW..!_^s
127C:0220 FC 56 57 F3 A4 5F 5E C3-50 56 33 C9 33 DB AC E8 .VW.._^.PV3.
127C:0230 C3 23 74 19 3C 0D 74 15-F6 C7 20 75 06 3A 06 1E .#t.<.t… u
127C:0240 D4 74 0A 41 3C 22 75 E6-80 F7 20 EB E1 5E 58 C3 .t.A<“u… .
127C:0250 A1 F3 D8 8B 36 F5 D8 C6-06 37 DA 00 C6 06 33 DA ….6….7..
27C:0260 00 8B 36 F5 D8 8B 0E F3-D8 8B D6 E3 42 51 56 5B ..6………
127C:0270 2B DE 59 03 CB 8B D6 C6-06 D7 DC 00 E3 31 49 AC +.Y………
-H 20B 100
030B 010B
-R BX
BX 0000
:
-R CX
CX 0000
:010B
-N PRINTHW.COM
-W
Writing 0010B bytes
-Q

C:WINDOWS>DIR PRINTHW.COM
Volume in drive C has no label
Volume Serial Number is 28FB-70BA
Directory of C:WINDOWS
PRINTHW COM 267 03-22-01 11:53 PRINTHW.COM
1 file(s) 267 bytes
0 dir(s) 555,089,920 bytes free

11)让我们试一试反覆输出:

PROMPT> DEBUG<按Enter>
-A 100<按Enter> (用汇编语系写一个新的程式,起始位址是100h)
JMP 125<按Enter> (从102h接前往125h)
<按Enter> (结束输入汇编指令。译者注:这里是为了例12做准备)
-E 102 ‘Hello World’ 0d 0a ‘$'<按Enter> (把字串输入记忆体)
-A 125<按Enter> (从125h开始继续编写我们的汇编语系程式)
MOV DX,0102<按Enter> (把字串的首位址(102h)放入DX寄存器)
MOV CX,0005<按Enter> (指定这条指令将被显示5次)
MOV AH,09<按Enter> (选取DOS的09号功能呼叫, 显示字串)
INT 21<按Enter> (执行DOS的功能呼叫, 显示”Hello, World”)
DEC CX<按Enter> (每次执行到这里CX都减去1)
JCXZ 0134<按Enter> (如果计数器CX=0,那麼前往位址0134h)
JMP 012D<按Enter> (其他情况下,即CX≠O时前往012Dh)
INT 20<按Enter> (程式离开DOS状态)
<按Enter> (结束汇编语系程式输入,回到DEBUG)
-U 100<按Enter> (从位址100h 开始反汇编)
-U<按Enter> (继续执行反汇编指令,直至你看到INT 20)
-H 0136 100<按Enter> (运算程式长度为36h)
-U 100 L 36<按Enter> (从100h反汇编到136h ,来确认你的计算)
-R BX<按Enter> (检视寄存器BX的值)
:0000<按Enter> (设定BX为0000h)
-R CX<按Enter> (把CX 设定为36h, 这就是程式长度36位元群组)
:0036<按Enter> (现在你可以把这36位元群组写入档案了)
-N printhw5.com<按Enter> (命名我,我们要写入的档案名)
-W<按Enter> (把这36位元群组的内容写进新档案)
-G<按Enter> (执行程式,在萤幕上显示”Hello-World “)
-Q<按Enter> (离开DEBUG)
PROMPT> DIR printhw5.com<按Enter>
将会汇报档案大小为54位元群组,换算为十六进位就是36h位元群组
PROMPT> printhw5.com<按Enter>
将在萤幕上显示五次”Hello World”。


12)我们现在把两个程式连线起来。

我们现在把printhw.com做为修补程式写进printhw5.com,新版本的printhw5将先执行原来的printhw.com再执行原来的printhw5.com。

PROMPT> COPY printhw5.com printhw5.bak<按Enter>
首先,备份printhw5.com,以后可以用於比较
PROMPT> DIR printhw5.com<按Enter>
现在,检视到得仍然是以前的54位元群组(36h 位元群組)
PROMPT> DEBUG printhw5.com<按Enter>
-R<按Enter> (现在检视仍然是BX:CX=0000 0036h bytes)
-U 100<按Enter> (检视到最後的是 EB 23 (JMP 0125))
-H 100 36<按Enter> (最後的指令是在 100h+36h=136h)
-H 136 1<按Enter> (下一个可用的存储器位置是136h+1h=137h)

现在你拥有足够的资料去修补那个程式

-E 110<按Enter> (把”Hello,World”输入记忆体)
48<按空格>65<按空格> (输入48h (H)和65h (e))
6C<按空格>6C<按空格> (输入6Ch (l)和6Ch (l))
6F<按空格>2C<按空格> (输入6Fh (o)和2Ch (,))
57<按空格>6F<按空格> (输入57h (W)和6Fh (o))
72<按空格>6C<按空格> (输入72h ?和6Ch (l))
64<按空格>24<按空格> (输入64h (d)和24h ($))
<按Enter> (停止输入”Hello,World”)
-D 110<按Enter> (顯示更才输入记忆体的資料:
48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 …HELLO,WORLD$…)
-A 100<按Enter> (在IP位址的(100h)开始夺取原来的程式的控制权,原来这里是”JMP 125″)
JMP 137<按Enter> (代替原来执行的程式首先执行我们现在的修补程式)
<按Enter> (结束汇编指令输入,回到DEBUG指令输入)
-A 137<按Enter> (在下面的可用通奸编译这个修补程式)
MOV AH,09<按Enter> (选取DOS的09号功能呼叫,显示输出)
MOV DX,110<按Enter> (把我们要输出的字段的首位址(110h)给DX寄存器)
INT 21<按Enter> (执行DOS 的功能呼叫,显示”Hello,World”)
JMP 0125<按Enter> (这里用跳转到原程式来代替离开到DOS指令(INT 20))
<按Enter> (结束汇编指令输入,回到DEBUG指令输入)
-U 125<按Enter> (确认一下源程式没有被我们误改了,如果误改了就马上离开DEBUG重新來過)
-U 100 L 1<按Enter> (确认已经使程式跳转到我们的修补程式位址137h)
-D 110 L C<按Enter> (确认资料区已经有了我们想要的资料)
-U 137<按Enter> (确认我们的新程式已经输入了)

现在我们可以把这个小程式存入硬碟了:
(注意:在现在整个程式的最后一条指令”JMP 0125″ 的后面一条的位址是0140h)

-H 0140h 100<按Enter> (計算140h-100h=40h; 答案是我们现在有一个长度为64位元群组的小程式)
-RBX<按Enter> (检查BX寄存器的值是否为”0″)
:<按Enter> (如果BX是0000h那麼就不需要改动啦)
-RCX<按Enter> (要把CX改为40h。这是我们的程式的长度)
:40<按Enter> (现在你可以把这0000:0040h个位元群组的小程式放入硬碟啦)
-W<按Enter> (覆盖我们的原程式)
-G<按Enter> (尝试执行我们的新程式)
-Q<按Enter> (离开DEBUG回到DOS)
PROMPT> DIR printhw5.com<按Enter>
现在你再看就发现文章大小不再是54位元群组, 变成了64位元群组.
PROMPT> printhw5.com<按Enter>
现在是首先在萤幕上列印”Hello,World”一次,然后再列印”Hello,World”5 次(注:这里其实可以在写程式的时候换一换内容试一试。)


13) 让我们逐步执行这个刚刚修补的程式:

PROMPT> DEBUG printhw5.com<按Enter>
-R<按Enter> (第1步:位址0100h内容是 EB35 “JMP 0137”)
-T<按Enter> (第2步:位址0137h内容是B409 “MOV AH,09”)
-T<按Enter> (第3步:位址0139h内容是BA1001 “MOV DX,0110”)
-T<按Enter> (第4步:位址0139h内容是CD21 “INT 21”)
-P<按Enter> (执行第5:”Hello,World”位址013Eh內容是EBE5 “JMP 0125”)
-T<按Enter> (到这里控制权已经回到了原程式)

如果你想的话你可以一步一步的执行完全部程式;方法就是一直按”T”直至到达下一个功能呼叫执行完成后。到那时按一个”P”就可以继续按”T”。

14)如果一开始的指令不是跳转指令,那麼可能就要用这种方法了:

例如:如果我们想叫程式printhw先列印”ABC”,就要取得控制权了。然后列印”ABC”的程式把控制权给回原来的printhw。在这个事例里printhw在100h的位址有两位元群组的程式;不能像上面那样简单的替代(一個JMP代替另一個JMP)就完事。解决办法就是使用NOP指令。

PROMPT> DIR printhw.com<按Enter>
将汇报程式的长度为267位元群组(10Bh 位元群組).
PROMPT> DEBUG printhw.com<按Enter>
-R<按Enter> (IP=100h 並且printhw’s 的档案大小=BX:CX=0000:010Bh)
-U 100<按Enter> (第一条指令B4 09 (MOV AH,09)是两个位元群组的)
(第二条指令是三个位元群组的 BA 00 02 (MOV DX,0200))
-H 100 10B<按Enter> (最后一条printhw的指令是在100h+10Bh=20Bh)
(DOS的INT 21功能呼叫是在105h开始的)

现在你有足够的资料输入你的程式了!

-A 100<按Enter> (要在printhw 的IP开始位置就夺取程式的控制权)
JMP 20B<按Enter> (前往20Bh增加一个程式)
NOP<按Enter> (用空指令填充直至你去到下一笔完整的指令)
NOP<按Enter> (你可以用它来覆盖你不想只执行的原程式指令 ,而不改变原来的位址。但是在这里我们只需要两个NOP)
注:为了使大家更加明白所以我将各条指令对应的机械指令的长度写在下面

B409 MOV AH,09
BA0002 MOV DX,0200
E90301 JMP 020B
90 NOP

这样我们就很清楚的看到JMP 020B的长度比MOV AH,09多了1个位元群组,但MOV DX,0200是3个位元群组,而NOP是空指令,是不执行任何动作的,它只是占1个位元群组。所以我们现在把前两条指令用一个JMP 020B和两个NOP代替。后面再加上去。

<按Enter> (结束汇编指令回到DEBUG指令输入)
-U 100<按Enter> (看一看前面我们做了些什麼)
(注意DOS INT 21中断任然是在 IP=105h的地方开始)
-A 20B<按Enter> (现在把我们的原程式写在后面)
MOV AH,02<按Enter> (选取DOS 的 2号功能呼叫, 字元显示输出)
MOV DL,41<按Enter> (在DL寄存器存入”A”的ASCII码41h)
INT 21<按Enter> (执行DOS 的功能呼叫,显示字元”A”)
MOV DL,42<按Enter> (在DL寄存器存入”B”的ASCII码42h)
INT 21<按Enter> (执行DOS 的功能呼叫,显示字元”B”)
MOV DL,43<按Enter> (在DL寄存器存入”C”的ASCII码43h)
INT 21<按Enter> (执行DOS 的功能呼叫,显示字元”C”)
MOV AH,09<按Enter> (现在重新输入原来在100h的程式指令)
MOV DX,0200<按Enter> (现在要打扫寄存器了,复原原来的200h的值)
JMP 105<按Enter> (前往INT 21指令的位置105h)
<按Enter> (请注意一下你这里最后的位址是0221h)
-H 221 100<按Enter> (计算221h-100h=121h 就是289位元群组的程式)
-R CX<按Enter> (把CX的值设为121h, 这就设定了程式的新长度)
:0121<按Enter> (现在用121h (也就是289位元群组)覆盖原值)
-W<按Enter> (把这289个位元群组写回原程式)
-Q<按Enter> (离开DEBUG)
PROMPT> DIR printhw.com<按Enter>
(现在在看就会是新程式的长度289位元群组而不是,267位元群组)
现在在萤幕上先出现”ABC”再出现”Hello,World”分享: