您的位置:首页 > 其它

[转贴]改好DEBUG七处缺点的comexe实现报告

2007-09-25 16:21 351 查看
改好DEBUG七处缺点的comexe实现报告




首先声明,本文所指DEBUG,系DOS 6.22,win 98及2k三者DEBUG.EXE.

(1) DEBUG命令T及P的2处缺点

跟踪命令T,建立在8086标志寄存器第8位(自陷位)置1后,处理器执行完一条
被跟踪指令,就进单步中断1的基础上(进入时,被调试进程栈顶3个字,被无辜破坏).
DEBUG预先接管中断1,在那里,对被跟踪指令的执行完现场,先保存,后显示.

于是,DEBUG用以下5步,让欲跟踪的指令,在自陷位持有1的处理器环境下,间接执行:

(1.1) or 标志寄存器,100h
(1.2) push 标志寄存器
(1.3) push 欲跟踪的指令CS
(1.4) push 欲跟踪的指令IP
(1.5) iret

欲跟踪的指令是int 21h等中断指令时,遇到1个问题:

处理器执行此int指令时,先压标志寄存器F(自陷位已被DEBUG置为1)入栈,
然后清标志寄存器的自陷位及中断位,接着压int下条指令y的CS,IP入栈,
最后,查找位于0:0的中断矢量表,执行此中断号对应的中断入口指令x
(21h中断的入口IP,CS,在0:84h,0:86h字).而此时的自陷位刚被清为0,
于是,就不能跟踪x这条指令.

再次进入中断1的时刻,只能是此int例程通过iret指令返回到用户态时,
处理器从栈中弹出y的ip,cs及标志寄存器F,间接执行完y的那个时刻.

命令T能跟进int例程内部,靠以下模拟int进入过程的5步:

(1.6) 压标志寄存器F入用户态堆栈.
(1.7) 压y的CS,IP入用户态堆栈.
(1.8) 清标志寄存器F的中断位.
(1.9) 改欲跟踪的指令为x.
(1.10) 用(1.1)开始的5步,间接执行x.注意,在依此弹出x的IP,CS后,弹出的标志
寄存器F,其中断位已被(1.8)清除,从而与int指令实际执行后的环境相同,
x在中断位关闭的氛围中执行.

置断点命令G,建立在一执行机器码为0cch的INT 3指令,就进断点中断3的
基础上.DEBUG预先接管中断3,然后用0cch替换断点首字节,运行被调试进程,如果
运行路径遇到此断点,就会进中断3.在那里,命令G对被调试进程进入int 3之前的
现场,先保存,后显示,再恢复断点首字节.

继续命令P,能执行int指令而不跟进去,靠的是对int的下条指令y置断点.
这样,就把整个int例程视为1条指令,使int的下条指令y,停于中断3.

命令T及P有2处缺点:

(1.11) 它们的步数从1到ffff,对想无限次运行,直至被调试进程自身终止的用户,
这是缺点1.

(1.12) 遇int或call指令,T进入而P不进入,对想跟踪自编的proc,而不想跟踪
int例程的用户,要不断用T与P,手工解决进入问题,T与P自动运行多步
的功能,只得弃用,这是缺点2.

(2) DEBUG对INTO执行命令P的1处缺点

F第11位(溢出位)为1时,执行机器码为0ceh的INTO,将进入int 4.例如,

mov al,7fh
inc al ;al变为80h,置1溢出位
into

,不想进入中断4内部,执行P命令时,DEBUG却与命令T相同,进了内部,这是缺点3.

(3) DEBUG不认首字被5a4d标识,后缀改为他名的exe文件的1处缺点

exe文件,以头两个字节为4d(M),5a(Z)做标识,不管后缀名.本文所用的4b01装入功能,
就按此规则,解决exe文件的重定位.

但DEBUG却依后缀名解决重定位,这是缺点4.

刚进DEBUG的bx:cx值,体现装入文件长度,对exe文件,此值,少去exe头占用的200h.

(4) DEBUG与用户交互时的3处缺点

(4.1) 用户想输出DEBUG的运行结果到foo.1时,只能发:DEBUG foo.com>foo.1
但运行提示及用户的键盘echo,也被重定向,不可见,这是缺点5.

(4.2) 改标志寄存器的标志位时,需知各标志的两字母简名,如溢出位为1/0,
简名为OV/NV,对不知简名,而想改标志的用户,这是缺点6.

(4.3) 被调试进程用功能4ch/31h,使al带errorlevel值5a,正常/驻留终止时,
DEBUG显出Program terminated normally信息,但不反映errorlevel及终止类型
字节,用户这时只得手工汇编mov ah,4d,int 21,从al,ah取两值,这是缺点7.

(5) comexe改好这七处缺点的做法:

(5.1) 仿命令T及P运行时,comexe将用'val[0001~fffe,ffff]',询问步数,
回答ffff时,comexe将无限次运行,直至被调试进程自身终止,这改好缺点1.

(5.2) 遇操作码为0cdh的int,或0cch,或0ceh且F溢出位为1,comexe将用
'proceed,n(ever enter int):',问是否进入中断内部,答p,本次不进入,
答n,从此不进入,答其他,将进入;call指令,comexe都进入,这改好缺点2,3.

(5.3) comexe调用4b01功能,装入被调试进程,依返回的sp初值,决定是否exe文件,
这改好缺点4.

(5.4) comexe先保存输出句柄1到oldstd1,对提示及用户的键盘echo,
让stderr代替句柄1,从而可见;对运行结果,让oldstd1代替句柄1,输出
能到屏幕或文件,这改好缺点5.

(5.5) comexe能读,写任意段:位移上的字,被调试进程AX,BX,CX,DX,SP,BP,SI,DI,
DS,ES,SS,CS,IP,F这14个字,从低存到高,AX的段:位移,被AX(seg:off=0526:0190)
指明,F有效位C等,被F(????ODITSZ?A?P?C)指明,这改好缺点6.

(5.6) comexe仿DEBUG,能捕获被调试进程5类终止,并改好缺点7:

装入映象后,comexe使被调试进程psp偏移0ah处的终止IP及CS,指向comexe的i22,
被调试进程用int 20h,或int 21h的功能0,或功能4ch正常终止,或用int 27h,
int 21h的功能31h驻留终止,DOS都将终止IP及CS写入中断22h,然后执行int 22h,
于是,comexe在i22,可感知这些终止,并用4d功能,取终止信息,显出
exit_type/errlev=00/5a.

(7) comexe仿DEBUG,能捕获被调试进程CTRL-BREAK,CTRL-C中断的做法:

按ctl-break/ctl-c键时,键盘电路中断CPU,键盘中断服务程序,会将40:71字节
第7位,置为1/0,并在屏幕光标处,显示^C,最后,调用中断23h.

comexe让中断23h指向i23,被调试进程被ctl中断,而进入i23时,sp指向键盘中断
服务程序调用中断23h那条指令后面的ip,加6后,指向被调试程序中,能检ctl
中断的int指令后面的ip,如int后面的cmp:

mov ah,1 ;读键盘
int 21h
cmp al,'q'

comexe对这两键,分显为^b/^c.而DEBUG,不分显.

(8) comexe仿DEBUG能求指令操作码的助记符的做法:

占1到6个字节的8086的指令,分3部分:操作码字节[寻址方式字节][位移或数据字节].

第2部分的出现被第1部分决定.第3部分的出现被第1,2部分决定.

8086有6种操作数寻址方式:

(8.1) 寄存器对寄存器,如mov cx,bx,把bx的内容送入cx.

(8.2) 立即数寻址,如mov cx,10,把10送入cx(10值,随.RADIX变,写.RADIX 4,cx为4)

(8.3) 直接存储器寻址,如mov cx,wd1,把写为wd1 dw 0的wd1字内容,送入cx.

(8.4) 寄存器(bx,bp,si,di)间接寻址,如mov cx,[bx],把bx的内容,作为有效地址EA,
将EA处的字,送入cx.

(8.5) 寄存器+位移disp的间接寻址,如mov cx,[bx]+1234h,把bx的内容加上1234h,
作为EA,将EA处的字,送入cx.

(8.6) 基址寄存器(bx,bp)+变址寄存器(si,di)+位移的间接寻址,如mov cx,
[bx]+[si]+13h,把bx的内容,si的内容,13h,三者相加,作为EA,将EA处的字,送入cx.

有时,操作码字节的第0位w,用1/0,指明字/字节操作.

有时,操作码字节的第1位vds,在移位指令中,用1/0,指明cl次/1次移动;在含运算
结果的指令中,用1/0,指明结果存于reg域/有效地址EA;在含立即数加减的指令
中,用1指明加减字时(w为1),寻址方式字节的下个字节,将依符号位,展成1个运算字.

寻址方式字节,从高到低,含mod域(2位),reg域(3位),r/m域(3位).

mod域解释disp的形成:

mod为0,则disp为0,即无位移低字节及位移高字节.(r/m域为6时,EA仅被位移低字节,
及位移高字节构成)

mod为1,则disp为位移低字节,及此字节的符号扩展字节,无位移高字节.

mod为2,则disp为位移低字节,及位移高字节.

mod为3,则r/m域是寄存器域.

reg域依w的1/0,索引ax,cx,dx,bx,sp,bp,si,di及al,cl,dl,bl,ah,ch,dh,bh

r/m域解释16位有效地址(EA)的组成:
r/m=0,EA=[BX]+[SI]+disp
r/m=1,EA=[BX]+[DI]+disp
r/m=2,EA=[BP]+[SI]+disp
r/m=3,EA=[BP]+[DI]+disp
r/m=4,EA=[SI]+disp
r/m=5,EA=[DI]+disp
r/m=6,EA=[BP]+disp(mod域为0时,EA仅被位移低字节,及位移高字节构成)
r/m=7,EA=[BX]+disp

(8.7) 举10个例子,解释反汇编思想:

(8.7.1) 字节操作,运算结果存于EA:
机器码00c1,反出add cl,al,mod为3,reg为0,索引到al,结果存于1值r/m索引到的cl

(8.7.2) 字操作,运算结果存于reg:
机器码03ad3412,反出add bp,[di]+1234h,mod为2,reg为5,索引到bp,r/m为5,
EA就是[DI]+disp,先低后高存储的disp为1234h

(8.7.3) mod为0,使位移为0:
机器码f630(div的reg,恒为6),反出div byte ptr [bx]+[si]+0,这时,r/m为0,
EA就是[BX]+[SI]+disp

(8.7.4) mod为0,r/m为6,使EA仅被16位disp构成:
机器码f6363412,反出div byte ptr [1234h]

(8.7.5) mod为1,使disp为位移低字节,及此字节的符号扩展字节:
机器码8042fd80,反出add byte ptr [bx]+[di]-3,80h,这时,disp为fd的16位符号
扩展字fffd,即-3,r/m为1,EA就是[BX]+[DI]+disp,加数为80h

(8.7.6) mod为2,使disp为位移高字节,及位移低字节:
机器码c78257136824,反出mov word ptr 1357h[bp+si],2468h,这时,mov的reg规定
为0,r/m为2,EA就是[BP]+[SI]+disp

(8.7.7) vds为1,w为1:
机器码83c3fc,反出add bx,-4,这时,add的reg规定为0,r/m为3,索引到bx,fc符号
扩展成运算字fffc,即-4

(8.7.8) vds为0,w为1:
机器码81c3fcff,反出add bx,-4,未用符号扩展优点,字-4存为fcff

(8.7.9) 偏移108h处,相等则跳到10fh的指令:
机器码7405,反出jz 10f,74不分域,下一条指令地址10ah,加上补码形式的位移
字节5,就是目的地址10fh.若想转101h,位移字节为f7,对应-9.

(8.7.10) 指定段前缀:
机器码26a03412,反出mov al,es:[1234h],段前缀26,2e,36,3e,对应es,cs,ss,ds.

隐含段前缀时的寻址方法:

[ip],[sp],[bx],[bp],[si],用cs,ss,ds,ss,ds

[di]不含串时,用ds,如mov [di],al,否则用es,如stosb

基址+变址的段前缀,依基址.

DEBUG靠4个表:mnemo,mnemo_idx,x4857_idx,x4857,求指令操作码的助记符.

(8.8) mnemo是指令助记符表,各助记符被空格隔开,如"CLD CLI".

(8.9) mnemo_idx被操作码索引,对应的字值为助记符对mnemo的偏移,例如,cli的
机器码是fa,mnemo_idx的第fa个字,值为48h,此为CLI串对mnemo的偏移.mnemo_idx
的字值为0ffffh时,要用操作码索引x4857_idx:

(8.9.1) x4857_idx的对应字节值不为0ffh时,是对x4857的偏移off,这时,要用寻址
方式字节的reg域,索引x4857的始于字节偏移off的8个字,这组字中被索引的字值,
为助记符对mnemo的偏移.

例如,dec ah,机器码是fecc,mnemo_idx的第fe个字,值为0ffffh,找x4857_idx的
第fe个字节,值为30h,再用寻址方式字节cc的reg值1,索引x4857的偏移30h字节
开始的8个字,找这组字中的第1个字,值为6ch,此为"DEC"对mnemo的偏移.

(9) comexe的跨段检查功能

DEBUG.EXE等,常用retf等指令,同时改IP,CS,comexe的t,遇CS改值,
用0033 gap seg,n(o check):,指明老CS的偏移33处的指令执行后,
使CS改值,并问还查跨段否,答n表示不查.

DEBUG依4表求助记符,是靠comexe,调试2k的DEBUG.EXE,对t,答ffff,对proceed,
答n,过了33,103,1aa,104跨段,遇显出'-'的28fc,读u等命令的478,显助记符
的292c,然后用DEBUG调试此EXE,得mnemo始于40ba,mnemo_idx始于3cba,
化简后,得x4857_idx,32个在4857的字,减40ba,得x4857.

想从文件输入的用户,对进中断及跨段,可写两个n,不管谁先到,再预写其他
命令,可使comexe自动运行,如用pctools写不含LF的29字节二进制文件foo.0:

0100 64 65 62 75 67 2E 65 78-65 0D 66 2E 65 78 65 0D debug.exe.f.exe.
0110 74 66 66 66 66 0D 6E 6E-75 0D 71 0D 71 tffff.nnu.q.q

其中,f.exe是debug.exe的参数,由

code segment
assume es:code,cs:code,ss:code,ds:code
@ proc far
push ds
xor ax,ax
push ax
ret
@ endp
code ends
end @

生成.执行comexe<foo.0,相当于执行了debug.exe f.exe的命令u,q

(10) comexe.asm全文:

RADIX = 16 ;可接收各进制
RADIX1 = 400h+RADIX ;4是移次
WANTSZ = 4 ;不含CR的输入长

setstd1 macro std1
mov ah,46h ;使bx起cx作用
mov bx,std1
mov cx,1 ;stdout
int 21h
endm

makebrk macro
mov al,es:[bx] ;保存首字节
mov brkval,al
mov byte ptr es:[bx],0cch ;换入0cch

mov brkoff,bx
mov brkseg,es
endm

alasc macro
mov ah,al

and al,15 ;低nibble
xlat

xchg ah,al

rept 4
shr al,1 ;高nibble
endm

xlat

stosw
endm

axasc macro
xchg ah,al ;处理ah

push ax
alasc
pop ax

xchg ah,al ;处理al
alasc
endm

newline macro
mov ah,9
lea dx,CRLF
int 21h
endm

code segment
assume es:code,cs:code,ss:code,ds:code

org 100h
@: jmp @1

w16 dw 0 ;参数块起始,0继承父env
dw 128+15+1 ;实长打头的参数串偏移
paraseg dw 5 dup(0) ;参数串段值及4字fcb
initsp dw 0
initss dw 0
initip dw 0
initcs dw 6 dup(0)

.w0 db 13,10
w0_w14 db '0000 0000 0000 0000 0000 0000 0000 0000 '
db '0000 0000 0000 0000 0000 0000 0000 '
w15 dw 2 dup(0)
$_32 db "$gap seg,n(o check):$" ;跨段标记

bufsz db WANTSZ+1 ;键盘缓冲区
charcnt db 0
charbuf db WANTSZ+1 dup(0)

cax dw 0
cbx dw ? ;被调试文件长的高,低字.对exe文件,少200h
ccx dw ?
cdx dw 0
csp dw ?
cbp dw 0
csi dw 0
cdi dw 0

cds dw ?
ces dw ?
css dw ?
ccs dw ?
cip dw ?

cf dw 3202h ;仿debug,初置标志寄存器.对应0:0
oldstd1 dw 0,1,1 ;伴随comexe的stdout

b0_b1 label word
byte0 db 0
byte1 db 0
intsz dw 0,3,3 ;欲进的中断指令的字节数

.ax db 13,10,'AX='
axdiasc db '0000 BX=0000 CX=0000 DX=0000 '
db 'SP=0000 BP=0000 SI=0000 DI=0000|'

codeasc dw 0 ;操作符asc

vecasc label word ;中断号asc
db 0,0,13,10,'DS='

dsipasc db '0000 ES=0000 SS=0000 CS=0000 IP=0000 '
oc db 23 dup(32),'|' ;8个标志简名
mne8086 db 7 dup(0) ;8086指令助记符
CRLF db 13,10,36

F01 db 'NVOVUPDNDIEIPLNGNZZRNAACPOPENCCY'

i? label word ;区别中断1,3,22h,23h
db 'co'

off23 label word
db 'm,'

seg23 label word
db 'ex'

steps1 label word
db 'e:'

chkgap db 36 ;查跨段?

steps dw 0a0dh ;步数

brkval db 'a' ;断点首字节
brkoff label word
db 'rg' ;断点off
brkseg label word
db '(len<85):$' ;断点seg

?cmd db 13,10,'AX(seg:off=' ;主菜单
caxseg db 4 dup(0),58
caxoff db 4 dup(0)
db ') F(????ODITSZ?A?P?C) d(ump word),edit,go,trace:$'

?steps db 13,10,'steps[0001~fffe,ffff]$'
?seg db 13,10,'seg[????]$'
?off db 13,10,'off[????]$'
?val db 13,10,'val[????]$'

?enter db 13,10,'proceed,n(ever enter int):$'

hextbl db '0123456789abcdef'
Fvalid dw 0ed5h ;over,direction,interrupt(,trap)
;sign,zero,auxiliary,parity,carry

ctl db 13,10,94
c_brk db 0,13,10,36

exitmsg db 13,10,'exit_type/errlev='
type4 db 0,0,47
errlev db 0,0,13,10,36

;指令助记符表(debug的40bah)
mnemo db "DB DW ; ORG ADD " ;0
db "ADC SUB SBB XOR "
db "OR AND AAA AAD A"
db "AM AAS CALL CBW "
db "CLC CLD CLI CMC "
db "CMPSB CMPSW CMP "
db "CWD DAA DAS DEC "
db "DIV ESC FXCH FFR"
db "EE FCOMPP FCOMP " ;80h
db "FCOM FICOMP FICO"
db "M FNOP FCHS FABS"
db " FTST FXAM FLDL2"
db "T FLDL2E FLDLG2 "
db "FLDLN2 FLDPI FLD"
db "1 FLDZ F2XM1 FYL"
db "2XP1 FYL2X FPTAN"
db " FPATAN FXTRACT " ;100h
db "FDECSTP FINCSTP "
db "FPREM FSQRT FRND"
db "INT FSCALE FINIT"
db " FDISI FENI FCLE"
db "X FBLD FBSTP FLD"
db "CW FSTCW FSTSW F"
db "STENV FLDENV FSA"
db "VE FRSTOR FADDP " ;180h
db "FADD FIADD FSUBR"
db "P FSUBR FSUBP FS"
db "UB FISUBR FISUB "
db "FMULP FMUL FIMUL"
db " FDIVRP FDIVR FD"
db "IVP FDIV FIDIVR "
db "FIDIV FWAIT FILD"
db " FLD FSTP FST FI" ;200h
db "STP FIST HLT IDI"
db "V IMUL INC INTO "
db "INT IN IRET JNBE"
db " JAE JA JCXZ JNB"
db " JBE JB JNC JC J"
db "NAE JNA JZ JE JG"
db "E JG JNLE JNL JL"
db "E JL JNGE JNG JM" ;280h
db "P JNZ JNE JPE JP"
db "O JNP JNS JNO JO"
db " JS JP LAHF LDS "
db "LEA LES LOCK LOD"
db "SB LODSW LOOPNZ "
db "LOOPZ LOOPNE LOO"
db "PE LOOP MOVSB MO"
db "VSW MOV MUL NEG " ;300h
db "NOP NOT OUT POPF"
db " POP PUSHF PUSH "
db "RCL RCR REPZ REP"
db "NZ REPE REPNE RE"
db "P RETF RET ROL R"
db "OR SAHF SAR SCAS"
db "B SCASW SHL SHR "
db "STC STD STI STOS" ;380h
db "B STOSW TEST WAI"
db "T XCHG XLAT ES: "
db "CS: SS: DS: ??? " ;3b0h

;x4857_idx被操作码索引,偶数值,是助记符对x4857的偏移

x4857_idx db 128 dup(1) ;0~7fh
db 4 dup(10h),76 dup(1) ;80h~0cfh
db 4 dup(0),4 dup(1),8 dup(0ffh) ;0d0h~0dfh
db 22 dup(1),20h,20h,6 dup(1),30h,30h ;0e0h~0ffh

;x4857被寻址方式字节reg域索引,项值为助记符对mnemo的偏移

;被256bh或255dh找出,是ROL,ROR,RCL,RCR,SHL,SHR,???,SAR偏移
x4857 dw 035bh,035fh,0330h,0334h,0378h,037ch,03bch,0368h

;被211fh或218ch找出,是ADD,OR,ADC,SBB,AND,SUB,XOR,CMP偏移
dw 0ch,20h,10h,18h,23h,14h,1ch,5ch

;被2585h找出,是TEST,???,NOT,NEG,MUL,IMUL,DIV,IDIV偏移
dw 398h,3bch,314h,30ch,308h,222h,70h,21dh

;被2594h找出,是INC,DEC,CALL,CALL,JMP,JMP,PUSH,???偏移
dw 227h,6ch,37h,37h,28eh,28eh,32bh,3bch

comment * (debug的3cbah)
000 C6 40 AF 21 C6 40 AF 21-C6 40 04 22 C6 40 04 22 ;00-03
010 C6 40 2F 21 C6 40 2F 21-E5 43 CC 21 DB 43 CC 21 ;04-07
020 DA 40 AF 21 DA 40 AF 21-DA 40 04 22 DA 40 04 22 ;08-0b
030 DA 40 2F 21 DA 40 2F 21-E5 43 CC 21 BA 40 6B 21 ;0c-0f
040 CA 40 AF 21 CA 40 AF 21-CA 40 04 22 CA 40 04 22 ;10-13
050 CA 40 2F 21 CA 40 2F 21-E5 43 CC 21 DB 43 CC 21 ;14-17
060 D2 40 AF 21 D2 40 AF 21-D2 40 04 22 D2 40 04 22 ;18-1b
070 D2 40 2F 21 D2 40 2F 21-E5 43 CC 21 DB 43 CC 21 ;1c-1f
080 DD 40 AF 21 DD 40 AF 21-DD 40 04 22 DD 40 04 22 ;20-23
090 DD 40 2F 21 DD 40 2F 21-66 44 6C 20 1E 41 7D 22 ;24-27
0A0 CE 40 AF 21 CE 40 AF 21-CE 40 04 22 CE 40 04 22 ;28-2b
0B0 CE 40 2F 21 CE 40 2F 21-6A 44 68 20 22 41 7D 22 ;2c-2f
0C0 D6 40 AF 21 D6 40 AF 21-D6 40 04 22 D6 40 04 22 ;30-33
0D0 D6 40 2F 21 D6 40 2F 21-6E 44 64 20 E1 40 7D 22 ;34-37
0E0 16 41 AF 21 16 41 AF 21-16 41 04 22 16 41 04 22 ;38-3b
0F0 16 41 2F 21 16 41 2F 21-72 44 60 20 ED 40 7D 22 ;3c-3f
100 E1 42 D9 21 E1 42 D9 21-E1 42 D9 21 E1 42 D9 21 ;40-43
110 E1 42 D9 21 E1 42 D9 21-E1 42 D9 21 E1 42 D9 21 ;44-47
120 26 41 D9 21 26 41 D9 21-26 41 D9 21 26 41 D9 21 ;48-4b
130 26 41 D9 21 26 41 D9 21-26 41 D9 21 26 41 D9 21 ;4c-4f
140 E5 43 D9 21 E5 43 D9 21-E5 43 D9 21 E5 43 D9 21 ;50-53
150 E5 43 D9 21 E5 43 D9 21-E5 43 D9 21 E5 43 D9 21 ;54-57
160 DB 43 D9 21 DB 43 D9 21-DB 43 D9 21 DB 43 D9 21 ;58-5b
170 DB 43 D9 21 DB 43 D9 21-DB 43 D9 21 DB 43 D9 21 ;5c-5f
180 BA 40 6B 21 BA 40 6B 21-BA 40 6B 21 BA 40 6B 21 ;60-63
190 BA 40 6B 21 BA 40 6B 21-BA 40 6B 21 BA 40 6B 21 ;64-67
1A0 BA 40 6B 21 BA 40 6B 21-BA 40 6B 21 BA 40 6B 21 ;68-6b
1B0 BA 40 6B 21 BA 40 6B 21-BA 40 6B 21 BA 40 6B 21 ;6c-6f
1C0 68 43 98 22 64 43 98 22-0F 43 98 22 07 43 98 22 ;70-73
1D0 22 43 98 22 4C 43 98 22-0B 43 98 22 FF 42 98 22 ;74-77
1E0 6B 43 98 22 60 43 98 22-54 43 98 22 58 43 98 22 ;78-7b
1F0 3C 43 98 22 28 43 98 22-38 43 98 22 2C 43 98 22 ;7c-7f
200 00 00 1F 21 00 00 1F 21-00 00 1F 21 00 00 8C 21 ;80-83
210 52 44 04 22 52 44 04 22-5C 44 04 22 5C 44 04 22 ;84-87
220 BE 43 AF 21 BE 43 AF 21-BE 43 04 22 BE 43 04 22 ;88-8b
230 BE 43 DD 21 7A 43 FF 21-BE 43 ED 21 DB 43 FA 21 ;8c-8f
240 CA 43 7D 22 5C 44 BB 22-5C 44 BB 22 5C 44 BB 22 ;90-93
250 5C 44 BB 22 5C 44 BB 22-5C 44 BB 22 5C 44 BB 22 ;94-97
260 F6 40 7D 22 1A 41 7D 22-F1 40 43 21 57 44 7D 22 ;98-9b
270 DF 43 7D 22 D6 43 7D 22-1D 44 7D 22 71 43 7D 22 ;9c-9f
280 BE 43 C8 22 BE 43 C8 22-BE 43 DC 22 BE 43 DC 22 ;a0-a3
290 B2 43 7D 22 B8 43 7D 22-0A 41 7D 22 10 41 7D 22 ;a4-a7
2A0 52 44 2F 21 52 44 2F 21-46 44 7D 22 4C 44 7D 22 ;a8-ab
2B0 87 43 7D 22 8D 43 7D 22-26 44 7D 22 2C 44 7D 22 ;ac-af
2C0 BE 43 E7 22 BE 43 E7 22-BE 43 E7 22 BE 43 E7 22 ;b0-b3
2D0 BE 43 E7 22 BE 43 E7 22-BE 43 E7 22 BE 43 E7 22 ;b4-b7
2E0 BE 43 EE 22 BE 43 EE 22-BE 43 EE 22 BE 43 EE 22 ;b8-bb
2F0 BE 43 EE 22 BE 43 EE 22-BE 43 EE 22 BE 43 EE 22 ;bc-bf
300 BA 40 6B 21 BA 40 6B 21-11 44 5C 21 11 44 7D 22 ;c0-c3
310 7E 43 FF 21 76 43 FF 21-BE 43 2A 21 BE 43 2A 21 ;c4-c7
320 BA 40 6B 21 BA 40 6B 21-0C 44 5C 21 0C 44 7D 22 ;c8-cb
330 EA 42 F8 22 EA 42 3E 21-E5 42 7D 22 F1 42 7D 22 ;cc-cf
340 00 00 6B 25 00 00 6B 25-00 00 5D 25 00 00 5D 25 ;d0-d3
350 E9 40 84 21 E5 40 84 21-BA 40 6B 21 61 44 7D 22 ;d4-d7
360 00 00 B4 23 00 00 4E 23-00 00 B4 23 00 00 26 23 ;d8-db
370 00 00 B4 23 00 00 07 23-00 00 B4 23 00 00 FD 22 ;dc-df
380 93 43 98 22 9A 43 98 22-AD 43 98 22 02 43 98 22 ;e0-e3
390 EE 42 03 25 EE 42 FE 24-D2 43 20 25 D2 43 25 25 ;e4-e7
3A0 F1 40 AB 22 48 43 AB 22-48 43 43 21 48 43 98 22 ;e8-eb
3B0 EE 42 F6 24 EE 42 F1 24-D2 43 0E 25 D2 43 13 25 ;ec-ef
3C0 82 43 70 20 BA 40 6B 21-F7 43 70 20 F2 43 70 20 ;f0-f3
3D0 D3 42 7D 22 06 41 7D 22-00 00 85 25 00 00 85 25 ;f4-f7
3E0 FA 40 7D 22 3A 44 7D 22-02 41 7D 22 42 44 7D 22 ;f8-fb
3F0 FE 40 7D 22 3E 44 7D 22-00 00 94 25 00 00 94 25 ;fc-ff
*

;mnemo_idx被操作码索引,非ffff项值,为助记符对mnemo的偏移,否则查x4857_idx
mnemo_idx dw 6 dup(0ch),32bh,321h ;0
dw 6 dup(20h),32bh,0

dw 6 dup(10h),32bh,321h
dw 6 dup(18h),32bh,321h

dw 6 dup(23h),3ach,64h
dw 6 dup(14h),3b0h,68h

dw 6 dup(1ch),3b4h,27h
dw 6 dup(5ch),3b8h,33h

dw 8 dup(227h) ;40h
dw 8 dup(6ch)

dw 8 dup(32bh)
dw 8 dup(321h)

dw 8 dup(0)
dw 8 dup(0)

dw 2aeh,2aah,255h,24dh,268h,292h,251h,245h
dw 2b1h,2a6h,29ah,29eh,282h,26eh,27eh,272h

dw 4 dup(0ffffh),398h,398h,3a2h,3a2h ;80h
dw 5 dup(304h),2c0h,304h,321h

dw 310h,7 dup(3a2h)
dw 3ch,60h,37h,39dh,325h,31ch,363h,2b7h

dw 4 dup(304h),2f8h,2feh,50h,56h
dw 398h,398h,38ch,392h,2cdh,2d3h,36ch,372h

dw 8 dup(304h)
dw 8 dup(304h)

dw 0,0,357h,357h,2c4h,2bch,304h,304h ;c0h
dw 0,0,352h,352h,230h,230h,22bh,237h

dw 4 dup(0ffffh),2fh,2bh,0,3a7h
dw 8 dup(0ffffh)

dw 2d9h,2e0h,2f3h,248h,234h,234h,318h,318h
dw 37h,3 dup(28eh),234h,234h,318h,318h

dw 2c8h,0,33dh,338h,219h,4ch,0ffffh,0ffffh
dw 40h,380h,48h,388h,44h,384h,0ffffh,0ffffh

INnib proc ;输WANTSZ个nibble到charbuf

INnib0: mov ah,9 ;提示
int 21h

push dx

inc ah ;0a是缓冲输入
lea dx,bufsz
int 21h

pop dx

cmp charcnt,WANTSZ
jnz INnib0

xor bx,bx ;bx收nibble
lea si,charbuf

INnib1: test charcnt,0ffh
jz INnib2

lodsb

mov cx,RADIX
lea di,hextbl
repne scasb
jnz INnib0

inc cx ;转'[0-9a-f]'为0~15
sub cx,RADIX1
neg cx

xchg ch,cl
shl bx,cl

or bl,ch

dec charcnt
jmp short INnib1

INnib2: ret
INnib endp

regasc proc
regasc1:lodsw

axasc

dec dh
jz regasc2

mov al,dl
cbw

add di,ax ;跳到AX=1234 BX=5678的5
jmp regasc1

regasc2:ret
regasc endp

i1: mov cs:i?,1*4
jmp sv

i3: mov cs:i?,3*4
jmp sv

i22: cmp cs:i?,22h*4
jnz i22_1
jmp myend ;被调试进程psp,已被comexe用4ch终止

i22_1: mov cs:i?,22h*4
jmp sv

i23: mov cs:i?,23h*4
add sp,3*2 ;sp指向键盘中断服务程序调用中断23h那条指令后面的ip,
;加6后,指向被调试程序中,能检ctl中断的int指令后面的ip

sv: mov cs:cax,ax ;保存reg
mov cs:cbx,bx
mov cs:ccx,cx
mov cs:cdx,dx
mov cs:cbp,bp
mov cs:csi,si
mov cs:cdi,di
mov cs:cds,ds
mov cs:ces,es
mov cs:css,ss

pop bx ;进i1,i3,i22,i23前的ip,cs,F到bx,es,cf
pop es
pop cs:cf

mov cs:csp,sp ;保存真实的csp

cmp cs:i?,3*4 ;中断3的ip要减1
jnz sv1

dec bx

sv1: mov ax,cs:i?
and ax,12

cmp ax,12 ;中断3,23h,恢复断点
jnz sv_ccs

mov ax,cs:brkseg
mov ds,ax

mov di,cs:brkoff

mov al,cs:brkval
mov ds:[di],al

sv_ccs: mov ax,es

cmp cs:ccs,ax
jz sv_cip

mov cs:ccs,ax ;ccs仅此时修改

cmp cs:i?,1*4 ;仅处理命令t跨段
jnz sv_cip

cmp cs:chkgap,36 ;查跨段?
jnz sv_cip

mov ax,cs:cip ;保存引起跨段的cip
mov cs:w15,ax

mov cs:$_32,32 ;置跨段标记为空格

sv_cip: mov cs:cip,bx

xor ax,ax
mov ds,ax

mov dx,cs:off23 ;指回老中断23h
mov ds:[23h*4],dx

mov dx,cs:seg23
mov ds:[23h*4+2],dx

mov di,cs:i?

mov dx,cs:cf[di] ;指回老中断1或3
mov ds:[di],dx

mov dx,cs:cf[di+2]
mov ds:[di+2],dx

mov cl,ds:[40h*10h+71h] ;取ctl-break位

test cl,80h
jz sv_cip1

mov ds:[40h*10h+71h],al ;清ctl-break位

sv_cip1:not ax ;ax为ffff

cmp cs:steps,ax ;steps为ffff
jz myenv

test cs:steps,ax ;steps为0
jz myenv

dec cs:steps

myenv: mov bp,cs ;指向comexe

mov ss,bp
mov sp,256

sti ;尽早开中断

mov ds,bp
cld ;方向,从低到高

cmp i?,22h*4
jb myenv1

mov steps,0 ;22h,23h中断,都清步数
je myenv1

shl cl,1 ;23h,左移cl
cmc ;变反c

mov ax,962h ;al为b
adc al,0

mov c_brk,al

lea dx,ctl
int 21h

myenv1: jmp main

scene proc ;显示现场

xor bh,bh ;用于byte0寻址
mov bl,byte0

mov si,bx

mov si,mnemo_idx[bx+si] ;mnemo_idx是字表,取助记符偏移到si

cmp si,0ffffh
jnz scene1

mov si,3bch ;浮点指令,反出???

mov al,x4857_idx[bx] ;x4857_idx是字节表
cmp al,255
jz scene1

mov bl,byte1 ;寻址方式字节,含mod(2),reg(3),r/m(3)
and bl,38h
shr bl,1
shr bl,1

add bl,al

mov si,x4857[bx] ;x4857是字表

scene1: add si,offset mnemo ;助记符偏移加上mnemo表头位置

mov ax,2020h
mov vecasc,ax ;填空格

mov cx,7 ;助记符最长7
mov di,si

repnz scasb ;助记符断于空格

push cx
sub cx,7
neg cx

lea di,mne8086 ;传助记符
rep movsb

pop cx
rep stosb ;传空格

lea bx,hextbl

mov al,byte0
lea di,codeasc ;操作码
alasc

cmp intsz,2 ;遇int 21h等?
jnz scene2

mov al,byte1
lea di,vecasc ;中断号
alasc

scene2: mov dx,804h ;dh是ax到di项数,dl是AX=1234 BX=5678的4,5隔

lea si,cax ;si取出预显数值
lea di,axdiasc ;di存放si显出字符
call regasc

mov dh,5 ;ds_ip项数
lea di,dsipasc
call regasc

mov bx,800h ;从溢出位向右,逐位测试
lea si,F01
lea di,oc

chkbit1:test Fvalid,bx ;此位有效?
jz chkbit4

test cf,bx
jz chkbit2

add si,2 ;此位为1
lodsw

jmp chkbit3

chkbit2:lodsw ;此位为0
add si,2

chkbit3:stosw ;传2字母
inc di ;跳空格

chkbit4:shr bx,1
jnc chkbit1

mov ah,9
lea dx,.ax
int 21h ;显示现场

ret
scene endp

@1: mov sp,256 ;设26字节comexe堆栈在低区,以释放尾后内存

lea bx,tail ;comexe内存映像尾
add bx,15

rept 4
shr bx,1 ;字节转节
endm

mov ah,4ah ;comexe内存始于es节,长bx节
int 21h ;释放comexe尾后的内存

mov ah,45h ;复制bx文件句柄到ax
mov bx,1 ;stdout
int 21h

mov oldstd1,ax

setstd1 2 ;stderr

mov ah,9
lea dx,i?;输入com,exe的8.3名
int 21h

mov si,128
mov byte ptr [si],13;限长:8文件名+点+3扩展名+回车
mov byte ptr [si+15],(128-26)-15-2

mov ah,10 ;stdin缓冲输入,存到dx指向
mov dx,si
int 21h

xor bh,bh
mov bl,[si+1] ;实长
mov [bx+128+2],bh ;4b01h要求0结尾

mov ah,9 ;输入被调试进程实参,字节数<85
lea dx,steps
int 21h

mov ah,10
mov dx,128+15
int 21h

setstd1 oldstd1

mov bp,cs ;bp恒指comexe

mov paraseg,bp ;参数串段值

mov ax,4b01h ;装入,而不启动
lea bx,w16 ;es:bx指参数块
mov dx,128+2 ;ds:dx指程序名
int 21h

jnc loaded

myend: mov ah,4ch
int 21h ;comexe返到父dos

loaded: lea bx,hextbl

mov ax,cs ;cax段
lea di,caxseg
axasc

lea ax,cax ;cax位移
lea di,caxoff
axasc

mov ax,3d00h ;打开,读
mov dx,128+2
int 21h

mov bx,ax ;句柄送bx

mov ax,4202h ;移指针到文件尾+cx:dx
xor dx,dx

mov es,dx ;清40:71处ctl-break位
mov es:[40h*10h+71h],dl

mov steps,dx ;清步数

xor cx,cx
int 21h

mov ccx,ax ;取指针dx:ax到cbx:ccx
mov cbx,dx

mov ah,3eh ;关闭
int 21h

mov ah,62h ;取被调试进程psp到bx
int 21h

mov cds,bx ;令cds,ces指向psp
mov ces,bx

mov es,bx

mov es:[10],offset i22
mov es:[12],cs ;置被调试进程psp终止矢量

add initsp,2 ;4b01h做后,[sp]为0ffff,未装首字是'ZM'的exe
;文件时,sp为fffc,且[sp+2]为0,使com文件的
;ret指令,返到psp偏移0的int 20h.故初始sp加2

mov bx,initsp
mov csp,bx

cmp bx,0fffeh
jz loaded1

sub ccx,200h ;调整exe文件长度
sbb cbx,0

loaded1:mov bx,initss
mov css,bx

mov bx,initcs
mov ccs,bx

mov es,bx

mov bx,initip
mov cip,bx

main: mov cx,es:[bx] ;取es:[bx]操作码,寻址方式到byte0,byte1
mov b0_b1,cx
mov es,bp

cmp i?,22h*4
jne main0

lea bx,hextbl

mov ah,4dh ;取终止信息
int 21h

mov dl,ah

lea di,errlev
alasc

mov al,dl
lea di,type4
alasc

mov ah,9
lea dx,exitmsg
int 21h

main0: mov intsz,2

cmp cl,0cdh ;欲进int 21h等
jz show

mov intsz,0

cmp cl,0cch ;欲进int 3
jz main1

cmp cl,0ceh ;欲进into
jnz main2

test cf,800h ;查溢出位
jz main2

main1: and cl,3 ;cc,ce转为int 3,4
add cl,6
shr cl,1

mov byte1,cl
inc intsz

main2: cmp steps,0ffffh
jnz show

cmp $_32,32 ;无尽跟踪时,查跨段
jz show

jmp set1 ;不费显时

show: call scene ;显示现场

cmp $_32,32 ;查跨段
jnz show2

setstd1 2 ;使输出可见

lea bx,hextbl ;用于alasc
mov ax,w15 ;显示跨段处cip
lea di,w15
mov dx,di
axasc

mov ah,9
int 21h

mov $_32,36 ;复原

mov ah,1 ;等待按键
int 21h

cmp al,'n' ;n,从此不查跨段
jne show1

inc chkgap ;已输n

show1: setstd1 oldstd1

show2: test steps,0ffffh
jz talk

jmp trace ;继续跟踪

talk: setstd1 2

talk1: mov ah,9
lea dx,?cmd
int 21h

mov ah,1 ;stdin输入[degt]
int 21h

cmp al,'t'
jne go

t0: lea dx,?steps ;输入步数
call INnib
or bx,bx ;非0
jz t0

mov steps,bx

newline
setstd1 oldstd1

jmp trace

go: cmp al,'g'
jnz dump

lea dx,?seg
call INnib

push bx

lea dx,?off
call INnib

pop es

makebrk
newline
setstd1 oldstd1

jmp set3

dump: cmp al,'d'
jnz edit

lea dx,?seg
call INnib

push bx

lea dx,?off
call INnib

pop ds

mov cx,16
mov si,bx
lea di,w16
rep movsw ;取16字

mov ds,bp

lea bx,hextbl ;用于alasc
mov dx,1001h ;dh是项数,dl是1234 5678的4,5隔
lea si,w16
lea di,w0_w14
call regasc

mov ah,9
lea dx,.w0
int 21h

jmp talk1

edit: cmp al,'e'
jnz kill

lea dx,?seg
call INnib

push bx

lea dx,?off
call INnib

push bx

lea dx,?val
call INnib

pop di
pop es

mov es:[di],bx ;换值
mov es,bp

jmp talk1

kill: mov i?,22h*4 ;令被调试进程返到父comexe
mov ah,4ch
int 21h

trace: test intsz,0ffffh
jnz faceint
jmp set1

faceint:cmp ?enter,13
jnz proceed

setstd1 2 ;未输过'n'

mov ah,9
lea dx,?enter
int 21h

mov ah,1 ;输入[pn]
int 21h

mov w0_w14,al ;暂存

newline
setstd1 oldstd1

cmp w0_w14,'p'
jz proceed ;p,本次不进int

cmp w0_w14,'n' ;n,从此不进int
jnz enter

inc ?enter ;已输n

proceed:mov es,ccs
mov bx,cip

add bx,intsz
makebrk

set3: mov di,3*4
lea dx,i3
jmp set

enter: mov ax,intsz
add ax,cip ;令ax指向预取指令

cli
mov ss,css ;取被调试进程堆栈
mov sp,csp
sti

push cf ;模拟进入int的压栈
push ccs
push ax

mov csp,sp ;调整csp

xor bx,bx
mov es,bx

mov bl,byte1 ;因进int 1或3,不能用int功能
shl bx,1 ;故从0:0取中断口到es:bx
shl bx,1

les bx,es:[bx]

and cf,not 0200h ;模拟进入int的关中断

mov i?,1*4
jmp sv_ccs ;设置ccs:cip

set1: or cf,100h ;置自陷位

mov di,1*4
lea dx,i1

set: xor ax,ax
mov es,ax

mov ax,es:[di] ;保存变的老中断1或3
mov cf[di],ax

mov ax,es:[di+2]
mov cf[di+2],ax

mov es:[di],dx
mov es:[di+2],cs ;令中断1或3,指向i1或i3

mov ax,es:[23h*4] ;保存变的老中断23h
mov off23,ax

mov ax,es:[23h*4+2]
mov seg23,ax

mov es:[23h*4],offset i23
mov es:[23h*4+2],cs ;令中断23h,指向i23

mov ax,cax ;恢复被调试进程环境
mov bx,cbx
mov cx,ccx
mov dx,cdx

mov bp,cbp
mov si,csi
mov di,cdi

cli ;防中断
mov sp,csp
mov ss,css
sti

mov es,ces
mov ds,cds

push cs:cf
push cs:ccs
push cs:cip

iret ;启动被调试进程

tail=$
code ends
end @

(11) 用comexe.com,重定向I/O,调试2k的debug.exe f.exe用例

comexe <foo.0 >foo.1 2>foo.2

foo.1中,接收u及反出首条指令的两个片断是:

AX=0a82 BX=0671 CX=0000 DX=4a36 SP=4a01 BP=0000 SI=0085 DI=0000|cd21
DS=0682 ES=0682 SS=0682 CS=0682 IP=0478 NV UP EI PL ZR NA PE NC|INT
u

...

AX=4000 BX=0001 CX=0013 DX=2638 SP=49c1 BP=0013 SI=4d6b DI=2638|cd21
DS=0682 ES=0682 SS=0682 CS=0682 IP=292c NV UP EI PL NZ NA PE NC|INT
1E PUSH

foo.2内容是:

com,exe:debug.exe

arg(len<85):f.exe

AX(seg:off=0526:0190) F(????ODITSZ?A?P?C) d(ump word),edit,go,trace:t
steps[0001~fffe,ffff]ffff

0033 gap seg,n(o check):n
proceed,n(ever enter int):n

AX(seg:off=0526:0190) F(????ODITSZ?A?P?C) d(ump word),edit,go,trace:q

输出到屏幕及foo.1的运行结果,未必一致,如:

mov ah,2 ;输出dl
mov dl,'0'
int 21h

DEBUG及comexe下,返回的al,对屏幕是30h,对foo.1是1.

(12) 对popf指令的1个注释

用popf指令,可使自陷位置1,若popf后面,仍有能使自陷位置1的若干popf指令,处理器
将在这些popf执行期间,不响应硬件时钟中断8.如做:

code segment
assume cs:code,ds:code

org 100h

start: jmp start1

old8 label dword
old8ip dw 0
old8cs dw 0

timer: sti
int 21h ;输出'0'

pushf ;多压1个字.老中断8,用弹出3个字的iret结束
call old8 ;调用老中断8,以防死机

iret

start1: cli

mov ax,3508h ;取老中断8
int 21h

mov old8ip,bx
mov old8cs,es

mov ah,25h ;令中断8指向timer
lea dx,timer
int 21h

mov ah,2 ;输出dl
mov dl,'0'

sti

loop1: pushf ;取标志寄存器
pop bx

chg: or bx,100h ;自陷位置1
; or bx,200h ;中断位置1

;进入int时,这两位都被8086清除,可比较

rept 400 ;入栈400次
push bx
endm

rept 400 ;弹栈400次
popf
endm

jmp loop1 ;每次时钟中断,都显'0'

code ends
end start

若只改chg处的or bx,100h为or bx,200h,对比速度执行,改前的com慢.

作者: 北京信息工程学院 软件工程研究中心 马文晓
写于: 2002.10.22
邮编: 100101
电话: 66188615,64884879
E-MAIL: mawenxiao@biti.edu.cn
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐