@ debug
@ http://thestarman.pcministry.com/asm/debug/debug.htm
@ uselessstest
@ 2010.1.9
1: 以不带参数的方式启动debug时.
即命令行下debug, 回车.
(1) 占据64K的空闲空间, 作为一个段.
(2) 段寄存器CS,DS,ES,SS都设置为该段的地址, CS=DS=ES=SS=segment location
(3) 指令指针(IP)指向cs:0100, 堆栈指针指向ss:FFEE
(4) 寄存器AX, BX, CX, DX, BP, SI, DI的值都为0
2: 以debug filename方式启动(file不为.exe)
(1) 占据至少64KB的空闲空间, 具体情况取决于你的操作系统和可用内存空间大小.
(2) CS=DS=ES=SS=Segment Location
(3) 这时IP设为cs:0100, SP设为ss:FFFE(注意与上面的区别)
(4) 文件大小的值设置到BX和CX中. 如文件大小为360,247B(57F37)那么BX=0005,
CX=7F37. 其他寄存器都设为0.
3: 对于exe文件, 可以先讲exe文件后缀改成其他, 然后用debug调入.
4: 有一些代码或数据存于开始的256B, 这些由DEBUG来使用, 但当你把这个区域的数据全部
清0后, debug依然可以正常工作.
开头两字节为 "CD 20"表示指令: INT 20
偏移量为50h和51h的两字节为"CD 21"表示指令 INT 21, 其后的字节"CB"表示指令RETF.
5: 每次运行DEBUG(在CMD.EXE里), 开头的256B都一样.显示的字符是NTVDM程序读取
的AUTOEXEC.NT的后面一次读取一行, 存入命令行参数所保存的内存地区. 文件中最长
的一行包括回车符(0D), 被更短的行覆盖, 最后填满偏移量82H到CEH的debug段.
AUTOEXEC.NT里换行符(0AH)在这里不会出现,因为回车符在它们前面讲光标送到新一行的
开头, 而且每一行的第一个空格符(20h)前的字符都不会出现, 这也是为什么REM没出现
的原因.而且不管怎样偏移量81H的值总是0DH.
C:/>debug
-d 0 cf
0B20:0000 CD 20 FF 9F 00 9A EE FE-1D F0 4F 03 84 05 8A 03 . ........O.....
0B20:0010 84 05 17 03 84 05 25 04-01 01 01 00 02 FF FF FF ......%.........
0B20:0020 FF FF FF FF FF FF FF FF-FF FF FF FF 28 05 4E 01 ............(.N.
0B20:0030 44 0A 14 00 18 00 20 0B-FF FF FF FF 00 00 00 00 D..... .........
0B20:0040 05 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0B20:0050 CD 21 CB 00 00 00 00 00-00 00 00 00 00 20 20 20 .!...........
0B20:0060 20 20 20 20 20 20 20 20-00 00 00 00 00 20 20 20 .....
0B20:0070 20 20 20 20 20 20 20 20-00 00 00 00 00 00 00 00 ........
0B20:0080 00 0D 20 20 20 53 45 54-20 42 4C 41 53 54 45 52 .. SET BLASTER
0B20:0090 3D 41 30 0D 64 64 72 65-73 73 2E 20 20 46 6F 72 =A0.ddress. For
0B20:00A0 20 65 78 61 6D 70 6C 65-3A 0D 20 6F 6E 20 4E 54 example:. on NT
0B20:00B0 56 44 4D 2C 20 73 70 65-63 69 66 79 20 61 6E 20 VDM, specify an
0B20:00C0 69 6E 76 61 6C 69 64 0D-20 6F 6E 6C 79 2E 0D 00 invalid. only...
6: 删掉AUTOEXEC.NT后就不能运行DEBUG, 也不能运行其他16位程序, 因为这些都必须
在NTVDM下运行. AUTOEXEC.NT文件位于C:/WINDOWS/SYSTEM32.
7: 命令
-?
assemble A [address]
compare C range address
dump D [range]
enter E address [list]
fill F range list
go G [=address] [addresses]
hex H value1 value2 (Learn 2's Complement!)
input I port
load L [address] [drive] [firstsector] [number]
move M range address
name N [pathname] [arglist]
output O port byte
proceed P [=address] [number]
quit Q . . . . . . . . . (Learn this first!)
register R [register]
search S range list
trace/step T [=address] [number]
unassemble U [range]
write W [address] [drive] [firstsector] [number]
[]中的为可选参数.
adress: 表示内存地址(16进制), 可以只用一个偏移量, 也可以使用段地址:偏移量的形
式, 前面的0可以忽略, 如1f表示CS:001F
range: 两个16进制表示的内存地址, 可以用偏移量表示,也可以使用段地址:偏移量的形式
有些命令要求后一个地址只能使用偏移量的表示方法如-c命令.
list: 一连串的十六进制数,用空格分开. 或者是一些ASCII字符, 由单引号或双引号界定.
number: 数字, DEBUG中所有的数字都是16进制形式的.
8: Quit : Q
退出debug
9: Hex: H value1 value2
计算value1和value2的和与差, value1和value2不能超过4位.
例: H ffff 1
0000 fffe
相加就是按照16进制的加法, 但相减有时是按照二进制补码来算的. 比如
H 1 FFFF
0000 0002 因为ffff是-1的补码所有1-(-1)=2
H 7FFF 8000
FFFF FFFF
因为7FFF+8000=FFFF, 7FFF-8000=7FFF+8000=FFFF. 8000的补码还是8000
10: Dump : D [range]
D [address] [length]
比如D C000:0010
D 100 L30
11: Search: S [range] [list]
返回list所在的段地址:偏移量
12: Compare: C [range] [address]
比较range指定的块1和address指定的块2之间的区别, 若有区别则显示.
由于range说明了块1的大小, 所以指定块2的时候只用给出起始地址.
13: Fill : F [range] [list]
可以用于清空或填入一段内存区域, 填入的时候是连续循环填入的.
例:
f 100 12f 'buffer'
d 100 12f
可以看到100-12f这一段内存都填入了buffer字符.
使用-f 100 ffff 0将指派的段全部清0
14: Enter: E [address] [list]
用于直接将数据或指令(机器码)存入内存.
例:
-e 100 B4 09 BA 0B 01 CD 21 B4 00 CD 21
-e 7EA 24
-G =100
会看到"Program terminated normally"显示出来, 数据24h表示的是"$"
上述指令的代码为
mov AH, 09
MOV DX, 010B
INT 21H
MOV AH, 00
INT 21H
于是我们可以用同样的方法来显示255个字符从00H~FFH.
e 100 B4 09 BA 0B 01 CD 21 B4 00 CD 21 0D 0A 0D 0A 00 01 02
换行与回车 |
e 112 03 04 05 06 07 08 09 20 0B 0C 20 0E 0F 10 11 12 13 14
-- --
回车和换行用空格代替
E 124 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 20 25 26
---
e 136 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38
e 148 39 3A 3B 3C 3D 3E 3F 0D 0A 0D 0A 40 41 42 43 44 45 46
e 15a 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58
e 16c 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A
e 17e 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C
e 190 7D 7E 7F 0D 0A 0D 0A 80 81 82 83 84 85 86 87 88 89 8A
e 1a2 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C
e 1b4 9D 9E 9F a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aA aB aC aD aE
e 1c6 aF b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 bA bB bC bD bE bF 0D
e 1d8 0A 0D 0A c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 cA cB cC cD cE
e 1ea cF d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 dA dB dC dD dE dF e0
e 1fc e1 e2 e3 e4 e5 e6 e7 e8 e9 eA eB eC eD eE eF f0 f1 f2
e 20e f3 f4 f5 f6 f7 f8 f9 fA fB fC fD fE fF 0D 0A 0D 0A 24
用g =100来运行该代码
15: GO: G [=address] [address]
G用于运行一个程序, 并在程序代码中设置断点.
=address用于告诉DEBUG从哪里开始执行, 如果仅使用G不加参数, 则程序从CS:IP指向
处开始运行.
address用于设置断点, 断点处的第一个字节必须为可用的8088/8086操作码. 因此有时
随意设置的断点, 程序运行到此处可能不会停止. 再比如要是代码中的操作码为80286
及以上的CPU指令, 则DEBUG不认识, 在此处设置的断点也不会HALT.
DEBUG设置断点的方式: 在原指令序列中加入"CCH" (INT 3). 设置断点后将代码存储为
文件时, 这些"CCH"也会存入. 因此使用断点时最好先保存文件的一个备份.
16: Assemble: A [address]
创建一段机器可执行代码, 在内存区域CS:0100或者是由address所指定的地址.
尽管所有的宏指令和标签都不能使用, 但你可以使用伪指令DB和DW.
A可以记住上次汇编代码的最后的地址, 因此连续使用A命令时都会从上次的最后地址开
始(Dump命令也是如此). 在一个空行输入回车后结束汇编码的输入.
可以使用分号;表示后面的内容为注释.但不能注释DB/DW行.
DEBUG使用[]来引用内存数据
DEBUG可以使用"WORD PTR"和"BYTE PTR"来表明数据的大小.
对所有的8087操作码, WAIT和FWAIT前缀必须明确指明.
17: Unassemble: U [range]
没有range时, 使用偏移量100, 32B大小来反汇编.(32B大小并不是一定的, 有时最后一
条指令可能需要多一些的字节, 但大小还是在32B左右)
80286,80386及更新的INTEL CPU指令不能识别,故也不能被反汇编.
18: Input: I [port]
在windows系统下用I/O命令要么不可靠, 要不就是被模拟的.
-o 70 04
-i 71
11 ;得到系统时间里的小时.
-o 70 02
-i 71
45 ;得到系统时间里的分钟.
19: Output: O [port] [byte]
20: Load: L [address] [drive] [firstsector] [number]
L [program]
address指定数据将要复制到的内存的地址.
drive: 0=A, 1=B, 2=C.. 等等.
firstsector: 起始的扇区(从0开始)
number: 指定要复制的扇区数.
不能用L命令来load MBR, 或者其他不属于主分区和逻辑驱动器里的扇区.
当使用命令L 100 2 0 1来查看硬盘的第一个分区(MBR)时, 看到的是C盘的引导记录.
21: Move: M [range] [address]
把range里指定的数据复制到address里.
22: Name: N [pathname] [arglist]
当你想debug一个文件时, 可以用N指令, 然后使用L指令.
还一种用法是和W指令结合, 将数据写入文件.
23: Register: R [register]
仅输入R救回显示所有8086寄存器的内容和下一条指令.
若输入R后加上某个寄存器名, 则debug会显示该寄存器的内容, 并允许你修改它.
可以使用R后加上F来修改标志寄存器的内容.
24: Trace: T [=address] [number]
若仅输入T, 则会只执行由CS:IP指向的一条指令(一般情况是这样的).
若要执行多个指令就要指定address和number.
25: Proceed: P [=address] [number]
基本和T一样, 但对于CALL, LOOP, REP, INT指令会一次性执行完,
26: Write: W [address] [drive] [firstsector] [number]
W指令要慎用, 正确使用会非常方便的在硬盘创建文件, 但错误使用会出问题.
W经常和N结合使用, 来生成一个程序.
有错误,问题,意见都可以提出来.
转载注明出处, 多谢!