;From: alan.illeman@canrem.com (Alan Illeman)
;Newsgroups: alt.lang.asm
;Subject: Re: :How can I make a TSR uninstaller ?
;--------------------------------------
; TSR.ASM using Tasm 3.1
; tasm /ml /m2 /q /w2 /t tsr.asm
; tlink /c /x /t tsr, tsr, NUL
;--------------------------------------
b equ <byte ptr> ; shorthand
w equ <word ptr>
d equ <dword ptr>
o equ <offset>
s equ <short>
True equ 1
False equ 0
cseg segment para public 'code'
assume nothing
assume cs:cseg, ss:cseg, ds:cseg, es:nothing
org 100h
.286
entry:
jmp install
;--------------------------------------
even
sp_save dw ? ; see deinstall
ss_save dw ? ;
ds_save dw ? ;
old2Fh dd ? ; old 2Fh handler
ident db ? ; multiplex TSR ident
ident_st db 'TSR.ASM' ; ident string
ident_len = $ - ident_st ;
even
;--------------------------------------
; Int 2fh, multiplex intercept
;
; al=0 installation check
;--------------------------------------
new2Fh proc far
cmp ah, cs:ident ; our tsr ?
je mult1 ; yes
jmp d cs:old2Fh ; no
mult1:
cmp al, 0 ; installation check ?
jne mult2 ; no
mov al, 0ffh ; yes, return al=0ffh
push cs ;
pop es ;
mov di, o cs:ident_st ; es:[di] --> ident string
mult2:
iret
new2Fh endp
;======================================
install proc near
push cs
pop ds
assume ds:cseg
;--------------------------------------
; check if deinstall required
;--------------------------------------
mov si, 81h ; command line
cld ;
ins1:
lodsb
cmp al, 0dh ; string-end ?
jne ins2 ;
jmp ins9 ; yes, no deinstall
ins2:
cmp al, 'd' ; 'd' ?
je ins3 ; yes
cmp al, 'D' ; 'D' ?
jne ins1 ; no
;--------------------------------------
; attempt deinstall
;--------------------------------------
ins3:
call installed ;
cmp ax, True ;
je ins4 ;
mov dx, o errmsg6 ; 'Tsr not installed'
jmp error ; exit
ins4:
;--------------------------------------
; check if int 2Fh vector has changed
; (installed has returned with es=psp of installed TSR)
;--------------------------------------
mov ax, 352Fh
push es
int 21h
pop es
cmp bx, o es:new2Fh
je ins5
mov dx, o errmsg5 ; 'TSR cannot be removed'
jmp error ; exit
ins5:
mov ax, 252Fh ; restore old 2Fh vector
push ds
lds dx, es:old2Fh ;
int 21h
pop ds
mov w es:[16h], cs ; install return psp
mov w es:[0ah], o gotx ; install return offset
mov w es:[0ch], cs ; install return segment
mov sp_save, sp ; save sp
mov ss_save, ss ; save ss
mov ds_save, ds ; save ds
mov ah, 50h ; set process
mov bx, es ; installed TSR
int 21h ;
mov ax, 4c00h ; exit, returning to goto...
int 21h ; ... per Mr. A. Schulman
;--------------------------------------
; deinstall return address, regs unknown
;--------------------------------------
gotx:
cli
mov ds, cs:ds_save ;
assume ds:cseg ; set ds
mov ss, ss_save ; set ss
mov sp, sp_save ; set sp
sti ;
mov dx, o errmsg4 ; 'TSR removed from memory'
jmp error ; exit
;--------------------------------------
; no deinstall, continue with installation
;--------------------------------------
ins9:
call installed ;
cmp ax, False ;
je ins10 ;
mov dx, o errmsg1 ; 'TSR already installed'
jmp error ;
;--------------------------------------
; search for a vacant num
;--------------------------------------
ins10: ; nums 0..191 are reserved
mov bh, 192 ; scan nums 192..255
ins11:
mov ah, bh ; ah=num
mov al, 0 ; al=0, installation check
push bx ds
int 2Fh ; multiplex
pop ds bx
cmp al, 0 ; this num used ?
je ins12 ; no, exit loop
inc bh ; next num
jnz ins11 ; up to 255
mov dx, o errmsg2 ; out of nums (unlikely)
jmp error
ins12:
mov ident, ah ; save num
mov ax, 352Fh ; save old vector
int 21h
mov w old2Fh[0], bx
mov w old2Fh[2], es
mov ax, 252Fh ; install new vector
mov dx, o new2Fh
int 21h
mov ah, 9
mov dx, o errmsg7 ; 'TSR installed'
int 21h
mov dx, o install ; install !
shr dx, 4
inc dx
mov ax, 3100h
int 21h
error:
mov ah, 9 ; display string
int 21h ;
mov ax, 4c00h ; exit to Dos
int 21h ;
install endp
even
;--------------------------------------
; call installed
;
; returns AX=True, ES=PSP, if installed
;--------------------------------------
installed proc near
assume ds:cseg
mov dx, False ;
mov bh, 192 ; scan nums 192..255
inst1:
mov ah, bh ; ah=num
mov al, 0 ; al=0, installation check
push bx ds
int 2Fh ; multiplex
pop ds bx
cmp al, 0ffh ; this num used ?
jne inst2 ; no
mov si, o ident_st ; es:[di] addresses...
mov cx, ident_len ; installed tsr string
cld ;
repe cmpsb ; ident string ok ?
jne inst2 ; no
mov dx, True ; yes, dx=True
jmp s inst3 ; exit
inst2:
inc bh ; next num
jnz inst1 ; up to 255
inst3:
mov ax, dx ; return ax
ret
installed endp
errmsg1 db 'TSR already installed', 13,10,7,'$'
errmsg2 db 'TSR install problem', 13,10,7,'$'
errmsg4 db 'TSR removed from memory', 13,10, '$'
errmsg5 db 'TSR cannot be removed', 13,10,7,'$'
errmsg6 db 'TSR not installed', 13,10,7,'$'
errmsg7 db 'TSR installed, type: <tsrname>'
db 'D, to deinstall', 13,10, '$'
cseg ends
end entry
end
Some gaps in labels, messages, since code that does anything
useful has been removed. Run "mem /c" at Dos prompt, make a
note of total free memory. Invoke TSR, then deinstall it and
run "mem /c" to see that is has been completely removed.
Techniques from Microsoft's snap.asm and "Undocumented Dos",
1990, by Andrew Schulman.
Since there are so many interrupts in TSR's, I prefer to use
a structure for addressing them :
INTS struc
flag db ? ; 1 = interrupt active
inum db ? ; interrupt number
inew dw ? ; new handler offset
iold dd ? ; old handler addr
INTS ends
szINTS equ size INTS ; struc size in bytes
..and so a standard TSR had this in its data area :
ints label byte
intTimer INTS { flag=0, inum=08h, inew=o new08h, iold=0 }
intKeyboard INTS { flag=0, inum=09h, inew=o new09h, iold=0 }
intVideo INTS { flag=0, inum=10h, inew=o new10h, iold=0 }
intDisk INTS { flag=0, inum=13h, inew=o new13h, iold=0 }
intDos INTS { flag=0, inum=21h, inew=o new21h, iold=0 }
intIdle INTS { flag=0, inum=28h, inew=o new28h, iold=0 }
intMultiplex INTS { flag=0, inum=2fh, inew=o new2Fh, iold=0 }
ints_len = ($ - ints)/szINTS
vars label byte
intCtrlBreak INTS { flag=0, inum=1bh, inew=o new1Bh, iold=0 }
intCtrlC INTS { flag=0, inum=23h, inew=o new23h, iold=0 }
intCritError INTS { flag=0, inum=24h, inew=o new24h, iold=0 }
vars_len = ($ - vars)/szINTS
A saving/installing/deinstalling loop makes the job easier.
mov si, o ints ; save old vectors
mov cx, ints_len + vars_len
ins13:
mov al, (INTS ptr [si]).inum
mov ah, 35h
int 21h
mov w (INTS ptr [si]).iold[0], bx
mov w (INTS ptr [si]).iold[2], es
add si, szINTS
loop ins13
Alan