;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 ; shorthand w equ d equ o equ s equ 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: ' 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